drdawud
drdawud

Reputation: 83

Handling Non-SSL Traffic in Python/Tornado

I have a webservice running in python 2.7.10 / Tornado that uses SSL. This service throws an error when a non-SSL call comes through (http://...).

I don't want my service to be accessible when SSL is not used, but I'd like to handle it in a cleaner fashion.

Here is my main code that works great over SSL:

if __name__ == "__main__":
    tornado.options.parse_command_line()
    #does not work on 2.7.6
    ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_ctx.load_cert_chain("...crt.pem","...key.pem")
    ssl_ctx.load_verify_locations("...CA.crt.pem")
    http_server = tornado.httpserver.HTTPServer(application, ssl_options=ssl_ctx, decompress_request=True)
    http_server.listen(options.port)

    mainloop = tornado.ioloop.IOLoop.instance()

    print("Main Server started on port XXXX")
    mainloop.start()

and here is the error when I hit that server with http://... instead of https://...:

[E 151027 20:45:57 http1connection:700] Uncaught exception
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/tornado/http1connection.py", line 691, in _server_request_loop
    ret = yield conn.read_response(request_delegate)
  File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 807, in run
    value = future.result()
  File "/usr/local/lib/python2.7/dist-packages/tornado/concurrent.py", line 209, in result
    raise_exc_info(self._exc_info)
  File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 810, in run
    yielded = self.gen.throw(*sys.exc_info())
  File "/usr/local/lib/python2.7/dist-packages/tornado/http1connection.py", line 166, in _read_message
    quiet_exceptions=iostream.StreamClosedError)
  File "/usr/local/lib/python2.7/dist-packages/tornado/gen.py", line 807, in run
    value = future.result()
  File "/usr/local/lib/python2.7/dist-packages/tornado/concurrent.py", line 209, in result
    raise_exc_info(self._exc_info)
  File "<string>", line 3, in raise_exc_info
SSLError: [SSL: HTTP_REQUEST] http request (_ssl.c:590) 

Any ideas how I should handle that exception?

And what the standard-conform return value would be when I catch a non-SSL call to an SSL-only API?

UPDATE

This API runs on a specific port e.g. https://example.com:1234/. I want to inform a user who is trying to connect without SSL, e.g. http://example.com:1234/ that what they are doing is incorrect by returning an error message or status code. As it is the uncaught exception returns a 500, which they could interpret as a programming error on my part. Any ideas?

Upvotes: 1

Views: 868

Answers (1)

matagus
matagus

Reputation: 6206

There's an excelent discussion in this Tornado issue about that, where Tornado maintainer says:

If you have both HTTP and HTTPS in the same tornado process, you must be running two separate HTTPServers (of course such a feature should not be tied to whether SSL is handled at the tornado level, since you could be terminating SSL in a proxy, but since your question stipulated that SSL was enabled in tornado let's focus on this case first). You could simply give the HTTP server a different Application, one that just does this redirect.

So, the best solution it's to HTTPServer that listens on port 80 and doesn't has the ssl_options parameter setted.

UPDATE

A request to https://example.com/some/path will go to port 443, where you must have an HTTPServer configured to handle https traffic; while a request to http://example.com/some/path will go to port 80, where you must have another instance of HTTPServer without ssl options, and this is where you must return the custom response code you want. That shouldn't raise any error.

Upvotes: 3

Related Questions