1.1 --- a/WebStack/Adapters/BaseHTTPRequestHandler.py Wed Feb 28 19:48:19 2007 +0000
1.2 +++ b/WebStack/Adapters/BaseHTTPRequestHandler.py Wed Feb 28 19:48:50 2007 +0000
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 BaseHTTPRequestHandler adapter.
1.6
1.7 -Copyright (C) 2004, 2005, 2006 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2004, 2005, 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This library is free software; you can redistribute it and/or
1.11 modify it under the terms of the GNU Lesser General Public
1.12 @@ -25,11 +25,16 @@
1.13 from WebStack.Generic import EndOfResponse
1.14 from WebStack.Adapters.Helpers.Error import ErrorResource
1.15
1.16 +# SSL-related imports.
1.17 +
1.18 +from OpenSSL import SSL
1.19 +import socket
1.20 +
1.21 class HandlerFactory:
1.22
1.23 "A factory class creating WebStack dispatcher objects."
1.24
1.25 - def __init__(self, resource, authenticator=None, handle_errors=1, error_resource=None):
1.26 + def __init__(self, resource, authenticator=None, handle_errors=1, error_resource=None, handler_class=None):
1.27
1.28 """
1.29 Initialise the root application-specific 'resource' and optional
1.30 @@ -37,18 +42,22 @@
1.31 handlers to deal with uncaught exceptions cleanly, and the optional
1.32 'error_resource' specifies an alternative error message generation
1.33 resource.
1.34 +
1.35 + If the optional 'handler_class' is specified, it will be used to
1.36 + instantiate handlers rather than the default Handler class.
1.37 """
1.38
1.39 self.webstack_resource = resource
1.40 self.webstack_authenticator = authenticator
1.41 self.handle_errors = handle_errors
1.42 self.error_resource = error_resource or ErrorResource()
1.43 + self.handler_class = handler_class or Handler
1.44
1.45 def __call__(self, request, client_address, server):
1.46
1.47 "Act as a factory for the server objects."
1.48
1.49 - handler = Handler(request, client_address, server, self.webstack_resource,
1.50 + handler = self.handler_class(request, client_address, server, self.webstack_resource,
1.51 self.webstack_authenticator, self.handle_errors, self.error_resource)
1.52 return handler
1.53
1.54 @@ -102,9 +111,49 @@
1.55 finally:
1.56 trans.commit()
1.57
1.58 +# Support for secure servers.
1.59 +
1.60 +class SecureHTTPServer(BaseHTTPServer.HTTPServer):
1.61 +
1.62 + "An HTTP server supporting https URLs."
1.63 +
1.64 + def __init__(self, server_address, HandlerClass, key_filename, certificate_filename):
1.65 +
1.66 + """
1.67 + Initialise the server using the given 'server_address' and
1.68 + 'HandlerClass', along with the specified 'key_filename' and
1.69 + 'certificate_filename'.
1.70 + """
1.71 +
1.72 + BaseHTTPServer.HTTPServer.__init__(self, server_address, HandlerClass)
1.73 + context = SSL.Context(SSL.SSLv23_METHOD)
1.74 + context.use_privatekey_file(key_filename)
1.75 + context.use_certificate_file(certificate_filename)
1.76 + self.socket = SSL.Connection(context, socket.socket(self.address_family, self.socket_type))
1.77 + self.server_bind()
1.78 + self.server_activate()
1.79 +
1.80 +class SecureHandler(Handler):
1.81 +
1.82 + "A secure version of the handler."
1.83 +
1.84 + def setup(self):
1.85 +
1.86 + "Set up the connection and streams."
1.87 +
1.88 + self.connection = self.request
1.89 + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
1.90 + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
1.91 +
1.92 +def SecureHandlerFactory(resource, authenticator=None, handle_errors=1, error_resource=None, handler_class=None):
1.93 +
1.94 + "Return a secure handler factory, based on HandlerFactory."
1.95 +
1.96 + return HandlerFactory(resource, authenticator, handle_errors, error_resource, handler_class=(handler_class or SecureHandler))
1.97 +
1.98 default_address = ("", 8080)
1.99
1.100 -def deploy(resource, authenticator=None, address=None, handle_errors=1, error_resource=None):
1.101 +def deploy(resource, authenticator=None, address=None, handle_errors=1, error_resource=None, server=None, factory=None, **server_args):
1.102
1.103 """
1.104 Deploy the given 'resource', with the given optional 'authenticator', at the
1.105 @@ -114,10 +163,33 @@
1.106 The optional 'handle_errors' flag (true by default) specifies whether error
1.107 conditions are handled gracefully, and the optional 'error_resource'
1.108 specifies an alternative error message generation resource, if desired.
1.109 +
1.110 + If the optional 'server' is specified, use the server provided as opposed to
1.111 + the default BaseHTTPServer.HTTPServer class. Use any 'server_args' (provided
1.112 + as additional keyword arguments) to instantiate the server.
1.113 +
1.114 + If the optional 'factory' is specified, use the factory provided as opposed
1.115 + to the default HandlerFactory class.
1.116 """
1.117
1.118 - handler = HandlerFactory(resource, authenticator, handle_errors, error_resource)
1.119 - server = BaseHTTPServer.HTTPServer(address or default_address, handler)
1.120 - server.serve_forever()
1.121 + factory = factory or HandlerFactory
1.122 + handler = factory(resource, authenticator, handle_errors, error_resource)
1.123 + server = server or BaseHTTPServer.HTTPServer
1.124 + app = server(address or default_address, handler, **(server_args or {}))
1.125 + app.serve_forever()
1.126 +
1.127 +def secure_deploy(resource, authenticator=None, address=None, handle_errors=1, error_resource=None, server=None, factory=None, **server_args):
1.128 +
1.129 + """
1.130 + Deploy the given 'resource' using a secure version of the server, employing
1.131 + the deploy function.
1.132 + """
1.133 +
1.134 + return deploy(
1.135 + resource, authenticator, address, handle_errors, error_resource,
1.136 + server=(server or SecureHTTPServer),
1.137 + factory=(factory or SecureHandlerFactory),
1.138 + **server_args
1.139 + )
1.140
1.141 # vim: tabstop=4 expandtab shiftwidth=4