Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutating request.base_url in Flask

I have a Flask application behind a Load balance that terminates SSL. I have code that "detects" when SSL is being used and mutates the request object:

@app.before_request
def before_request():
    x_forwarded_proto = request.headers.get('X-Forwarded-Proto')
    if  x_forwarded_proto == 'https':
        request.url = request.url.replace('http://', 'https://')
        request.url_root = request.url_root.replace('http://', 'https://')
        request.host_url = request.host_url.replace('http://', 'https://')

I then have a blueprint view function:

admin = Blueprint('admin', __name__, url_prefix='/admin')
@admin.route('/login')
def login():
    print request.url

The output of this function is (when I go to /admin/login) is always http:// instead of https:// (even though it should have been mutated in the before_request function.

Any ideas on how I can fix this?

like image 957
mmattax Avatar asked Nov 07 '13 15:11

mmattax


People also ask

How do you process incoming request data in Flask?

To access the incoming data in Flask, you have to use the request object. The request object holds all incoming data from the request, which includes the mimetype, referrer, IP address, raw data, HTTP method, and headers, among other things.

How do you handle a post request in Python Flask?

GET and POST requestsEnter the following script in the Python shell. Once the development server is up and running, open login. html in the browser, enter the name in the text field, and then click Submit. The form data will POST to the URL in the action clause of the form label.


1 Answers

Turns out request is a proxied object. I'm not sure of the internals but it's "reset" on each import. I solved the issue by subclassing Request

class ProxiedRequest(Request):
    def __init__(self, environ, populate_request=True, shallow=False):
        super(Request, self).__init__(environ, populate_request, shallow)
        # Support SSL termination. Mutate the host_url within Flask to use https://
        # if the SSL was terminated.
        x_forwarded_proto = self.headers.get('X-Forwarded-Proto')
        if  x_forwarded_proto == 'https':
            self.url = self.url.replace('http://', 'https://')
            self.host_url = self.host_url.replace('http://', 'https://')
            self.base_url = self.base_url.replace('http://', 'https://')
            self.url_root = self.url_root.replace('http://', 'https://')

app = Flask(__name__);
app.request_class = ProxiedRequest
like image 111
mmattax Avatar answered Nov 09 '22 15:11

mmattax