blob: 249716299d25590c8bdf9a55ef3b8a4817cc544e [file] [log] [blame]
# Copyright (c) The PyAMF Project.
# See LICENSE.txt for details.
"""
WSGI server implementation.
The Python Web Server Gateway Interface (WSGI) is a simple and universal
interface between web servers and web applications or frameworks.
The WSGI interface has two sides: the "server" or "gateway" side, and the
"application" or "framework" side. The server side invokes a callable
object (usually a function or a method) that is provided by the application
side. Additionally WSGI provides middlewares; a WSGI middleware implements
both sides of the API, so that it can be inserted "between" a WSGI server
and a WSGI application -- the middleware will act as an application from
the server's point of view, and as a server from the application's point
of view.
@see: U{WSGI homepage (external)<http://wsgi.org>}
@see: U{PEP-333 (external)<http://www.python.org/peps/pep-0333.html>}
@since: 0.1.0
"""
import pyamf
from pyamf import remoting
from pyamf.remoting import gateway
__all__ = ['WSGIGateway']
class WSGIGateway(gateway.BaseGateway):
"""
WSGI Remoting Gateway.
"""
def getResponse(self, request, environ):
"""
Processes the AMF request, returning an AMF response.
@param request: The AMF Request.
@type request: L{Envelope<pyamf.remoting.Envelope>}
@rtype: L{Envelope<pyamf.remoting.Envelope>}
@return: The AMF Response.
"""
response = remoting.Envelope(request.amfVersion)
for name, message in request:
processor = self.getProcessor(message)
environ['pyamf.request'] = message
response[name] = processor(message, http_request=environ)
return response
def badRequestMethod(self, environ, start_response):
"""
Return HTTP 400 Bad Request.
"""
response = "400 Bad Request\n\nTo access this PyAMF gateway you " \
"must use POST requests (%s received)" % environ['REQUEST_METHOD']
start_response('400 Bad Request', [
('Content-Type', 'text/plain'),
('Content-Length', str(len(response))),
('Server', gateway.SERVER_NAME),
])
return [response]
def __call__(self, environ, start_response):
"""
@rtype: C{StringIO}
@return: File-like object.
"""
if environ['REQUEST_METHOD'] != 'POST':
return self.badRequestMethod(environ, start_response)
body = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
stream = None
timezone_offset = self._get_timezone_offset()
# Decode the request
try:
request = remoting.decode(body, strict=self.strict,
logger=self.logger, timezone_offset=timezone_offset)
except (pyamf.DecodeError, IOError):
if self.logger:
self.logger.exception('Error decoding AMF request')
response = "400 Bad Request\n\nThe request body was unable to " \
"be successfully decoded."
if self.debug:
response += "\n\nTraceback:\n\n%s" % gateway.format_exception()
start_response('400 Bad Request', [
('Content-Type', 'text/plain'),
('Content-Length', str(len(response))),
('Server', gateway.SERVER_NAME),
])
return [response]
except (KeyboardInterrupt, SystemExit):
raise
except:
if self.logger:
self.logger.exception('Unexpected error decoding AMF request')
response = ("500 Internal Server Error\n\nAn unexpected error "
"occurred whilst decoding.")
if self.debug:
response += "\n\nTraceback:\n\n%s" % gateway.format_exception()
start_response('500 Internal Server Error', [
('Content-Type', 'text/plain'),
('Content-Length', str(len(response))),
('Server', gateway.SERVER_NAME),
])
return [response]
if self.logger:
self.logger.debug("AMF Request: %r" % request)
# Process the request
try:
response = self.getResponse(request, environ)
except (KeyboardInterrupt, SystemExit):
raise
except:
if self.logger:
self.logger.exception('Error processing AMF request')
response = ("500 Internal Server Error\n\nThe request was "
"unable to be successfully processed.")
if self.debug:
response += "\n\nTraceback:\n\n%s" % gateway.format_exception()
start_response('500 Internal Server Error', [
('Content-Type', 'text/plain'),
('Content-Length', str(len(response))),
('Server', gateway.SERVER_NAME),
])
return [response]
if self.logger:
self.logger.debug("AMF Response: %r" % response)
# Encode the response
try:
stream = remoting.encode(response, strict=self.strict,
timezone_offset=timezone_offset)
except:
if self.logger:
self.logger.exception('Error encoding AMF request')
response = ("500 Internal Server Error\n\nThe request was "
"unable to be encoded.")
if self.debug:
response += "\n\nTraceback:\n\n%s" % gateway.format_exception()
start_response('500 Internal Server Error', [
('Content-Type', 'text/plain'),
('Content-Length', str(len(response))),
('Server', gateway.SERVER_NAME),
])
return [response]
response = stream.getvalue()
start_response('200 OK', [
('Content-Type', remoting.CONTENT_TYPE),
('Content-Length', str(len(response))),
('Server', gateway.SERVER_NAME),
])
return [response]