Skip to content

Instantly share code, notes, and snippets.

@dragermrb
Last active December 28, 2023 06:10
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save dragermrb/108158f5a284b5fba806 to your computer and use it in GitHub Desktop.
Save dragermrb/108158f5a284b5fba806 to your computer and use it in GitHub Desktop.
Python 3 HTTP Server with Basic Authentication
import http.server
import cgi
import base64
import json
from urllib.parse import urlparse, parse_qs
class CustomServerHandler(http.server.BaseHTTPRequestHandler):
def do_HEAD(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
def do_AUTHHEAD(self):
self.send_response(401)
self.send_header(
'WWW-Authenticate', 'Basic realm="Demo Realm"')
self.send_header('Content-type', 'application/json')
self.end_headers()
def do_GET(self):
key = self.server.get_auth_key()
''' Present frontpage with user authentication. '''
if self.headers.get('Authorization') == None:
self.do_AUTHHEAD()
response = {
'success': False,
'error': 'No auth header received'
}
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
elif self.headers.get('Authorization') == 'Basic ' + str(key):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
getvars = self._parse_GET()
response = {
'path': self.path,
'get_vars': str(getvars)
}
base_path = urlparse(self.path).path
if base_path == '/path1':
# Do some work
pass
elif base_path == '/path2':
# Do some work
pass
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
else:
self.do_AUTHHEAD()
response = {
'success': False,
'error': 'Invalid credentials'
}
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
def do_POST(self):
key = self.server.get_auth_key()
''' Present frontpage with user authentication. '''
if self.headers.get('Authorization') == None:
self.do_AUTHHEAD()
response = {
'success': False,
'error': 'No auth header received'
}
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
elif self.headers.get('Authorization') == 'Basic ' + str(key):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
postvars = self._parse_POST()
getvars = self._parse_GET()
response = {
'path': self.path,
'get_vars': str(getvars),
'get_vars': str(postvars)
}
base_path = urlparse(self.path).path
if base_path == '/path1':
# Do some work
pass
elif base_path == '/path2':
# Do some work
pass
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
else:
self.do_AUTHHEAD()
response = {
'success': False,
'error': 'Invalid credentials'
}
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
response = {
'path': self.path,
'get_vars': str(getvars),
'get_vars': str(postvars)
}
self.wfile.write(bytes(json.dumps(response), 'utf-8'))
def _parse_POST(self):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
if ctype == 'multipart/form-data':
postvars = cgi.parse_multipart(self.rfile, pdict)
elif ctype == 'application/x-www-form-urlencoded':
length = int(self.headers.getheader('content-length'))
postvars = cgi.parse_qs(
self.rfile.read(length), keep_blank_values=1)
else:
postvars = {}
return postvars
def _parse_GET(self):
getvars = parse_qs(urlparse(self.path).query)
return getvars
class CustomHTTPServer(http.server.HTTPServer):
key = ''
def __init__(self, address, handlerClass=CustomServerHandler):
super().__init__(address, handlerClass)
def set_auth(self, username, password):
self.key = base64.b64encode(
bytes('%s:%s' % (username, password), 'utf-8')).decode('ascii')
def get_auth_key(self):
return self.key
if __name__ == '__main__':
server = CustomHTTPServer(, ('', 8888))
server.set_auth('demo', 'demo')
server.serve_forever()
@mazzma12
Copy link

Traceback (most recent call last):
  File "server.py", line 156, in <module>
    server = CustomHTTPServer(None, ('hello.com', 8888))
  File "server.py", line 145, in __init__
    super().__init__(address, handlerClass)
  File "/usr/lib/python3.5/socketserver.py", line 440, in __init__
    self.server_bind()
  File "/usr/lib/python3.5/http/server.py", line 138, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "/usr/lib/python3.5/socketserver.py", line 454, in server_bind
    self.socket.bind(self.server_address)
TypeError: getsockaddrarg: AF_INET address must be tuple, not NoneType

It seems that the arg None in l.156 server = CustomHTTPServer(None, ('', 8888)) was not intended

@2114L3
Copy link

2114L3 commented Mar 21, 2018

drop the None
server = CustomHTTPServer(('', 8888))

@ehunaj
Copy link

ehunaj commented Nov 23, 2019

def run(server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment