1 #!/usr/bin/env python 2 3 """ 4 WSGI adapter. 5 6 Copyright (C) 2004, 2005, 2006, 2007 Paul Boddie <paul@boddie.org.uk> 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public 10 License as published by the Free Software Foundation; either 11 version 2.1 of the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 """ 22 23 import WebStack.WSGI 24 from WebStack.Generic import EndOfResponse 25 from WebStack.Adapters.Helpers.wsgi_cgi import run_with_cgi 26 from WebStack.Adapters.Helpers.Error import ErrorResource 27 28 class WSGIAdapter: 29 30 "A WSGI adapter class." 31 32 def __init__(self, resource, authenticator=None, handle_errors=1, error_resource=None): 33 34 """ 35 Initialise the adapter with the given WebStack 'resource' and the 36 optional 'authenticator'. The optional 'handle_errors' parameter (if 37 true) causes handlers to deal with uncaught exceptions cleanly, and the 38 optional 'error_resource' specifies an alternative error message 39 generation resource. 40 """ 41 42 self.resource = resource 43 self.authenticator = authenticator 44 self.handle_errors = handle_errors 45 self.error_resource = error_resource or ErrorResource() 46 47 def __call__(self, environ, start_response): 48 49 """ 50 Dispatch to the root application-specific 'resource'. Return a list of 51 strings comprising the response body text. 52 """ 53 54 # NOTE: It would be best to give start_response to the transaction so 55 # NOTE: that the underlying response's write method can be used by the 56 # NOTE: transaction directly. Unfortunately, WebStack doesn't provide 57 # NOTE: any means of declaring when the headers have been set and when 58 # NOTE: response body output is the only thing to be subsequently 59 # NOTE: produced. 60 61 trans = WebStack.WSGI.Transaction(environ) 62 63 try: 64 if self.authenticator is None or self.authenticator.authenticate(trans): 65 try: 66 self.resource.respond(trans) 67 except EndOfResponse: 68 pass 69 except: 70 if self.handle_errors: 71 trans.rollback() 72 trans.set_response_code(500) # Internal error 73 self.error_resource.respond(trans) 74 else: 75 raise 76 else: 77 trans.set_response_code(401) # Unauthorized 78 trans.set_header_value("WWW-Authenticate", '%s realm="%s"' % ( 79 self.authenticator.get_auth_type(), self.authenticator.get_realm())) 80 finally: 81 trans.commit() 82 83 # NOTE: Provide sensible messages. 84 # NOTE: Ignoring the write method returned by start_response. 85 86 start_response( 87 "%s WebStack status" % trans.get_response_code(), 88 trans.get_wsgi_headers() 89 ) 90 return [trans.get_wsgi_content()] 91 92 def deploy_as_cgi(resource, authenticator=None, address=None, handle_errors=1, error_resource=None): 93 94 """ 95 Deploy the given 'resource', with the given optional 'authenticator', at the 96 given optional 'address', where 'address' is a 2-tuple of the form 97 (host_string, port_integer). 98 99 NOTE: The 'address' is ignored with the current WSGI implementation. 100 101 The optional 'handle_errors' flag (true by default) specifies whether error 102 conditions are handled gracefully, and the optional 'error_resource' 103 specifies an alternative error message generation resource, if desired. 104 """ 105 106 handler = WSGIAdapter(resource, authenticator, handle_errors, error_resource) 107 run_with_cgi(handler) 108 109 try: 110 import wsgiref.simple_server 111 except ImportError: 112 pass 113 else: 114 default_address = ("", 8080) 115 116 def deploy_with_wsgiref(resource, authenticator=None, address=None, handle_errors=1, error_resource=None): 117 118 """ 119 Deploy the given 'resource', with the given optional 'authenticator', at the 120 given optional 'address', where 'address' is a 2-tuple of the form 121 (host_string, port_integer). 122 123 The optional 'handle_errors' flag (true by default) specifies whether error 124 conditions are handled gracefully, and the optional 'error_resource' 125 specifies an alternative error message generation resource, if desired. 126 """ 127 128 host, port = address or default_address 129 handler = WSGIAdapter(resource, authenticator, handle_errors, error_resource) 130 app = wsgiref.simple_server.make_server(host, port or default_address, handler) 131 app.serve_forever() 132 133 # vim: tabstop=4 expandtab shiftwidth=4