`url_for` returns http instead of https
naokipeter opened this issue · 7 comments
When I deploy the app on Heroku [1], all the url_for
s in base.html give me URLs with http instead of https, which triggers a Mixed Content error. When I run uvicorn locally using ssl_keyfile
and ssl_certfile
, I don't get this problem.
Links:
[1] https://aqueous-waters-64836.herokuapp.com/
You may need uvicorn's --proxy-headers
setting.
Have a dig into what headers Heroku sets to inform the application about what scheme was used to make the connection.
I used the options for Uvicorn (--proxy-headers
) and Gunicorn (--forwarded-allow-ips="*"
) to pass on X-Forwarded-Proto
in environments with a trusted proxy (e.g. on Heroku), but, as far as I can tell from looking at templating:url_for
, requests:url_for
and routing:url_path_for
, the only thing Starlette looks at when determining the protocol is the base URL.
Right, and the --proxy-headers
effect is to set the scheme correctly https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py#L26 so that the application level re- constructs the incoming URL with the HTTP scheme as seen by the proxy, rather than the HTTP scheme on which the proxy connected to the application.
You'll want to have a dig into whatever custom headers your deployment environment is setting, in order to inform the application about the actual scheme of the originating request, and also take a look at the ASGI messages that are being passed to the application.
The request headers contain 'x-forwarded-proto':'https'
, but the scope has 'scheme': 'http'
. Could it be that sslcontext
isn't recognized properly by Uvicorn?
• request.headers
:
{
'host':'aqueous-waters-64836.herokuapp.com',
'connection':'close',
'cache-control':'max-age=0',
'upgrade-insecure-requests':'1',
'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
'accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'referer':'https://dashboard.heroku.com/',
'accept-encoding':'gzip, deflate, br',
'accept-language':'en-US,en;q=0.9,de-CH;q=0.8,de;q=0.7,ja;q=0.6,fr;q=0.5',
'x-request-id':'2be84343-c7c8-48dd-9762-0f124c7c8dd0',
'x-forwarded-for':'51.154.88.136',
'x-forwarded-proto':'https',
'x-forwarded-port':'443',
'via':'1.1 vegur',
'connect-time':'0',
'x-request-start':'1559493926662',
'total-route-time':'0'
}
• request._scope
:
{
'type': 'http',
'http_version': '1.1',
'server': ('172.19.29.62',
20081),
'client': ('10.63.95.16',
33910),
'scheme': 'http',
'method': 'GET',
'root_path': '',
'path': '/',
'query_string': b'',
'headers': [
(b'host',
b'aqueous-waters-64836.herokuapp.com'),
(b'connection',
b'close'),
(b'upgrade-insecure-requests',
b'1'),
(b'user-agent',
b'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'),
(b'accept',
b'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3'),
(b'accept-encoding',
b'gzip, deflate, br'),
(b'accept-language',
b'en-US,en;q=0.9,de-CH;q=0.8,de;q=0.7,ja;q=0.6,fr;q=0.5'),
(b'x-request-id',
b'c3418f86-aece-4c5a-a3dd-8c70cdd095bc'),
(b'x-forwarded-for',
b'217.192.56.102'),
(b'x-forwarded-proto',
b'https'),
(b'x-forwarded-port',
b'443'),
(b'via',
b'1.1 vegur'),
(b'connect-time',
b'1'),
(b'x-request-start',
b'1559656483407'),
(b'total-route-time',
b'0')
],
'app': <starlette.applications.Starletteobjectat0x7efda97c5278>,
'router': <starlette.routing.Routerobjectat0x7efda97c52b0>,
'endpoint': <functionhomepageat0x7efda97c0a60>,
'path_params': {
}
}
• await request.receive()
:
{'type': 'http.request', 'body': b'', 'more_body': False}
What does your Procfile
look like?
web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker --forwarded-allow-ips="*" app:app
Okay thanks! That helps tease out the root issue from this - encode/uvicorn#369 - will continue any conversation on that one instead.
Short: we don't have any equivalent for the --forwarded-allow-ips="*"
gunicorn setting in uvicorn. A quick fix might be to special case *
into proxy_headers=True
. Tho really we ought to match gunicorn's settings more closely here.