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?
Related
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.
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'})
In my Pylons config file, I have:
[server:main1]
port = 9090
...config here...
[server:main2]
port = 9091
...config here...
Which are ran using:
paster serve --server-name=main1 ...(more stuff)...
paster serve --server-name=main2 ...(more stuff)...
Now, using Haproxy and Stunnel, I have all http requests going to main1 and all https requests going to main2. I would like some of my controllers to react a little differently based on if they are being requested under http or https but pylons.request.scheme always thinks that it is under http even when it is not.
Seeing as I always know that main2 is always the one handling all https requests, is there a way for the controller to determine what sever name it was ran under or what id it is?
I got around this by just changing the workflow to not have to react differently based on what protocol it's under. It doesn't look like there's a way to pass a unique arbitrary identifier to each separate process that it can read.
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.
I have a bottle.py application which has a number of routes already built. I would like to create a new get route which, when accessed, passes the request along to another HTTP server and relays the result back.
What is the simplest way to get that done?
In principle, all you need is to install the wsgiproxy module and do this:
import bottle
from wsgiproxy.app import WSGIProxyApp
root = bottle.Bottle()
proxy_app = WSGIProxyApp("http://localhost/")
root.mount(proxy_app,"/proxytest")
Running this app will then proxy all requests under /proxytest to the server running on localhost:80. In practice, I found this didn't work without taking extra steps to remove hop-by-hop headers. I took the code in this gist and stripped it down to make a simple app that successfully proxies the request.