| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -32,14 +32,26 @@ handler. Code to create and run the server looks like this:: | |
| httpd.serve_forever() | ||
|
|
||
|
|
||
| .. class:: HTTPServer(server_address, RequestHandlerClass) | ||
| .. class:: HTTPServer(server_address, RequestHandlerClass, \ | ||
| bind_and_activate=True, *, tls=None) | ||
|
|
||
| This class builds on the :class:`~socketserver.TCPServer` class by storing | ||
| the server address as instance variables named :attr:`server_name` and | ||
| :attr:`server_port`. The server is accessible by the handler, typically | ||
| through the handler's :attr:`server` instance variable. | ||
|
|
||
| .. class:: ThreadingHTTPServer(server_address, RequestHandlerClass) | ||
| HTTPS support can be enabled using the *tls* argument. In this case, it must | ||
| be a tuple of two strings, the first being the path to an SSL certificate and | ||
| the second the path to its private key. | ||
|
|
||
| .. warning:: | ||
|
|
||
| The HTTPS support is for development and test puposes and must not be used | ||
|
Comment thread
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityspelling: purposes
Sorry, something went wrong.
All reactions
|
||
| in production. | ||
|
|
||
|
|
||
| .. class:: ThreadingHTTPServer(server_address, RequestHandlerClass, \ | ||
| bind_and_activate=True, *, tls=None) | ||
|
|
||
| This class is identical to HTTPServer but uses threads to handle | ||
| requests by using the :class:`~socketserver.ThreadingMixIn`. This | ||
| Expand Down | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -101,6 +101,7 @@ | |
| import socket # For gethostbyaddr() | ||
| import socketserver | ||
| import sys | ||
| import ssl | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityssl support is optional, you have to wrap the import in a try/except block.
Sorry, something went wrong.
All reactions
|
||
| import time | ||
| import urllib.parse | ||
| import contextlib | ||
| Expand Down Expand Up | @@ -131,7 +132,23 @@ | |
|
|
||
| class HTTPServer(socketserver.TCPServer): | ||
|
|
||
| allow_reuse_address = 1 # Seems to make sense in testing environment | ||
| allow_reuse_address = True # Seems to make sense in testing environment | ||
|
|
||
| def __init__(self, server_address, RequestHandlerClass, | ||
| bind_and_activate=True, *, tls=None): | ||
| if tls is None: | ||
| self.tls_cert = self.tls_key = None | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt's not a cert file, it's a cert chain file.
Sorry, something went wrong.
All reactions
|
||
| else: | ||
| self.tls_cert, self.tls_key = tls | ||
| super().__init__(server_address, RequestHandlerClass, bind_and_activate) | ||
|
|
||
| def server_activate(self): | ||
| """Wrap the socket in SSLSocket if TLS is enabled""" | ||
| super().server_activate() | ||
| if self.tls_cert and self.tls_key: | ||
| context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityuse ssl.create_default_context.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThe default SSL context requires a TLS 1.3 certificate so it doesn't work with ssl_cert.pem: ssl.SSLError: [SSL: TLSV13_ALERT_CERTIFICATE_REQUIRED] tlsv13 alert certificate required Is this something that we want to force for a development server?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThere is no such thing as a TLS 1.3 certificate. This is a TLS alert with message certificate required. Looks like the certificate does not have correct extensions to handle TLS 1.3. You cannot use any file from test directory any way. The directory is often not installed or shipped to reduce disk space usage in containers or on small systems.
Sorry, something went wrong.
All reactions
|
||
| context.load_cert_chain(self.tls_cert, self.tls_key) | ||
| self.socket = context.wrap_socket(self.socket, server_side=True) | ||
|
|
||
| def server_bind(self): | ||
| """Override server_bind to store the server name.""" | ||
| Expand Down Expand Up | @@ -1237,7 +1254,7 @@ def _get_best_family(*address): | |
|
|
||
| def test(HandlerClass=BaseHTTPRequestHandler, | ||
| ServerClass=ThreadingHTTPServer, | ||
| protocol="HTTP/1.0", port=8000, bind=None): | ||
| protocol="HTTP/1.0", port=8000, bind=None, tls=None): | ||
| """Test the HTTP request handler class. | ||
|
|
||
| This runs an HTTP server on port 8000 (or the port argument). | ||
| Expand All | @@ -1246,12 +1263,13 @@ def test(HandlerClass=BaseHTTPRequestHandler, | |
| ServerClass.address_family, addr = _get_best_family(bind, port) | ||
|
|
||
| HandlerClass.protocol_version = protocol | ||
| with ServerClass(addr, HandlerClass) as httpd: | ||
| with ServerClass(addr, HandlerClass, tls=tls) as httpd: | ||
| host, port = httpd.socket.getsockname()[:2] | ||
| url_host = f'[{host}]' if ':' in host else host | ||
| protocol = 'HTTPS' if tls else 'HTTP' | ||
| print( | ||
| f"Serving HTTP on {host} port {port} " | ||
| f"(http://{url_host}:{port}/) ..." | ||
| f"Serving {protocol} on {host} port {port} " | ||
| f"({protocol.lower()}://{url_host}:{port}/) ..." | ||
| ) | ||
| try: | ||
| httpd.serve_forever() | ||
| Expand All | @@ -1275,7 +1293,19 @@ def test(HandlerClass=BaseHTTPRequestHandler, | |
| default=8000, type=int, | ||
| nargs='?', | ||
| help='Specify alternate port [default: 8000]') | ||
| parser.add_argument('--tls-cert', | ||
| help='Specify the path to a TLS certificate') | ||
|
Comment thread
Comment on lines
+1296
to
+1297
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitycert chain
Sorry, something went wrong.
All reactions
|
||
| parser.add_argument('--tls-key', | ||
| help='Specify the path to a TLS key') | ||
| args = parser.parse_args() | ||
|
|
||
| if args.tls_cert is None and args.tls_key is None: | ||
| tls = None | ||
| elif not args.tls_cert or not args.tls_key: | ||
| parser.error('Both --tls-cert and --tls-key must be provided to enable TLS') | ||
| else: | ||
| tls = (args.tls_cert, args.tls_key) | ||
|
Comment thread
Comment on lines
+1304
to
+1307
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt's common to have the private key and the cert chain in the same file. The key argument should be optional.
Sorry, something went wrong.
All reactions
|
||
|
|
||
| if args.cgi: | ||
| handler_class = CGIHTTPRequestHandler | ||
| else: | ||
| Expand All | @@ -1296,4 +1326,5 @@ def server_bind(self): | |
| ServerClass=DualStackServer, | ||
| port=args.port, | ||
| bind=args.bind, | ||
| tls=tls | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -21,6 +21,7 @@ | |
| import html | ||
| import http.client | ||
| import urllib.parse | ||
| import ssl | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitytry/except ImportError
Sorry, something went wrong.
All reactions
|
||
| import tempfile | ||
| import time | ||
| import datetime | ||
| Expand All | @@ -43,13 +44,18 @@ def read(self, n=None): | |
|
|
||
|
|
||
| class TestServerThread(threading.Thread): | ||
| def __init__(self, test_object, request_handler): | ||
| def __init__(self, test_object, request_handler, tls=None): | ||
| threading.Thread.__init__(self) | ||
| self.request_handler = request_handler | ||
| self.test_object = test_object | ||
| self.tls = tls | ||
|
|
||
| def run(self): | ||
| self.server = HTTPServer(('localhost', 0), self.request_handler) | ||
| self.server = HTTPServer( | ||
| ('localhost', 0), | ||
| self.request_handler, | ||
| tls=self.tls | ||
| ) | ||
| self.test_object.HOST, self.test_object.PORT = self.server.socket.getsockname() | ||
| self.test_object.server_started.set() | ||
| self.test_object = None | ||
| Expand All | @@ -64,11 +70,13 @@ def stop(self): | |
|
|
||
|
|
||
| class BaseTestCase(unittest.TestCase): | ||
| tls = None | ||
|
|
||
| def setUp(self): | ||
| self._threads = threading_helper.threading_setup() | ||
| os.environ = support.EnvironmentVarGuard() | ||
| self.server_started = threading.Event() | ||
| self.thread = TestServerThread(self, self.request_handler) | ||
| self.thread = TestServerThread(self, self.request_handler, self.tls) | ||
| self.thread.start() | ||
| self.server_started.wait() | ||
|
|
||
| Expand Down Expand Up | @@ -291,6 +299,31 @@ def test_head_via_send_error(self): | |
| self.assertEqual(b'', data) | ||
|
|
||
|
|
||
| class BaseHTTPSServerTestCase(BaseTestCase): | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualitySkip the test if ssl module is not supported
Sorry, something went wrong.
All reactions
|
||
| # This is a simple test for the HTTPS support. If the GET works we don't | ||
| # need to test everything else as it will have been covered by | ||
| # BaseHTTPServerTestCase. | ||
|
|
||
| # We have to use the correct path from the folder created by regtest | ||
| tls = ('../../Lib/test/ssl_cert.pem', '../../Lib/test/ssl_key.pem') | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityos.path.join(os.path.dirname(__file__), 'ssl_cert.pem')
Sorry, something went wrong.
All reactions
|
||
|
|
||
| class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler): | ||
| pass | ||
|
|
||
| def test_get(self): | ||
| response = self.request('/') | ||
| self.assertEqual(response.status, HTTPStatus.OK) | ||
|
|
||
| def request(self, uri, method='GET', body=None, headers={}): | ||
| self.connection = http.client.HTTPSConnection( | ||
| self.HOST, | ||
| self.PORT, | ||
| context=ssl._create_unverified_context() | ||
| ) | ||
| self.connection.request(method, uri, body, headers) | ||
| return self.connection.getresponse() | ||
|
|
||
|
|
||
| class RequestHandlerLoggingTestCase(BaseTestCase): | ||
| class request_handler(BaseHTTPRequestHandler): | ||
| protocol_version = 'HTTP/1.1' | ||
| Expand Down | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| A ``tls`` argument has been added to :class:`http.server.HTTPServer` and | ||
| :class:`ThreadingHTTPServer` to enable HTTPS. The ``--tls-cert`` and | ||
| ``--tls-key`` argument have been added to ``python -m http.server``. Patch | ||
| contributed by Rémi Lapeyre. |
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis should be a separate class, not an argument.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.