Actively writing an HTTPS webserver in Python 3 Please help me improving this existing, working code. I am not asking you to change what it does, as it handles connections already perfectly as designed by my own specs. I just want the code to be reviewed to be sure.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, ssl
from socketserver import ThreadingMixIn
from http.server import SimpleHTTPRequestHandler, HTTPServer

global sslcontext
sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
sslcontext.options |= ssl.OP_NO_TLSv1
sslcontext.options |= ssl.OP_NO_TLSv1_1
sslcontext.protocol = ssl.PROTOCOL_TLSv1_2
sslcontext.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305")
sslcontext.set_ecdh_curve("secp384r1")
sslcontext.load_cert_chain("/home/pi/keys/fullchain.pem", "/home/pi/keys/privkey.pem")

class HSTSHandler(SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
        SimpleHTTPRequestHandler.end_headers(self)

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    daemon_threads = True

def main():
    try:
        os.chdir("/media/external")#auto-change working directory
        SimpleHTTPRequestHandler.sys_version = "0.1"#display custom Python system version
        SimpleHTTPRequestHandler.server_version = "0.2"#display custom server software version
        my_server = ThreadedHTTPServer(('', 443), HSTSHandler)
        my_server.socket = sslcontext.wrap_socket(my_server.socket, server_side=True)
        print('Starting server, use &lt;Ctrl-C&gt; to stop')
        my_server.serve_forever()

    except KeyboardInterrupt:
        print(' received, shutting down server')
        my_server.shutdown()

if __name__ == '__main__':
    main()
When importing names from a location (module, package, dynamic library, ...), don't mix multiple locations on a single line. That is, this:

import os, ssl


... should be:

import os
import ssl


This is purely a stylistic concern, and it's one of the rules listed in PEP-8, the official Python style guide.
Global variables should be a last resort. They clutter the global namespace, are hard to track when reading the code, and are very prone to race conditions when using threads. Here, you could pass the context as an argument, or perhaps set up another class with the context attached as an attribute.

Let's say you have to share foo between func_a() and func_b(). Three different approaches:


Make foo global (analogous to what you did with the context, not great):

foo = Foo()

def func_a():
    foo.method_1()

def func_b():
    foo.method_2()

func_a()
func_b()

Pass foo as an argument:

def func_a(foo):
    foo.method_1()

def func_b(foo):
    foo.method_2()

def main():
    foo = Foo()
    func_a(foo=foo)
    func_b(foo=foo)

Make foo a class attribute:

class MyClass:
    def __init__(self, foo):
        self.foo = foo

    def func_a(self):
        self.foo.method_1()

    def func_b(self):
        self.foo.method_2()

my_class = MyClass(Foo())
my_class.func_a()
my_class.func_b()



Even if you stick to using global variables, setting global sslcontext is unnecessary because you're not reassigning it. If you're not assigning to a variable, Python will:

i. Try to find the name locally;

ii. If that fails, look for the name in global scope;

iii. Finally, raise a NameError to indicate the variable doesn't exist in any scope.

Therefore, if you reference sslcontext locally, the interpreter will find the global name (ii.). But it can't read your mind. If you instead assign sslcontext = 42, Python will assume you want to create a fresh, local variable with the name 'sslcontext' and the value of 42, rather than reassigning the global sslcontext. That's it. That's where global comes in, and that's all it's good for.
In HSTSHandler.end_headers(), this idiom:

SimpleHTTPRequestHandler.end_headers(self)


... could be more clearly expressed by calling super(), then super().end_headers(). This is good practice, and also assures multi-inheritance is handled correctly.
Source code encoding does not need to be set explicitly here, as ASCII will suffice.


That's as much as I can give you without more context to the question.