Update of /cvsroot/webware/Webware/WebKit
In directory usw-pr-cvs1:/tmp/cvs-serv6221
Added Files:
Tag: MultipleSerApp-1
WebKitRequestHandler.py RequestHandler.py
HTTPRequestHandler.py MonitorRequestHandler.py
Log Message:
Protocol handlers for multi-app AppServer
--- NEW FILE: WebKitRequestHandler.py ---
import time
from marshal import dumps, loads
from WebKit.RequestHandler import *
import string
#Need to know this value for communications
#Note that this limits the size of the dictionary we receive from the AppServer to 2,147,483,647 bytes
int_length = len(dumps(int(1)))
from WebKit.ASStreamOut import ASStreamOut
class TASASStreamOut(ASStreamOut):
def __init__(self, sock):
ASStreamOut.__init__(self)
self._socket = sock
def flush(self):
debug=0
result = ASStreamOut.flush(self)
## print self._buffer
if result: ##a true return value means we can send
reslen = len(self._buffer)
if debug: print "TASASStreamout is sending %s bytes" % reslen
sent = 0
while sent < reslen:
try:
sent = sent + self._socket.send(self._buffer[sent:sent+8192])
except socket.error, e:
if e[0]==errno.EPIPE: #broken pipe
pass
else:
print "StreamOut Error: ", e
break
self.pop(sent)
class WebKitRequestHandler(RequestHandler):
def __init__(self, server, config, name):
RequestHandler.__init__(self, server, config, name)
self._defaultAppName = self._config.get('DefaultApplication', None)
if not self._defaultAppName:
self.findDefaultApplication()
self._defaultApp = self.server.applicationInstanceByName(self._defaultAppName)
self.hosts = config.get('Hosts',None)
self.hostapps = self.mapHostsToApps()
def findDefaultApplication(self):
"""
If the config does not specify a 'DefaultApplication' entry, try to figure it out.
"""
wkApps = self.server.applicationServiceNames("WebKit")
if len(wkApps)>0:
self._defaultAppName = wkApps[0]
else:
raise "No Default Application Found"
def mapHostsToApps(self):
hostapps = {}
if not self.hosts: return None
for key,value in self.hosts.items():
hostapps[key] = self.server.applicationInstanceByName(value)
if not hostapps[key]:
del hostapps[key]
del self.hosts[key]
return hostapps
def handleRequest(self):
verbose = self.server._verbose
startTime = time.time()
if verbose:
print '%5i %s ' % (self._number, timestamp()['pretty']),
conn = self.sock
# @@ 2001-05-30 ce: Ack! Look at this hard coding. 2001-07-09 jsl: I'll give you hard coding... ;)
BUFSIZE = 8*1024
data = []
chunk = ''
while len(chunk) < int_length:
block = conn.recv(int_length)
if not block:
conn.close()
raise NotEnoughDataError, 'received only %d out of %d bytes when receiving dict_length' % (len(chunk), int_length)
chunk = chunk + block
dict_length = loads(chunk)
if type(dict_length) != type(1):
conn.close()
print
print "Error: Invalid AppServer protocol"
return 0
chunk = ''
missing = dict_length
while missing > 0:
block = conn.recv(missing)
if not block:
conn.close()
raise NotEnoughDataError, 'received only %d out of %d bytes when receiving dict' % (len(chunk), dict_length)
chunk = chunk + block
missing = dict_length - len(chunk)
dict = loads(chunk)
#if verbose: print "Comm Delay=%s" % (time.time() - dict['time'])
####Do virtual host stuff
app = self._defaultApp
if self.hostapps:
host = dict['environ'].get('HTTP_HOST', None)
print 'host is', host
if host:
app = self.hostapps.get(host, None)
if app == None:
print "Host %s is unknown, using default Application" % host
app = self._defaultApp
dict['input'] = conn.makefile("rb",8012)
if dict:
if verbose:
if dict.has_key('environ'):
requestURI = Funcs.requestURI(dict['environ'])
else:
requestURI = None
print requestURI
strmOut = TASASStreamOut(self.sock)
transaction = app.dispatchRawRequest(dict, strmOut)
strmOut.close()
try:
conn.shutdown(1)
conn.close()
except:
pass
if verbose:
duration = '%0.2f secs' % (time.time() - startTime)
duration = string.ljust(duration, 19)
print '%5i %s %s' % (self._number, duration, requestURI)
print
transaction._application=None
transaction.die()
del transaction
def restartApp(self):
"""
Not used
"""
if self.server.num_requests> 200:
print "Trying to get lock"
ReStartLock.acquire()
if self.server.num_requests> 200: #check again to make sure another thread didn't do it
print "Restarting Application"
currApp=self.server.wkApp
wkAppServer=currApp._server
newApp = wkAppServer.createApplication()
newApp._sessions = currApp._sessions
wkAppServer._app=newApp
self.server.wkApp=newApp
for i in currApp._factoryList:
currApp._factoryList.remove(i)
for i in currApp._factoryByExt.keys():
currApp._factoryByExt[i]=None
currApp._canFactory=None
wkAppServer._plugIns=[]
wkAppServer.loadPlugIns()
self.server.num_requests=0
print "Refs to old App=",sys.getrefcount(currApp)
currApp=None
ReStartLock.release()
class NotEnoughDataError(Exception):
pass
--- NEW FILE: RequestHandler.py ---
"""
Parent Class for Request Handlers
"""
from MiscUtils.Funcs import timestamp
from WebUtils import Funcs
class RequestHandler:
def __init__(self, server, config, name):
self.server = server
self._config = config
self._name = name
def name(self):
"""
This is the name given by the user to this 'Service'. It identifies this requesthandler uniquely in the AppServer.
"""
return self._name
def activate(self, sock, number):
"""
Activates the handler for processing the request.
Number is the number of the request, mostly used to identify
verbose output. Each request should be given a unique,
incremental number.
"""
self.sock = sock
self._number = number
def close(self):
"""
This function is called by AppServer.threadLoop when this RH is finished serving a request
"""
self.sock = None
self.server.returnRHInstance(self)
--- NEW FILE: HTTPRequestHandler.py ---
import time, string, urllib, mimetools
from marshal import dumps, loads
from WebKit.WebKitRequestHandler import WebKitRequestHandler
from MiscUtils.Funcs import timestamp
from StringIO import StringIO
from pprint import pprint
#Need to know this value for communications
#Note that this limits the size of the dictionary we receive from the AppServer to 2,147,483,647 bytes :)
int_length = len(dumps(int(1)))
ServerString = "Server: Webware for Python 1.0pre\r\n"
dateFormat = "%a, %d %b %Y %X GMT"
from WebKit.ASStreamOut import ASStreamOut
class HTTPStreamOut(ASStreamOut):
def __init__(self, sock):
ASStreamOut.__init__(self)
self._socket = sock
self.statusSent=0
def flush(self):
debug=0
result = ASStreamOut.flush(self)
## print self._buffer
if result: ##a true return value means we can send
reslen = len(self._buffer)
if debug:
print "TASASStreamout is sending %s bytes" % reslen
sent = 0
while sent < reslen:
sent = sent+self.handle_write(sent)
self.pop(sent)
def handle_write(self, start):
if not self.statusSent:
t = time.gmtime(time.time())
datestring = "Date: %s\r\n" % (time.strftime(dateFormat,t))
if string.lower(self._buffer[:7]) == "status:" :
statusend = string.find(self._buffer, "\n") + 1
self._buffer = "HTTP/1.0 " + self._buffer[8:statusend] + datestring + ServerString + self._buffer[statusend:]
else:
self._buffer = "HTTP/1.0 200 OK\r\n" + datestring + ServerString + self._buffer
self.statusSent=1
try:
sent = self._socket.send(self._buffer[start:start+8192])
except socket.error, e:
if e[0] == errno.EPIPE: #bad file descriptor
pass
else:
print "StreamOut Error: ", e
return sent
http_variables= ["accept-encoding", "accept-charset", "accept-language", "connection", "user-agent", "accept", "host", "referrer", "pragma", "cookie"]
class HTTPRequestHandler(WebKitRequestHandler):
def __init__(self, server, parameters, name):
self.serverName = None
WebKitRequestHandler.__init__(self, server, parameters, name)
def activate(self, sock, number):
WebKitRequestHandler.activate(self, sock, number)
verbose = self.server._verbose
if not self.serverName:
self.serverName = 'localhost'#sock.gethostname()
self.clientf = sock.makefile("r+",0)
self.active = 1
self.client_address = sock.getpeername()
self.statusSent=0
self.have_request=0
self.path=''
self.serverPort = sock.getsockname()[1] #does this work right?? or do I get the new socket??? the latter huh?
if verbose:
print "HTTP Request from ", self.client_address
def close(self):
self.reqtype=None
self.headers=None
self.path=None
self.clientf=None
self.reqdata=None
self.datalength=None
try:
self.sock.shutdown(2)
RequestHandler.close(self)
except:
pass
##print "exception in rh close"
def handleRequest(self):
verbose = self.server._verbose
startTime = time.time()
if verbose:
print '%5i %s ' % (self._number, timestamp()['pretty']),
self.requestline = self.clientf.readline()
if not self.requestline:
self.close()
return
## print self.requestline
self.request = string.split(self.requestline)
if not len(self.request)>1:
self.close()
return
self.reqtype = string.upper(self.request[0])
self.path = self.request[1]
## print self.clientf.read()
## self.close()
self.headers = mimetools.Message(self.clientf, seekable=0)
## print "self.headers=",str(self.headers)
self._strmOut = HTTPStreamOut(self.sock)
if verbose:
print "Handling HTTP Request"
self.handleHTTPRequest()
self._strmOut = None
if verbose:
duration = '%0.2f secs' % (time.time() - startTime)
duration = string.ljust(duration, 19)
print '%5i %s %s' % (self._number, duration, self.headers)
print
def handleHTTPRequest(self):
verbose = self.server._verbose
path = self.path
i = string.rfind(path, '?')
if i >= 0:
path, query = path[:i], path[i+1:]
else:
query = ''
env = {}
env['SERVER_SOFTWARE'] = "WebKit.HTTPServer" ##self.version_string()
env['SERVER_SIGNATURE'] = "Webware for Python HTTP Server"
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['SERVER_PROTOCOL'] = "HTTP/1.0" ##self.protocol_version
env['SERVER_NAME'] = self.serverName
env['HTTP_HOST'] = self.serverName
env['SERVER_PORT'] = str(self.serverPort)
env['REQUEST_METHOD'] = self.reqtype
uqrest = urllib.unquote(path)
env['PATH_INFO'] = uqrest
#env['PATH_TRANSLATED'] = self.translate_path(uqrest)
env['SCRIPT_NAME'] = ''
env['QUERY_STRING'] = query
host, port = self.client_address
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = host
env['REMOTE_PORT'] = str(port)
# AUTH_TYPE
# REMOTE_USER
# REMOTE_IDENT
if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader
## length = self.headers.getheader('Content-Length')
## if length:
## print "*******Length=",length
## env['CONTENT_LENGTH'] = length
## input = self.clientf
## else:
## input = StringIO('')
input = self.clientf
##Or maybe not
## fix handling of cookies, the message class names them "COOKIE", "COOKIE2", etc.
##this must be fixed in the regular request handler????
## cookiestring = ''
## for name, value in self.headers.items():
#### print "Checking %s=%s" %(name,value)
## if string.lower(name)[:6] == "cookie":
## if len(name) > 6 and not name[6:] in string.digits:
## continue
## cookiestring = cookiestring + value + "; "
## del self.headers[name]
## if cookiestring:
## self.headers['cookie']=cookiestring
for name, value in self.headers.items():
transformed=string.upper(string.replace(name, '-', '_'))
if name in http_variables:
env['HTTP_' + transformed] = value
## elif: transformed[:6]== "COOKIE":
## env['HTTP_' + transformed] = value
else:
env[transformed] = value
dict = {
'format': 'CGI',
'time': time.time(),
'environ': env,
'input': input
}
## print __file__
## pprint(dict)
####Do virtual host stuff
app = self._defaultApp
if self.hostapps:
host = dict['environ'].get('HTTP_HOST', None)
if host:
if string.find(host,':'):
host = host[:string.find(host,':')]
app = self.hostapps.get(host, None)
if app == None:
if verbose: print "Host %s is unknown, using default Application" % host
app = self._defaultApp
transaction = app.dispatchRawRequest(dict, self._strmOut)
self._strmOut.flush()
self._strmOut.close()
transaction._application=None
transaction.die()
del transaction
## def OriginalhandleRequest(self):
## verbose = self.server._verbose
## startTime = time.time()
## if verbose:
## print '%5i %s ' % (self._number, timestamp()['pretty']),
## if not self.handle_read():
## return
## if verbose:
## print 'received %d bytes' % len(self.reqdata)
## self.rfile = StringIO(self.reqdata[string.find(self.reqdata,"\n")+1:])
## self.headers = mimetools.Message(self.rfile)
## print "self.headers=",str(self.headers)
## self._strmOut = HTTPStreamOut(self.sock)
## if verbose:
## print "Handling HTTP Request"
## self.handleHTTPRequest()
## self._strmOut = None
## if verbose:
## duration = '%0.2f secs' % (time.time() - startTime)
## duration = string.ljust(duration, 19)
## print '%5i %s %s' % (self._number, duration, self.headers)
## print
## def handle_read(self):
## have_request=haveheader=0
## request_data=[]
## while not have_request:
## if not haveheader:
## data = string.strip(self.clientf.readline())
## if data:
## request_data.append(data+"\r\n")
## continue
## if len(request_data) == 0: #if we get here and have received nothing, bail
## self.close()
## return 0
## haveheader = 1
## request_data.append("\r\n") #replace the blank eol stripped by readline
## try:
## self.reqtype = string.split(request_data[0])[0]
## except:
## self.close()
## self.reqdata = string.join(request_data,"")
## have_request = 1
## self.path = string.split(request_data[0])[1]
#### if string.lower(self.reqtype) == "get":
#### self.reqdata = string.join(request_data,"")
#### have_request = 1
#### self.path = string.split(request_data[0])[1]
#### continue
#### elif string.lower(self.reqtype) == "post":
###### print "Post Request"
#### for i in request_data:
#### if string.lower(string.split(i,":")[0]) =="content-length":
#### self.datalength = int(string.split(i)[1])
#### break
#### self.path = string.split(request_data[0])[1]
#### self.reqdata=string.join(request_data,"")
#### request_data = []
#### continue
#### else:
#### print "Unrecognized Request Type"
#### Old Don't use
#### else:
#### data = self.sock.recv(self.datalength)
#### print "received %s bytes" % len(data)
#### request_data.append(data)
#### self.datalength = self.datalength - len(data)
#### if self.datalength > 0:
#### continue
#### self.inputdata = string.join(request_data,"")
## self.inputdata = self.clientf
## have_request = 1
#### self.sock.shutdown(0)
## print self.reqdata
## return 1
--- NEW FILE: MonitorRequestHandler.py ---
from WebKit.RequestHandler import RequestHandler
from marshal import dumps, loads
import time
#Need to know this value for communications
#Note that this limits the size of the dictionary we receive from the AppServer to 2,147,483,647 bytes
int_length = len(dumps(int(1)))
class MonitorRequestHandler(RequestHandler):
def handleRequest(self):
verbose = self.server._verbose
startTime = time.time()
if verbose:
print 'BEGIN REQUEST'
print time.asctime(time.localtime(startTime))
conn = self.sock
if verbose:
print 'receiving request from', conn
BUFSIZE = 8*1024
chunk = ''
while len(chunk) < int_length:
chunk = chunk + conn.recv(int_length)
dict_length = loads(chunk)
if type(dict_length) != type(1):
conn.close()
print "Error: Invalid AppServer protocol"
return 0
chunk = ''
missing = dict_length
while missing > 0:
chunk = chunk + conn.recv(missing)
missing = dict_length - len(chunk)
dict = loads(chunk)
if dict['format'] == "STATUS":
conn.send(str(self.server._reqCount))
if dict['format'] == 'QUIT':
conn.send("OK")
conn.close()
self.server.initiateShutdown()
|