Skip to content

Instantly share code, notes, and snippets.

@tomazas
Last active January 25, 2022 14:29
Show Gist options
  • Save tomazas/af5b47bbf334b6502f8a0c94069a6540 to your computer and use it in GitHub Desktop.
Save tomazas/af5b47bbf334b6502f8a0c94069a6540 to your computer and use it in GitHub Desktop.
Python 3 multi-threaded HTTPS server implementing GET & POST on port 443
# Python 3 multi-threaded HTTPS server implementing GET & POST on port 443
# Tested using Python 3.10.1
# can be used with a generated self-signed certificate using bash command:
# openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
# run using below run.sh bash script:
'''
#!/bin/bash
nohup /usr/bin/python -u http_ssl_server.py > server.log 2>&1 &
echo $! > pid
'''
# stop using below stop.sh bash script:
'''
#!/bin/bash
kill -9 `cat pid`
rm pid
'''
import http.server
import socketserver
import sys
import ssl
import socket
# config
hostName = "0.0.0.0"
serverPort = 443
socket_timeout = 2
payload = "<html><head></head><body><h2>%s<br/>SSL node reached successfully</h2></body></html>"
class Handler(http.server.BaseHTTPRequestHandler):
def respond(self, title):
self.sys_version = "1.0"
self.server_version = "HTTPS Server" # prevent leaking python version
self.close_connection = True # ensure threads close the socket
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(str.encode(payload%title))
def do_GET(self):
self.respond("HTTP GET")
def do_POST(self):
content_len = int(self.headers.get('Content-Length', 0))
if content_len > 0:
post_body = self.rfile.read(content_len)
self.respond("HTTP POST")
# patch for Python3 issue #46518
old_accept = socket.socket.accept
def patch_accept(self):
newsock, addr = old_accept(self)
newsock.settimeout(socket_timeout)
return newsock, addr
socket.socket.accept = patch_accept
print("starting %s:%d"%(hostName, serverPort))
httpd = http.server.ThreadingHTTPServer((hostName, serverPort), Handler)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.verify_mode = ssl.CERT_OPTIONAL # client is not required to provide certificate
ctx.check_hostname = False # server hostname not validated agains certificate
ctx.load_default_certs()
ctx.load_cert_chain(certfile='./cert.pem', keyfile='./key.pem', password=None)
httpd.socket = ctx.wrap_socket(httpd.socket,server_side=True)
httpd.serve_forever()
print("done")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment