import BaseHTTPServer, mimetools
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import threading, socket
from WebKit.NewThreadedAppServer import Handler
from WebKit.ASStreamOut import ASStreamOut
import time
class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Handles incoming requests. Recreated with every request.
Abstract base class.
"""
## This sends certain CGI variables. These are some that
## should be sent, but aren't:
## SERVER_ADDR
## SERVER_PORT
## SERVER_SOFTWARE
## SERVER_NAME
## HTTP_CONNECTION
## SERVER_PROTOCOL
## HTTP_KEEP_ALIVE
## These I don't think are needed:
## DOCUMENT_ROOT
## PATH_TRANSLATED
## GATEWAY_INTERFACE
## PATH
## SERVER_SIGNATURE
## SCRIPT_NAME (?)
## SCRIPT_FILENAME (?)
## SERVER_ADMIN (?)
def doRequest(self):
"""
Actually performs the request, creating the environment and
calling self.doTransaction(env, myInput) to perform the
response.
"""
self.server_version = 'Webware/0.1'
env = {}
if self.headers.has_key('Content-Type'):
env['CONTENT_TYPE'] = self.headers['Content-Type']
del self.headers['Content-Type']
self.headersToEnviron(self.headers, env)
env['REMOTE_ADDR'], env['REMOTE_PORT'] = map(str, self.client_address)
env['REQUEST_METHOD'] = self.command
path = self.path
if path.find('?') != -1:
env['REQUEST_URI'], env['QUERY_STRING'] = path.split('?', 1)
else:
env['REQUEST_URI'] = path
env['QUERY_STRING'] = ''
env['PATH_INFO'] = env['REQUEST_URI']
myInput = ''
if self.headers.has_key('Content-Length'):
myInput = self.rfile.read(int(self.headers['Content-Length']))
self.doTransaction(env, myInput)
do_GET = do_POST = do_HEAD = doRequest
# These methods are used in WebDAV requests:
do_OPTIONS = do_PUT = do_DELETE = doRequest
do_MKCOL = do_COPY = do_MOVE = doRequest
do_PROPFIND = doRequest
def headersToEnviron(self, headers, env):
"""Use a simple heuristic to convert all the headers to
environmental variables..."""
for header, value in headers.items():
env['HTTP_%s' % (header.upper().replace('-', '_'))] = value
return env
def processResponse(self, data):
"""
Takes a string (like what a CGI script would print) and
sends the actual HTTP response (response code, headers, body).
"""
s = StringIO(data)
headers = mimetools.Message(s)
self.doLocation(headers)
self.sendStatus(headers)
self.sendHeaders(headers)
self.sendBody(s)
def doLocation(self, headers):
"""If there's a Location header and no Status header,
we need to add a Status header ourselves."""
if headers.has_key('Location'):
if not headers.has_key('Status'):
## @@: is this the right status header?
headers['Status'] = '301 Moved Temporarily'
def sendStatus(self, headers):
if not headers.has_key('Status'):
status = "200 OK"
else:
status = headers['Status']
del headers['Status']
pos = status.find(' ')
if pos == -1:
code = int(status)
message = ''
else:
code = int(status[:pos])
message = status[pos:].strip()
self.send_response(code, message)
def sendHeaders(self, headers):
for header, value in headers.items():
self.send_header(header, value)
self.end_headers()
def sendBody(self, bodyFile):
self.wfile.write(bodyFile.read())
bodyFile.close()
class HTTPAppServerHandler(Handler, HTTPHandler):
"""
Adapters HTTPHandler to fit with ThreadedAppServer's
model of an adapter
"""
protocolName = 'http'
def handleRequest(self):
HTTPHandler.__init__(self, self._sock, self._sock.getpeername(), None)
def doTransaction(self, env, myInput):
streamOut = ASStreamOut()
requestDict = {
'format': 'CGI',
'time': time.time(),
'environ': env,
'input': StringIO(myInput),
}
self.dispatchRawRequest(requestDict, streamOut)
self.processResponse(streamOut._buffer)
self._sock.shutdown(2)
def dispatchRawRequest(self, requestDict, streamOut):
transaction = self._server._app.dispatchRawRequest(requestDict, streamOut)
streamOut.close()
transaction._application=None
transaction.die()
del transaction