###########################################
# mod_python adapter for WebKit
#
#
# Contributed by: Dave Wallace
# Modified by Jay Love and Geoff Talvola
#
##########################################
"""
Here's how I set up my Apache conf:
<Location /WK >
SetHandler python-program
# add the directory that contains ModPythonAdapter.py
PythonPath "sys.path+['/path/to/WebKit']"
PythonOption AppWorkDir /path/to/dir/with/adapter.address
PythonHandler WebKit.Adapters.ModPythonAdapter
PythonDebug On
</Location>
If you used the MakeAppWorkDir.py script to make a seperate
application working directory, specify that path for the AppWorkDir
option, otherwise it should be in your WebKit directory in which case
you should use /path/to/WebKit/adapter.address
http://localhost/WK/Welcome
You may also send all requests with a .psp extension to WebKit by adding these lines, outside
of any location or directory.
AddHandler python-program .psp
PythonPath "sys.path+['/path/to/WebKit']"
PythonHandler modpHandler::pspHandler
PythonOption AppWorkDir /path/to/dir/with/adapter.address
"""
# Fix the current working directory -- this gets initialized incorrectly
# for some reason when run using mod_python.
import os
try:
os.chdir(os.path.abspath(os.path.dirname(__file__)))
except Exception:
pass
from mod_python import apache
import time
from socket import *
import sys
from Adapter import Adapter
debug = 0
__adapter = None
bufsize = 32*1024
class ModPythonAdapter(Adapter):
def __init__(self, host, port, webkitdir):
Adapter.__init__(self, webkitdir)
self.host = host
self.port = port
def handler(self, req):
self.reset(req)
try:
# Get input
myInput = self.input(req)
# get the apache module to do the grunt work of
# building the environment
env=apache.build_cgi_env(req)
#make sure env is a dictionary (may not be for Apache2)
env=dict(env)
# Fix up the path
if not env.has_key('PATH_INFO'): env['PATH_INFO']=req.path_info
# Communicate with the app server
respdict = self.transactWithAppServer(env, myInput, self.host, self.port)
# Respond back to Apache
# self.respond(req, respdict)
except:
self.handleException(req)
return apache.OK
def pspHandler(self, req):
self.reset(req)
try:
# Get input
myInput = self.input(req)
# get the apache module to do the grunt work of
# building the environment
env=apache.build_cgi_env(req)
#make sure env is a dictionary (may not be for Apache2)
env=dict(env)
# Special environment setup needed for psp handler
env['WK_ABSOLUTE']=1
# Fix up the path
if not env.has_key('PATH_INFO'): env['PATH_INFO']=req.path_info
# Communicate with the app server
respdict = self.transactWithAppServer(env, myInput, self.host, self.port)
# Respond back to Apache
self.respond(req, respdict)
except:
self.handleException(req)
return apache.OK
def typehandler(self, req):
""" Not being used yet.
Probably never be used, b/c the req.handler field is read only in mod_python.
"""
self.reset(req)
debug=1
if debug:
ot = open("/tmp/log2.txt","a")
ot.write("In Type Handler\n")
ot.flush()
if req.filename is None:
return apache.DECLINED
fn = req.filename
if debug:
ot.write("TH: Filename: %s\n"%fn)
ext = fn[fn.rfind("."):]
if debug:
ot.write("TH: Extension: %s\n"%ext)
if debug:
ot.write("Req_Handler = %s\n"%req.handler)
ot.flush()
ot.close()
if ext == ".psp":
req.handler = "python-program"
return apache.OK
else:
return apache.DECLINED
def input(self, req):
myInput = ''
inp = req.read(bufsize)
# this looks like bad performance if we don't get it all
# in the first buffer
while inp:
myInput = myInput + inp
inp = req.read(bufsize)
return myInput
def processResponse(self, data):
req = self.request()
if self.doneHeader():
req.write(data)
return
headerData = self.headerData() + data
self.setHeaderData(headerData)
headerend = headerData.find("\r\n\r\n")
if headerend < 0:
return
headers = headerData[:headerend]
for header in headers.split("\r\n"):
colon = header.find(':')
name = header[:colon]
value = header[colon+1:]
req.headers_out.add(name, value)
if name.lower() == 'content-type':
req.content_type = value
if name.lower() == 'status':
req.status = int(value.lstrip().split(' ', 1)[0])
req.send_http_header()
req.write(headerData[headerend+4:])
self.setDoneHeader(1)
def handleException(self, req):
import traceback
apache.log_error('WebKit mod_python: Error while responding to request\n')
apache.log_error('Python exception:\n')
traceback.print_exc(file=sys.stderr)
output = traceback.format_exception(*sys.exc_info())
output = ''.join(output)
output = output.replace('&', '&'
).replace('<', '<').replace('>', '>')
req.write('''
<html><body>
<p><pre>ERROR
%s</pre>
</body></html>\n''' % output)
def reset(self, request):
self.setDoneHeader(0)
self.setHeaderData('')
self.setRequest(request)
# These methods are non-thread-safe. On platforms like NT where Apache runs multi-threaded,
# and the same ModPythonAdapter instance may be called simultaneously for different requests,
# they need to replaced with threadsafe versions. See WinModPythonAdapter below.
def doneHeader(self):
return self._doneHeader
def setDoneHeader(self, doneHeader):
self._doneHeader = doneHeader
def headerData(self):
return self._headerData
def setHeaderData(self, headerData):
self._headerData = headerData
def request(self):
return self._request
def setRequest(self, request):
self._request = request
# NT-specific, thread-safe version of ModPythonAdapter. Requires Win32 extensions.
if os.name == 'nt':
import win32api
# This is a Windows-specific thread-safe version of ModPythonAdapter. It replaces the
# non-thread-safe [set]doneHeader, [set]headerData, and [set]request with versions
# that store the information keyed by thread ID.
#
# This seems a bit hokey, but it was easy to write and it works.
OriginalModPythonAdapter = ModPythonAdapter
class WinModPythonAdapter(OriginalModPythonAdapter):
def __init__(self, host, port, webkitdir):
OriginalModPythonAdapter.__init__(self, host, port, webkitdir)
self._threadSafeStorage = {}
def threadSafeValue(self, name):
threadID = win32api.GetCurrentThreadId()
return self._threadSafeStorage[threadID, name]
def setThreadSafeValue(self, name, value):
threadID = win32api.GetCurrentThreadId()
self._threadSafeStorage[threadID, name] = value
def doneHeader(self):
return self.threadSafeValue('doneHeader')
def setDoneHeader(self, doneHeader):
self.setThreadSafeValue('doneHeader', doneHeader)
def headerData(self):
return self.threadSafeValue('headerData')
def setHeaderData(self, headerData):
self.setThreadSafeValue('headerData', headerData)
def request(self):
return self.threadSafeValue('request')
def setRequest(self, request):
self.setThreadSafeValue('request', request)
# Replace ModPythonAdapter with the Windows-safe version.
ModPythonAdapter = WinModPythonAdapter
def _adapter(req):
global __adapter
if __adapter is None:
appWorkDir = req.get_options()['AppWorkDir']
WEBWARE_ADDRESS_FILE = os.path.join(appWorkDir, 'adapter.address')
host, port = open(WEBWARE_ADDRESS_FILE).read().split(':')
port = int(port)
__adapter = ModPythonAdapter(host, port, appWorkDir)
return __adapter
def handler(req):
return _adapter(req).handler(req)
def pspHandler(req):
return _adapter(req).pspHandler(req)
def typehandler(req):
return _adapter(req).typehandler(req)
|