Redirect http to https

Good day!
I can’t figure out how to redirect all http requests to https.
I tried using middleware -

@app.middleware('request')
async def force_ssl(request):
    if request.headers.get('X-Forwarded-Proto') == 'http':
        return response.redirect(
            request.url.replace('http://', 'https://', 1),
            status=301
        )

Unfortunately, it works only sometimes.
Is there a more robust way of forcing SSL to all requests?

It seems like the only time this would happen is if X-Forwarded-Proto doesn’t get set for some reason. Maybe change request.headers.get() to request.scheme ?

Is there any reason why you can’t do this in a proxy like nginx running in front of sanic?

2 Likes

Thanks for suggestions.
I think, the problem I am having is with static routes.
Is there a way to redirect static routes? Request middleware does not seem to catch those.

I don’t want to use nginx because I am trying to build standalone application with zero configuration. Pip install and you are ready to go.

I think middleware is still supposed to apply to static routes, but I’ll have to investigate.

Good day.

Recently I upgraded Sanic to last version (19.9.0).
And now middleware i used before won’t fire for Http requests if SSL is enabled.

I get two warnings in logs:

SSL handshake failed
protocol: <asyncio.sslproto.SSLProtocol object at 0x000001D383EC87B8>
transport: <_SelectorSocketTransport fd=1292 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "C:\Users\enf64_000\AppData\Local\Programs\Python\Python37\lib\asyncio\sslproto.py", line 625, in _on_handshake_complete
    raise handshake_exc
  File "C:\Users\enf64_000\AppData\Local\Programs\Python\Python37\lib\asyncio\sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "C:\Users\enf64_000\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: HTTP_REQUEST] http request (_ssl.c:1056)

and second:

SSL error in data received
protocol: <asyncio.sslproto.SSLProtocol object at 0x000001D383EC87B8>
transport: <_SelectorSocketTransport closing fd=1292 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "C:\Users\enf64_000\AppData\Local\Programs\Python\Python37\lib\asyncio\sslproto.py", line 526, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "C:\Users\enf64_000\AppData\Local\Programs\Python\Python37\lib\asyncio\sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "C:\Users\enf64_000\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: HTTP_REQUEST] http request (_ssl.c:1056)

Could someone point me, how to redirect all Http requests to https, please?
Can I somehow hook to second exception maybe?

Have you looked into exception handling?