-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathModPythonAdapter.py
More file actions
300 lines (226 loc) · 8.66 KB
/
Copy pathModPythonAdapter.py
File metadata and controls
300 lines (226 loc) · 8.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#!/usr/bin/env python
"""WebWare for Python adapter for mod_python.
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
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 'PATH_INFO' not in env:
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 'PATH_INFO' not in env:
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):
"""Type handler.
Not being used yet. Probably never be used, because the req.handler
field is read only in mod_python.
"""
self.reset(req)
debug = True
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
ext = fn[fn.rfind("."):]
if debug:
ot.write("TH: Filename: %s\n"%fn)
ot.write("TH: Extension: %s\n" % ext)
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 += 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(None, 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)