librelist archives

« back to archive

Flask, external URLs, and Host headers

Flask, external URLs, and Host headers

From:
David King
Date:
2015-03-22 @ 06:54
I want url_for(_external=True) and redirects etc to generate a different 
hostname than I want to listen on.

Here's the situation: my site is on origin.mysite.com, and my CDN talks to
me there with that Host header. But users talk to me via www.mysite.com. 

The CDN must hit me with the origin Host header because there's more than 
one site hosted there, and it's mapped via the Host header. I don't 
control the web server on the origin host, and as far as I know there's no
way to route queries for the www hostname to me.

If I set SERVER_NAME = None, then I can't generate external URLs without a
request context, and with a request context the external URLs generated 
are for origin.mysite.com.

If I set SERVER_NAME = origin.mysite.com, then external URLs are all 
generated for origin.mysite.com.

If I set SERVER_NAME = www.mysite.com, then requests to me 404 because 
they hit me with "Host: origin.mysite.com" (because of the Host header 
rewriting done at the CDN) and now Flask can't figure out which 
application to route them to.

(note that in none of these cases do redirects in particular generate 
www.mysite.com URLs; they appear to always use the Host header?)

Poking at flask internals, especially the implementation of url_for, it 
looks like routing and generated URLs are very tightly linked together 
through the url_map. I took a naive stab at adding this support to flask 
(https://github.com/ketralnis/flask/commit/1e7006efbbbaea76696ced315fafccb5d1cc9d53)
but it doesn't quite work, and I suspect that that's because of something 
that I don't understand about the URL map.

I'm okay with maintaining local changes to flask if that's the most direct
way to my goal, but it wouldn't be my favourite option if there's a better
one.

Is this a losing battle?

Re: [flask] Flask, external URLs, and Host headers

From:
David King
Date:
2015-03-22 @ 08:55
After a lot of messing with this, I found a solution that works for my 
case. By the time a request gets into my code the request router on the 
origin has already found me. So once my code is being called, I can 
rewrite the Host header to be www instead of origin, and just pretend that
that's what I had all along.

May not work for everyone, but for my use case it's great.


    from werkzeug.contrib.fixers import HeaderRewriterFix

    def wrap_app(app):
        # users hit us at www, but by the time it gets to us it's
        # origin. Just pretend that it is what we want it to be
        app = HeaderRewriterFix(app,
                                remove_headers=['Host'],
                                add_headers=[('Host', app.config['SERVER_NAME'])])
        return app


Also the rest of http://werkzeug.pocoo.org/docs/0.10/contrib/fixers/ is 
pretty useful too



On 21 Mar 2015, at 23:54, David King <dking@ketralnis.com> wrote:

> I want url_for(_external=True) and redirects etc to generate a different
hostname than I want to listen on.
> 
> Here's the situation: my site is on origin.mysite.com, and my CDN talks 
to me there with that Host header. But users talk to me via 
www.mysite.com. 
> 
> The CDN must hit me with the origin Host header because there's more 
than one site hosted there, and it's mapped via the Host header. I don't 
control the web server on the origin host, and as far as I know there's no
way to route queries for the www hostname to me.
> 
> If I set SERVER_NAME = None, then I can't generate external URLs without
a request context, and with a request context the external URLs generated 
are for origin.mysite.com.
> 
> If I set SERVER_NAME = origin.mysite.com, then external URLs are all 
generated for origin.mysite.com.
> 
> If I set SERVER_NAME = www.mysite.com, then requests to me 404 because 
they hit me with "Host: origin.mysite.com" (because of the Host header 
rewriting done at the CDN) and now Flask can't figure out which 
application to route them to.
> 
> (note that in none of these cases do redirects in particular generate 
www.mysite.com URLs; they appear to always use the Host header?)
> 
> Poking at flask internals, especially the implementation of url_for, it 
looks like routing and generated URLs are very tightly linked together 
through the url_map. I took a naive stab at adding this support to flask 
(https://github.com/ketralnis/flask/commit/1e7006efbbbaea76696ced315fafccb5d1cc9d53)
but it doesn't quite work, and I suspect that that's because of something 
that I don't understand about the URL map.
> 
> I'm okay with maintaining local changes to flask if that's the most 
direct way to my goal, but it wouldn't be my favourite option if there's a
better one.
> 
> Is this a losing battle?
>