|
83 | 83 | __version__ = "0.6" |
84 | 84 |
|
85 | 85 | __all__ = [ |
86 | | - "HTTPServer", "ThreadingHTTPServer", "BaseHTTPRequestHandler", |
87 | | - "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler", "HTTPSServer", |
88 | | - "ThreadingHTTPSServer", |
| 86 | + "HTTPServer", "ThreadingHTTPServer", |
| 87 | + "HTTPSServer", "ThreadingHTTPSServer", |
| 88 | + "BaseHTTPRequestHandler", "SimpleHTTPRequestHandler", |
| 89 | + "CGIHTTPRequestHandler", |
89 | 90 | ] |
90 | 91 |
|
91 | 92 | import copy |
@@ -150,6 +151,56 @@ class ThreadingHTTPServer(socketserver.ThreadingMixIn, HTTPServer): |
150 | 151 | daemon_threads = True |
151 | 152 |
|
152 | 153 |
|
| 154 | +class HTTPSServer(HTTPServer): |
| 155 | + def __init__(self, server_address, RequestHandlerClass, |
| 156 | + bind_and_activate=True, *, certfile, keyfile=None, |
| 157 | + password=None, alpn_protocols=None): |
| 158 | + try: |
| 159 | + import ssl |
| 160 | + except ImportError: |
| 161 | + raise RuntimeError("SSL module is missing; HTTPS support is unavailable") |
| 162 | + |
| 163 | + self.ssl = ssl |
| 164 | + self.certfile = certfile |
| 165 | + self.keyfile = keyfile |
| 166 | + self.password = password |
| 167 | + # Support by default HTTP/1.1 |
| 168 | + self.alpn_protocols = ["http/1.1"] if alpn_protocols is None else alpn_protocols |
| 169 | + |
| 170 | + super().__init__(server_address, RequestHandlerClass, bind_and_activate) |
| 171 | + |
| 172 | + def server_activate(self): |
| 173 | + """Wrap the socket in SSLSocket.""" |
| 174 | + super().server_activate() |
| 175 | + |
| 176 | + context = self._create_context() |
| 177 | + self.socket = context.wrap_socket(self.socket, server_side=True) |
| 178 | + |
| 179 | + def _create_context(self): |
| 180 | + """Create a secure SSL context.""" |
| 181 | + context = self.ssl.create_default_context(self.ssl.Purpose.CLIENT_AUTH) |
| 182 | + context.load_cert_chain(certfile=self.certfile, |
| 183 | + keyfile=self.keyfile, |
| 184 | + password=self.password) |
| 185 | + context.set_alpn_protocols(self.alpn_protocols) |
| 186 | + |
| 187 | + return context |
| 188 | + |
| 189 | + |
| 190 | +class ThreadingHTTPSServer(socketserver.ThreadingMixIn, HTTPSServer): |
| 191 | + daemon_threads = True |
| 192 | + |
| 193 | + |
| 194 | +def _get_best_family(*address): |
| 195 | + infos = socket.getaddrinfo( |
| 196 | + *address, |
| 197 | + type=socket.SOCK_STREAM, |
| 198 | + flags=socket.AI_PASSIVE, |
| 199 | + ) |
| 200 | + family, type, proto, canonname, sockaddr = next(iter(infos)) |
| 201 | + return family, sockaddr |
| 202 | + |
| 203 | + |
153 | 204 | class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): |
154 | 205 |
|
155 | 206 | """HTTP request handler base class. |
@@ -1252,56 +1303,6 @@ def run_cgi(self): |
1252 | 1303 | self.log_message("CGI script exited OK") |
1253 | 1304 |
|
1254 | 1305 |
|
1255 | | -class HTTPSServer(HTTPServer): |
1256 | | - def __init__(self, server_address, RequestHandlerClass, |
1257 | | - bind_and_activate=True, *, certfile, keyfile=None, |
1258 | | - password=None, alpn_protocols=None): |
1259 | | - try: |
1260 | | - import ssl |
1261 | | - except ImportError: |
1262 | | - raise RuntimeError("SSL module is missing; HTTPS support is unavailable") |
1263 | | - |
1264 | | - self.ssl = ssl |
1265 | | - self.certfile = certfile |
1266 | | - self.keyfile = keyfile |
1267 | | - self.password = password |
1268 | | - # Support by default HTTP/1.1 |
1269 | | - self.alpn_protocols = ["http/1.1"] if alpn_protocols is None else alpn_protocols |
1270 | | - |
1271 | | - super().__init__(server_address, RequestHandlerClass, bind_and_activate) |
1272 | | - |
1273 | | - def server_activate(self): |
1274 | | - """Wrap the socket in SSLSocket.""" |
1275 | | - super().server_activate() |
1276 | | - |
1277 | | - context = self._create_context() |
1278 | | - self.socket = context.wrap_socket(self.socket, server_side=True) |
1279 | | - |
1280 | | - def _create_context(self): |
1281 | | - """Create a secure SSL context.""" |
1282 | | - context = self.ssl.create_default_context(self.ssl.Purpose.CLIENT_AUTH) |
1283 | | - context.load_cert_chain(certfile=self.certfile, |
1284 | | - keyfile=self.keyfile, |
1285 | | - password=self.password) |
1286 | | - context.set_alpn_protocols(self.alpn_protocols) |
1287 | | - |
1288 | | - return context |
1289 | | - |
1290 | | - |
1291 | | -class ThreadingHTTPSServer(socketserver.ThreadingMixIn, HTTPSServer): |
1292 | | - daemon_threads = True |
1293 | | - |
1294 | | - |
1295 | | -def _get_best_family(*address): |
1296 | | - infos = socket.getaddrinfo( |
1297 | | - *address, |
1298 | | - type=socket.SOCK_STREAM, |
1299 | | - flags=socket.AI_PASSIVE, |
1300 | | - ) |
1301 | | - family, type, proto, canonname, sockaddr = next(iter(infos)) |
1302 | | - return family, sockaddr |
1303 | | - |
1304 | | - |
1305 | 1306 | def test(HandlerClass=BaseHTTPRequestHandler, |
1306 | 1307 | ServerClass=ThreadingHTTPServer, |
1307 | 1308 | protocol="HTTP/1.0", port=8000, bind=None, |
|
0 commit comments