111111except ImportError :
112112 ssl = None
113113
114+ from getpass import getpass
114115from http import HTTPStatus
115116
116117
@@ -1261,14 +1262,19 @@ def run_cgi(self):
12611262
12621263class HTTPSServer (HTTPServer ):
12631264 def __init__ (self , server_address , RequestHandlerClass ,
1264- bind_and_activate = True , * , certfile , keyfile ):
1265+ bind_and_activate = True , * , certfile , keyfile = None ,
1266+ password = None , alpn_protocols = None ):
12651267 if ssl is None :
12661268 raise ImportError ("SSL support missing" )
12671269 if not certfile :
12681270 raise TypeError ("__init__() missing required argument 'certfile'" )
12691271
12701272 self .certfile = certfile
12711273 self .keyfile = keyfile
1274+ self .password = password
1275+ # Support by default HTTP/1.1
1276+ self .alpn_protocols = alpn_protocols or ["http/1.1" ]
1277+
12721278 super ().__init__ (server_address , RequestHandlerClass , bind_and_activate )
12731279
12741280 def server_activate (self ):
@@ -1277,8 +1283,12 @@ def server_activate(self):
12771283 raise ImportError ("SSL support missing" )
12781284
12791285 super ().server_activate ()
1286+
12801287 context = ssl .create_default_context (ssl .Purpose .CLIENT_AUTH )
1281- context .load_cert_chain (certfile = self .certfile , keyfile = self .keyfile )
1288+ context .load_cert_chain (certfile = self .certfile ,
1289+ keyfile = self .keyfile ,
1290+ password = self .password )
1291+ context .set_alpn_protocols (self .alpn_protocols )
12821292 self .socket = context .wrap_socket (self .socket , server_side = True )
12831293
12841294
@@ -1299,7 +1309,7 @@ def _get_best_family(*address):
12991309def test (HandlerClass = BaseHTTPRequestHandler ,
13001310 ServerClass = ThreadingHTTPServer ,
13011311 protocol = "HTTP/1.0" , port = 8000 , bind = None ,
1302- tls_cert = None , tls_key = None ):
1312+ tls_cert = None , tls_key = None , tls_password = None ):
13031313 """Test the HTTP request handler class.
13041314
13051315 This runs an HTTP server on port 8000 (or the port argument).
@@ -1311,9 +1321,8 @@ def test(HandlerClass=BaseHTTPRequestHandler,
13111321 if not tls_cert :
13121322 server = ServerClass (addr , HandlerClass )
13131323 else :
1314- server = ThreadingHTTPSServer (
1315- addr , HandlerClass , certfile = tls_cert , keyfile = tls_key
1316- )
1324+ server = ThreadingHTTPSServer (addr , HandlerClass , certfile = tls_cert ,
1325+ keyfile = tls_key , password = tls_password )
13171326
13181327 with server as httpd :
13191328 host , port = httpd .socket .getsockname ()[:2 ]
@@ -1334,31 +1343,42 @@ def test(HandlerClass=BaseHTTPRequestHandler,
13341343 import argparse
13351344 import contextlib
13361345
1346+ PASSWORD_EMPTY = object ()
1347+
13371348 parser = argparse .ArgumentParser ()
13381349 parser .add_argument ("--cgi" , action = "store_true" ,
1339- help = "Run as CGI server" )
1350+ help = "run as CGI server" )
13401351 parser .add_argument ("-b" , "--bind" , metavar = "ADDRESS" ,
1341- help = "Bind to this address "
1352+ help = "bind to this address "
13421353 "(default: all interfaces)" )
13431354 parser .add_argument ("-d" , "--directory" , default = os .getcwd (),
1344- help = "Serve this directory "
1355+ help = "serve this directory "
13451356 "(default: current directory)" )
13461357 parser .add_argument ("-p" , "--protocol" , metavar = "VERSION" ,
13471358 default = "HTTP/1.0" ,
1348- help = "Conform to this HTTP version "
1359+ help = "conform to this HTTP version "
13491360 "(default: %(default)s)" )
13501361 parser .add_argument ("--tls-cert" , metavar = "PATH" ,
1351- help = "Specify the path to a TLS certificate" )
1362+ help = "path to the TLS certificate" )
13521363 parser .add_argument ("--tls-key" , metavar = "PATH" ,
1353- help = "Specify the path to a TLS key" )
1364+ help = "path to the TLS key" )
1365+ parser .add_argument ("--tls-password" , metavar = "PASSWORD" , nargs = "?" ,
1366+ default = None , const = PASSWORD_EMPTY ,
1367+ help = "password for the TLS key "
1368+ "(default: empty)" )
13541369 parser .add_argument ("port" , default = 8000 , type = int , nargs = "?" ,
1355- help = "Bind to this port "
1370+ help = "bind to this port "
13561371 "(default: %(default)s)" )
13571372 args = parser .parse_args ()
13581373
13591374 if not args .tls_cert and args .tls_key :
13601375 parser .error ("--tls-key requires --tls-cert to be set" )
13611376
1377+ if not args .tls_key and args .tls_password :
1378+ parser .error ("--tls-password requires --tls-key to be set" )
1379+ elif args .tls_password is PASSWORD_EMPTY :
1380+ args .tls_password = getpass ("Enter the password for the TLS key: " )
1381+
13621382 if args .cgi :
13631383 handler_class = CGIHTTPRequestHandler
13641384 else :
@@ -1384,4 +1404,5 @@ def finish_request(self, request, client_address):
13841404 protocol = args .protocol ,
13851405 tls_cert = args .tls_cert ,
13861406 tls_key = args .tls_key ,
1407+ tls_password = args .tls_password ,
13871408 )
0 commit comments