# HG changeset patch # User paulb # Date 1172692130 0 # Node ID f992d6bff579c23985855f2ff3c62eb07de050d1 # Parent 9c9054eaea3de22b15c35d1fb277f8926b0e2ad2 [project @ 2007-02-28 19:48:50 by paulb] Added a secure_deploy function, changing various other details of the infrastructure to accommodate different kinds of servers and handlers. diff -r 9c9054eaea3d -r f992d6bff579 WebStack/Adapters/BaseHTTPRequestHandler.py --- a/WebStack/Adapters/BaseHTTPRequestHandler.py Wed Feb 28 19:48:19 2007 +0000 +++ b/WebStack/Adapters/BaseHTTPRequestHandler.py Wed Feb 28 19:48:50 2007 +0000 @@ -3,7 +3,7 @@ """ BaseHTTPRequestHandler adapter. -Copyright (C) 2004, 2005, 2006 Paul Boddie +Copyright (C) 2004, 2005, 2006, 2007 Paul Boddie This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,11 +25,16 @@ from WebStack.Generic import EndOfResponse from WebStack.Adapters.Helpers.Error import ErrorResource +# SSL-related imports. + +from OpenSSL import SSL +import socket + class HandlerFactory: "A factory class creating WebStack dispatcher objects." - def __init__(self, resource, authenticator=None, handle_errors=1, error_resource=None): + def __init__(self, resource, authenticator=None, handle_errors=1, error_resource=None, handler_class=None): """ Initialise the root application-specific 'resource' and optional @@ -37,18 +42,22 @@ handlers to deal with uncaught exceptions cleanly, and the optional 'error_resource' specifies an alternative error message generation resource. + + If the optional 'handler_class' is specified, it will be used to + instantiate handlers rather than the default Handler class. """ self.webstack_resource = resource self.webstack_authenticator = authenticator self.handle_errors = handle_errors self.error_resource = error_resource or ErrorResource() + self.handler_class = handler_class or Handler def __call__(self, request, client_address, server): "Act as a factory for the server objects." - handler = Handler(request, client_address, server, self.webstack_resource, + handler = self.handler_class(request, client_address, server, self.webstack_resource, self.webstack_authenticator, self.handle_errors, self.error_resource) return handler @@ -102,9 +111,49 @@ finally: trans.commit() +# Support for secure servers. + +class SecureHTTPServer(BaseHTTPServer.HTTPServer): + + "An HTTP server supporting https URLs." + + def __init__(self, server_address, HandlerClass, key_filename, certificate_filename): + + """ + Initialise the server using the given 'server_address' and + 'HandlerClass', along with the specified 'key_filename' and + 'certificate_filename'. + """ + + BaseHTTPServer.HTTPServer.__init__(self, server_address, HandlerClass) + context = SSL.Context(SSL.SSLv23_METHOD) + context.use_privatekey_file(key_filename) + context.use_certificate_file(certificate_filename) + self.socket = SSL.Connection(context, socket.socket(self.address_family, self.socket_type)) + self.server_bind() + self.server_activate() + +class SecureHandler(Handler): + + "A secure version of the handler." + + def setup(self): + + "Set up the connection and streams." + + self.connection = self.request + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + +def SecureHandlerFactory(resource, authenticator=None, handle_errors=1, error_resource=None, handler_class=None): + + "Return a secure handler factory, based on HandlerFactory." + + return HandlerFactory(resource, authenticator, handle_errors, error_resource, handler_class=(handler_class or SecureHandler)) + default_address = ("", 8080) -def deploy(resource, authenticator=None, address=None, handle_errors=1, error_resource=None): +def deploy(resource, authenticator=None, address=None, handle_errors=1, error_resource=None, server=None, factory=None, **server_args): """ Deploy the given 'resource', with the given optional 'authenticator', at the @@ -114,10 +163,33 @@ The optional 'handle_errors' flag (true by default) specifies whether error conditions are handled gracefully, and the optional 'error_resource' specifies an alternative error message generation resource, if desired. + + If the optional 'server' is specified, use the server provided as opposed to + the default BaseHTTPServer.HTTPServer class. Use any 'server_args' (provided + as additional keyword arguments) to instantiate the server. + + If the optional 'factory' is specified, use the factory provided as opposed + to the default HandlerFactory class. """ - handler = HandlerFactory(resource, authenticator, handle_errors, error_resource) - server = BaseHTTPServer.HTTPServer(address or default_address, handler) - server.serve_forever() + factory = factory or HandlerFactory + handler = factory(resource, authenticator, handle_errors, error_resource) + server = server or BaseHTTPServer.HTTPServer + app = server(address or default_address, handler, **(server_args or {})) + app.serve_forever() + +def secure_deploy(resource, authenticator=None, address=None, handle_errors=1, error_resource=None, server=None, factory=None, **server_args): + + """ + Deploy the given 'resource' using a secure version of the server, employing + the deploy function. + """ + + return deploy( + resource, authenticator, address, handle_errors, error_resource, + server=(server or SecureHTTPServer), + factory=(factory or SecureHandlerFactory), + **server_args + ) # vim: tabstop=4 expandtab shiftwidth=4