I've a simple Python Flask application, which is being served by Apache via mod_wsgi.
The part of my application which works perfectly on my localhost, but does not work through mod_wsgi is the accessing of custom request headers.
When I request a certain web page, I pass it a header called auth_user. On my localhost, I am able to access this header as: request.headers["auth_user"], which works great. However when served through Apache and mod_wsgi, this custom header does not exist! Printing all request.headers shows that the standard Content-Type, Cache-Control headers are sent, but not the auth_user header which i've been sending to my localhost with no problem.
Tcpdump shows that the server is receiving the header, but it is not available in my request.headers.
Does anyone have any idea why this header is not being made available within the app?
Well this one took me many hours...
Turns out that only alphanumeric characters or '-' are allowed.
Any headers not conforming these will be ignored.
http://modwsgi.readthedocs.org/en/latest/release-notes/version-4.3.0.html <- Bug fixes, point 2.
The solution is to set the claim prefix to something without _ like
OIDCClaimPrefix OIDC-CLAIM-
Ensure your Apache configuration has the WSGIPassAuthorization directive set to 'On' so your headers get past Apache + WSGI and to your Flask app.
Related
I've been working in a Flask project using waitress for production environement (Targeting Linux ARM and Windows), and I need to recieve a request from a service which has a headers like "dev_id" and "request_code" (doc).
Waitress got a pull request in 2015 (link) basically skipping headers containing _, which explains why the headers are not present in the request object.
I've considered switching to Gunicorn, but Windows support is a must-have.
Using flask as a self-WSGI works, but do not seems to be the perfect approach for a production environement.
Using raw socket for HTTP instead of Flask sounds acceptable, but demands some work for refactoring.
Changing the header name is not an option as I do not have access.
I want to read the header dev_id sent by my client in a Flask application, but waitress doesn't let me do that. Is there any way to ignore this rule? Any workarounds?
I have two domains, one is for front-end(abc.aa.com) another is for back-end(xx.abc.aa.com).
I have to upload a picture from the front-end to back-end with ajax only if I set it.
Header set Access-Control-Allow-Origin "*" to .htaccess, it will succeed.
Otherwise a cross-domain error will happen, but I want to allow only the abc.aa.com to access this source; how can I achieve this?
I also tried this tutorial, but only origin="*" will work.
My env:
python 2.7
flask
webuploader
Currently..
environ['SERVER_NAME']
can get the domain name. such as..
domaint.tld
or
sub.domain.tld
but can it also get..
domain.tld/file/in/question.extension
also ?
if that is possible.. then can this somehow replace.. mod rewrite and do something like this..
suppose the url is
domain.tld/01
we split this at
/
and then if it starts with 0 it must be something that we are looking for..
use the number after '0'
to pull out variable content.
can this replace mod_rewrite ?
i do not like touching mod_rewrite due to complex stuff of regex..
It cannot really replace mod_rewrite if the intent is that the rewritten URL be fed back in as a sub request into Apache as a whole with request content still available. All you can really do is perform URL rewriting for use of the URL and request within a specific Python WSGI application.
The qualification on the first about request content is that when using daemon mode of mod_wsgi, it is possible to return a 200 response with no content and a Location response header, where the value of the Location header is a server relative URL. This will cause a new sub request to be performed at the Apache level, but in doing that it can only issue a GET request with no request content.
The 200/Location response can thus be used as a way for a WSGI application to reroute a request the WSGI application handles back to Apache to serve up a different resource, such as a static file or even a PHP application. This is by no means though a general mechanism that could be used to replace mod_rewrite and would only be suitable in certain use cases.
And on the specific point of access to other parts of the original request information, you have:
SERVER_NAME
SCRIPT_NAME
PATH_INFO
See for example URL reconstruction in the WSGI specification at:
https://www.python.org/dev/peps/pep-3333/#url-reconstruction
Under Apache/mod_wsgi you also have REQUEST_URI, but that can be complicated to deal with as is not decoded nor normalised and can be a server relative URL or technically a URI format including scheme and host/port information.
I have a Flask application that will run under Apache in production. I have some static files, but they require authenticated access. So using X-Sendfile seemed reasonable to speed up the file delivery after authentication:
flaskapp = flask.Flask()
flaskapp.use_x_sendfile = True
Then where I'm generating the response:
return flask.send_file(filepath)
It seems to work fine under Apache. The problem is when I run the development server:
# Use SharedDataMiddleware to deliver JS, CSS, icons, etc.
flaskapp.wsgi_app = SharedDataMiddleware(flaskapp.wsgi_app, {'/static': '/path/to/static'})
flaskapp.run(host='0.0.0.0', debug=True)
When I run it this way with use_x_sendfile = True, the X-Sendfile header shows up in the actual response and an empty file (0 byte) is delivered to the client. Turning off X-Sendfile (and forcing the browser to discard the cached file) fixes the issue, so it seems the Werkzeug server Flask runs isn't processing the X-Sendfile header. Is there a way to enable the development server to process X-Sendfile, or am I forced to turn this off during development?
The flask documentation mentions that the server must support the X-Sendfile, and werkzeug's dev server doesn't (there's no mention anywhere in the documentation and a grep through werkzeug's source for sendfile returned no matches).
It wouldn't probably be too hard to add this behaviour to the server, but I'm not really sure if supporting such advanced features is a priority for a developement server.
Btw, as additional keyword arguments to run are passed through to werkzeug's run_simple, you don't need to create the middleware yourself, you can just use:
flaskapp.run(host='0.0.0.0', debug=True, static_files={'/static': '/path/to/static'})
Is it possible to setup a listener on say port 9090 and add a header, like Host: test.host to each request incoming on 9090 and send it on to say 8080?
Thanks
EDIT: I went with a reverse-proxy for now, applying the hostname:port to any request that comes in.
Twisted has an implementation of a reverse proxy that you could modify to suit your needs. You can look at the examples here. If you look at the source code of twisted.web.proxy, you can see that the 'Host:' header is set in ReverseProxyRequest.process, so you could subclass it and set your own header.
Unless you need to tailor the proxied request based on parameters that only your web application can know (for example, you need to authenticate the proxied request with your webapp's custom authentication system), you should use your web server's proxy capabilities.
Example with Apache:
Listen 0.0.0.0:9090
ProxyRequests off
<VirtualHost myhost:9090>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
ProxyPassReverseCookieDomain localhost myhost
</VirtualHost>
If you have to proxy things in a Flask or Werkzeug application, you can use httplib, creating requests based on the incoming request data and returning the response, either raw or modified (eg for link rewriting). It's doable, I have one such proxy in use where there was no good alternative. If you do that I recommend against using regular expressions to rewrite HTML links. I used PyQuery instead, it's far easier to get it right.