def __call__(self, environ, start_response): """The WSGI application callable""" verbose = self._verbose requestDict = dict(environ=environ) requestID = self._requestID self._requestID = requestID + 1 startTime = time() requestTime = startTime requestDict['requestID'] = requestID requestDict['time'] = requestTime requestDict['format'] = 'CGI' if verbose: uri = requestURI(environ) if not self._silentURIs or not self._silentURIs.search(uri): requestDict['verbose'] = True requestTime = localtime(requestTime)[:6] fmt = '{:5d} {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d} {}' print(fmt.format(requestID, *requestTime, uri)) requestDict['input'] = environ['wsgi.input'] streamOut = WSGIStreamOut(start_response, bufferSize=self._responseBufferSize, useWrite=self._wsgiWrite, encoding=self._outputEncoding) transaction = self.dispatchRawRequest(requestDict, streamOut) try: streamOut.close() aborted = False except ConnectionAbortedError: aborted = True if verbose and requestDict.get('verbose'): endTime = time() duration = round((endTime - startTime) * 1000) if aborted: error = '* connection aborted *' else: error = requestURI(environ) fmt = '{:5d} {:16.0f} ms {}\n' print(fmt.format(requestID, duration, error)) transaction._application = None transaction.die() del transaction return streamOut.iterable()
def endRequest(self, error=None): """Track end of a raw request. Subclasses can use and override this method. """ if self._verbose: requestDict = self._requestDict if requestDict.get('verbose'): requestID = requestDict['requestID'] duration = round((time() - requestDict['time']) * 1000) if not error: env = requestDict.get('environ') error = requestURI(env) if env else '-' print '%5d %14.0f msec %s\n' % (requestID, duration, error)
def endRequest(self, error=None): """Track end of a raw request. Subclasses can use and override this method. """ if self._verbose: requestDict = self._requestDict if requestDict.get('verbose'): requestID = requestDict['requestID'] duration = round((time() - requestDict['time'])*1000) if not error: env = requestDict.get('environ') error = requestURI(env) if env else '-' print '%5d %14.0f msec %s\n' % ( requestID, duration, error)
def handleRequest(self): """Handle a request. Actually performs the request, creating the environment and calling self.doTransaction(env, input) to perform the response. """ self.server_version = 'Webware/' + self._server.version() env = {} if self.headers.has_key('Content-Type'): env['CONTENT_TYPE'] = self.headers['Content-Type'] del self.headers['Content-Type'] if self.headers.has_key('Content-Length'): env['CONTENT_LENGTH'] = self.headers['Content-Length'] del self.headers['Content-Length'] key = 'If-Modified-Since' if self.headers.has_key(key): env[key] = self.headers[key] del self.headers[key] 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['SCRIPT_NAME'] = '' env['PATH'] = os.getenv('PATH', '') env['PATH_INFO'] = env['REQUEST_URI'] env['SERVER_ADDR'], env['SERVER_PORT'] = map(str, self._serverAddress) env['SERVER_SOFTWARE'] = self.server_version env['SERVER_PROTOCOL'] = self.protocol_version env['GATEWAY_INTERFACE'] = 'CGI/1.1' if self._server._verbose: uri = requestURI(env) startTime = time.time() sys.stdout.write('%5i %s %s\n' % (self._requestID, timestamp()['pretty'], uri)) self.doTransaction(env, self.rfile) if self._server._verbose: duration = ('%0.2f secs' % (time.time() - startTime)).ljust(19) sys.stdout.write('%5i %s %s\n\n' % (self._requestID, duration, uri))
def handleRequest(self): """Handle request. Creates the request dictionary, and creates a `TASStreamOut` object for the response, then calls `Application.dispatchRawRequest`, which does the rest of the work (here we just clean up after). """ verbose = self._server._verbose self._startTime = time.time() requestDict = self.receiveDict() if not requestDict: return if verbose: uri = requestDict.has_key('environ') \ and requestURI(requestDict['environ']) or '-' sys.stdout.write('%5i %s %s\n' % (self._requestID, timestamp()['pretty'], uri)) requestDict['input'] = self.makeInput() requestDict['requestID'] = self._requestID streamOut = TASStreamOut(self._sock, bufferSize=self._server._responseBufferSize) transaction = self._server._app.dispatchRawRequest(requestDict, streamOut) try: streamOut.close() aborted = False except ConnectionAbortedError: aborted = True try: self._sock.shutdown(1) self._sock.close() except Exception: pass if verbose: duration = ('%0.2f secs' % (time.time() - self._startTime)).ljust(19) sys.stdout.write('%5i %s %s\n\n' % (self._requestID, duration, aborted and '*connection aborted*' or uri)) transaction._application = None transaction.die() del transaction
def startRequest(self, requestDict=None): """Track start of a raw request. Subclasses can use and override this method. """ requestDict = requestDict or {} requestID = self._requestID requestTime = requestDict.get('time') or time() requestDict['requestID'] = requestID requestDict['time'] = requestTime # The request object is stored for tracking/debugging purposes. self._requestDict = requestDict if self._verbose: env = requestDict.get('environ') uri = requestURI(env) if env else '-' if not self._silentURIs or not self._silentURIs.search(uri): requestDict['verbose'] = True requestTime = localtime(requestTime)[:6] print '%5d %4d-%02d-%02d %02d:%02d:%02d %s' % ( (requestID,) + requestTime + (uri,))
def writeContent(self): app = self.application() server = app.server() request = self.request() field = request.field myRequestID = request.requestID() wr = self.writeln try: threadHandler = server._threadHandler abortRequest = server._canAbortRequest and server.abortRequest except AttributeError: threadHandler = {} abortRequest = None maxRequestTime = server.setting('MaxRequestTime', 0) or 0 try: max_duration = int(field('duration')) except (KeyError, ValueError): max_duration = int(maxRequestTime/2) or 60 wr('<h2>Current thread status</h2>', '<p>Automatic cancelation of long-running requests is controlled by' ' the <tt>AppServer.config</tt> setting <tt>MaxRequestTime</tt>.</p>') if maxRequestTime: if abortRequest: wr('<p>Currently, this is set to <b>%d</b> seconds.</p>' % maxRequestTime) else: wr('<p>Currently, this is set to %d seconds, but inactive.</p>' % maxRequestTime) else: wr('<p>Currently, this setting is disabled.</p>') wr('<form action="ThreadControl" method="post">', '<p>') if abortRequest: wr('<input name="cancel_all" type="submit"' ' value="Cancel all requests below">') wr('<input name="cancel_selected" type="submit"' ' value="Cancel all selected requests">') else: wr('<p>You need Python 2.3 with <code>ctypes</code> or a' ' newer Python version to enable cancelation of threads.</p>') wr('<input name="refresh_view" type="submit"' ' value="Refresh view">', '</p>') if abortRequest: wr('<p><input name="cancel_long" type="submit"' ' value="Cancel all long-running requests">' ' (longer than <input type="text" name="duration" value="%d"' ' size="6" maxlength="12" style="text-align: right">' ' seconds)</p>' % max_duration) wr('<p>You can <a href="Sleep" target="_blank">create a long-running' ' request</a> in a separate browser window for testing.</p>' '<p>(Your web browser may get stuck if it is waiting for more' ' than one of these.)</p>') if field('cancel_selected', None): killIDs = field('selectedIDs', None) or [] elif field('cancel_all', None): killIDs = field('allIDs', '').split(',') elif field('cancel_long', None): killIDs = field('longIDs', None) or [] else: killIDs = [] if not isinstance(killIDs, list): killIDs = [killIDs] try: killIDs = map(int, killIDs) except ValueError: killIDs = [] killedIDs = [] errorIDs = [] activeIDs = [] for h in threadHandler.values(): try: activeIDs.append(h._requestID) except AttributeError: continue for requestID in killIDs: if (not requestID or requestID == myRequestID or requestID not in activeIDs): continue if abortRequest: try: killed = abortRequest(requestID) == 1 except Exception: killed = 0 else: killed = 0 if killed: killedIDs.append(requestID) else: errorIDs.append(requestID) if killedIDs: msg = (len(killedIDs) > 1 and 'The following requests have been canceled: %s' % ', '.join(map(str, killedIDs)) or 'Request %d has been canceled.' % killedIDs[0]) wr('<p style="color:green">%s</p>' % msg) tries = 100 while tries: pendingIDs = [] for h in threadHandler.values(): try: requestID = h._requestID if requestID in killedIDs: pendingIDs.append(requestID) except AttributeError: continue if pendingIDs: sleep(0.125) tries -= 1 else: pendingIDs = [] tries = 0 if pendingIDs: msg = (len(pendingIDs) > 1 and 'The following of these are still pending: %s' % ', '.join(map(str, pendingIDs)) or 'The request is still pending.') wr('<p>%s</p><p>You can' ' <a href="ThreadControl">refresh the view<a>' ' to verify cancelation.</p>' % msg) if errorIDs: msg = (len(errorIDs) > 1 and 'The following requests could not be canceled: %s' % ', '.join(map(str, errorIDs)) or 'Request %d could not be canceled.' % errorIDs[0]) wr('<p style="color:red">%s</p>' % msg) curTime = time() activeThreads = [] try: threadCount = server._threadCount except AttributeError: threadCount = 0 for t, h in threadHandler.items(): try: name = t.getName() requestID = h._requestID requestDict = h._requestDict if requestID != requestDict['requestID']: raise AttributeError startTime = requestDict.get('time') env = requestDict.get('environ') client = env and (env.get('REMOTE_NAME') or env.get('REMOTE_ADDR')) or None uri = env and requestURI(env) or None activeThreads.append((name, requestID, startTime, curTime - startTime, client, uri)) except AttributeError: continue if activeThreads: headings = ('Thread name', 'Request ID', 'Start time', 'Duration', 'Client', 'Request URI') sort = field('sort', None) wr('<table class="NiceTable"><tr>') column = 0 sort_column = 1 sort = field('sort', None) for heading in headings: sort_key = heading.lower().replace(' ', '_') if sort_key == sort: sort_column = column wr('<th><a href="ThreadControl?sort=%s">%s</a></th>' % (sort_key, heading)) column += 1 if abortRequest: wr('<th>Cancel</th>') wr('</tr>') if sort_column: def key(t): return t[sort_column], t[1] else: def key(t): try: n = int(t[0].rsplit('-', 1)[-1]) except ValueError: n = 0 return n, t[0] activeThreads.sort(key=key) else: wr('<p>Could not determine the active threads.</p>') longIDs = [] for (name, requestID, startTime, duration, client, uri) in activeThreads: if startTime: startTime = strtime(startTime) duration = int(duration + 0.5) if duration > 0: if duration > max_duration: duration = '<b>%s</b>' % duration if requestID: longIDs.append(requestID) duration = '%s s' % duration else: duration = int(1000*(duration) + 0.5) duration = '%s ms' % duration else: duration = startTime = '-' if abortRequest and requestID and requestID != myRequestID: checkbox = ('<input type="hidden" name="allIDs" value="%d">' '<input type="checkbox" name="selectedIDs" value="%d">' % (requestID, requestID)) else: checkbox = ' ' if not requestID: requestID = '-' elif requestID == myRequestID: requestID = '<b>%s</b>' % requestID if not client: client = '-' if uri: uri = uri.replace('/', '/' + '<wbr>') else: uri = '-' wr('<tr><td align="right">', name, '</td><td align="right">', requestID, '</td><td>', startTime, '</td><td align="right">', duration, '</td><td>', client, '</td><td>', uri, '</td>') if abortRequest: wr('<td align="center">', checkbox, '</td>') wr('</tr>') if activeThreads: wr('</table>') if abortRequest: longIDs = ','.join(map(str, longIDs)) wr('<input type="hidden" name="longIDs" value="%s">' % longIDs) wr('</form>') if threadCount > len(activeThreads): wr('<p>Idle threads waiting for requests: <b>%d</b></p>' % (threadCount - len(activeThreads))) wr('<p>Current time: %s</p>' % strtime(curTime))
def __init__(self, dict={}): ## import pprint ## pprint.pprint(dict) Request.__init__(self) self._parents = [] if dict: # Dictionaries come in from web server adapters like the CGIAdapter assert dict['format'] == 'CGI' self._time = dict['time'] self._environ = dict['environ'] self._input = dict['input'] self._fields = FieldStorage.FieldStorage(self._input, environ=self._environ, keep_blank_values=1, strict_parsing=0) self._fields.parse_qs() self._cookies = Cookie() if self._environ.has_key('HTTP_COOKIE'): # Protect the loading of cookies with an exception handler, because some cookies # from IE are known to break the cookie module. try: self._cookies.load(self._environ['HTTP_COOKIE']) except: traceback.print_exc(file=sys.stderr) else: # If there's no dictionary, we pretend we're a CGI script and see what happens... import time self._time = time.time() self._environ = os.environ.copy() self._input = None self._fields = cgi.FieldStorage(keep_blank_values=1) self._cookies = Cookie() # Debugging if 0: f = open('env.text', 'a') save = sys.stdout sys.stdout = f print '>> env for request:' keys = self._environ.keys() keys.sort() for key in keys: print '%s: %s' % (repr(key), repr(self._environ[key])) print sys.stdout = save f.close() # Fix up environ if it doesn't look right. # Fix #1: No PATH_INFO # This can happen when there is no extra path info past the adapter. # e.g., http://localhost/WebKit.cgi if not self._environ.has_key('PATH_INFO'): self._environ['PATH_INFO'] = '' # Fix #2: No REQUEST_URI # REQUEST_URI isn't actually part of the CGI standard and some # web servers like IIS don't set it (as of 8/22/2000). if not self._environ.has_key('REQUEST_URI'): self._environ['REQUEST_URI'] = requestURI(self._environ) self._adapterName = self._environ.get('SCRIPT_NAME', '') # We use the cgi module to get the fields, but then change them into an ordinary dictionary of values try: keys = self._fields.keys() except TypeError: # This can happen if, for example, the request is an XML-RPC request, not # a regular POST from an HTML form. In that case we just create an empty # set of fields. keys = [] dict = {} for key in keys: value = self._fields[key] if type(value) is not ListType: if value.filename: if debug: print "Uploaded File Found" else: value = value.value # i.e., if we don't have a list, we have one of those cgi.MiniFieldStorage objects. Get it's value. else: value = map(lambda miniFieldStorage: miniFieldStorage.value, value) # extract those .value's dict[key] = value self._fieldStorage = self._fields self._fields = dict self._pathInfo = None # We use Tim O'Malley's Cookie class to get the cookies, but then change them into an ordinary dictionary of values dict = {} for key in self._cookies.keys(): dict[key] = self._cookies[key].value self._cookies = dict self._transaction = None self._serverRootPath = "" self._extraURLPath = "" # try to get automatic path session # if UseAutomaticPathSessions is enabled in Application.config # Application.py redirects the browser to a url with SID in path # http://gandalf/a/_SID_=2001080221301877755/Examples/ # _SID_ is extracted and removed from path self._pathSession = None if self._environ['PATH_INFO'][1:6] == '_SID_': self._pathSession = self._environ['PATH_INFO'][7:].split('/', 1)[0] self._cookies['_SID_'] = self._pathSession sidstring = '_SID_=' + self._pathSession + '/' self._environ['REQUEST_URI'] = self._environ[ 'REQUEST_URI'].replace(sidstring, '') self._environ['PATH_INFO'] = self._environ['PATH_INFO'].replace( sidstring, '') if self._environ.has_key('PATH_TRANSLATED'): self._environ['PATH_TRANSLATED'] = self._environ[ 'PATH_TRANSLATED'].replace(sidstring, '') assert (not self._environ.has_key('WK_URI')) # obsolete? self._sessionExpired = 0 # Save the original urlPath. self._originalURLPath = self.urlPath() if debug: print "Done setting up request, found keys %s" % repr( self._fields.keys())
def writeContent(self): app = self.application() server = app.server() request = self.request() field = request.field myRequestID = request.requestID() wr = self.writeln threadHandler = server._threadHandler abortRequest = server.abortRequest maxRequestTime = server.setting('MaxRequestTime', 0) or 0 try: max_duration = int(field('duration')) except (KeyError, ValueError): max_duration = int(maxRequestTime/2) or 60 wr('<h2>Current thread status</h2>', '<p>Automatic cancelation of long-running requests is controlled by' ' the <code>AppServer.config</code> setting <code>MaxRequestTime</code>.</p>') if maxRequestTime: wr('<p>Currently, this is set to <b>%d</b> seconds.</p>' % maxRequestTime) else: wr('<p>Currently, this setting is disabled.</p>') wr('<form action="ThreadControl" method="post">', '<p>') wr('<input name="cancel_all" type="submit"' ' value="Cancel all requests below">') wr('<input name="cancel_selected" type="submit"' ' value="Cancel all selected requests">') wr('<input name="refresh_view" type="submit"' ' value="Refresh view">', '</p>') wr('<p><input name="cancel_long" type="submit"' ' value="Cancel all long-running requests">' ' (longer than <input type="text" name="duration" value="%d"' ' size="6" maxlength="12" style="text-align: right">' ' seconds)</p>' % max_duration) wr('<p>You can <a href="Sleep" target="_blank">create a long-running' ' request</a> in a separate browser window for testing.</p>' '<p>(Your web browser may get stuck if it is waiting for more' ' than one of these.)</p>') if field('cancel_selected', None): killIDs = field('selectedIDs', None) or [] elif field('cancel_all', None): killIDs = field('allIDs', '').split(',') elif field('cancel_long', None): killIDs = field('longIDs', None) or [] else: killIDs = [] if not isinstance(killIDs, list): killIDs = [killIDs] try: killIDs = map(int, killIDs) except ValueError: killIDs = [] killedIDs = [] errorIDs = [] activeIDs = [] for h in threadHandler.values(): try: activeIDs.append(h._requestID) except AttributeError: continue for requestID in killIDs: if (not requestID or requestID == myRequestID or requestID not in activeIDs): continue try: killed = abortRequest(requestID) == 1 except Exception: killed = 0 if killed: killedIDs.append(requestID) else: errorIDs.append(requestID) if killedIDs: msg = (len(killedIDs) > 1 and 'The following requests have been canceled: %s' % ', '.join(map(str, killedIDs)) or 'Request %d has been canceled.' % killedIDs[0]) wr('<p style="color:green">%s</p>' % msg) tries = 100 while tries: pendingIDs = [] for h in threadHandler.values(): try: requestID = h._requestID if requestID in killedIDs: pendingIDs.append(requestID) except AttributeError: continue if pendingIDs: sleep(0.125) tries -= 1 else: pendingIDs = [] tries = 0 if pendingIDs: msg = (len(pendingIDs) > 1 and 'The following of these are still pending: %s' % ', '.join(map(str, pendingIDs)) or 'The request is still pending.') wr('<p>%s</p><p>You can' ' <a href="ThreadControl">refresh the view<a>' ' to verify cancelation.</p>' % msg) if errorIDs: msg = (len(errorIDs) > 1 and 'The following requests could not be canceled: %s' % ', '.join(map(str, errorIDs)) or 'Request %d could not be canceled.' % errorIDs[0]) wr('<p style="color:red">%s</p>' % msg) curTime = time() activeThreads = [] try: threadCount = server._threadCount except AttributeError: threadCount = 0 for t, h in threadHandler.items(): try: name = t.getName() requestID = h._requestID requestDict = h._requestDict if requestID != requestDict['requestID']: raise AttributeError startTime = requestDict.get('time') env = requestDict.get('environ') client = (env.get('REMOTE_NAME') or env.get('REMOTE_ADDR')) if env else None uri = requestURI(env) if env else None activeThreads.append((name, requestID, startTime, curTime - startTime, client, uri)) except AttributeError: continue if activeThreads: headings = ('Thread name', 'Request ID', 'Start time', 'Duration', 'Client', 'Request URI') sort = field('sort', None) wr('<table class="NiceTable"><tr>') column = 0 sort_column = 1 sort = field('sort', None) for heading in headings: sort_key = heading.lower().replace(' ', '_') if sort_key == sort: sort_column = column wr('<th><a href="ThreadControl?sort=%s">%s</a></th>' % (sort_key, heading)) column += 1 wr('<th>Cancel</th>') wr('</tr>') if sort_column: def key(t): return t[sort_column], t[1] else: def key(t): try: n = int(t[0].rsplit('-', 1)[-1]) except ValueError: n = 0 return n, t[0] activeThreads.sort(key=key) else: wr('<p>Could not determine the active threads.</p>') longIDs = [] for (name, requestID, startTime, duration, client, uri) in activeThreads: if startTime: startTime = strtime(startTime) duration = int(duration + 0.5) if duration > 0: if duration > max_duration: duration = '<b>%s</b>' % duration if requestID: longIDs.append(requestID) duration = '%s s' % duration else: duration = int(1000*(duration) + 0.5) duration = '%s ms' % duration else: duration = startTime = '-' if requestID and requestID != myRequestID: checkbox = ('<input type="hidden" name="allIDs" value="%d">' '<input type="checkbox" name="selectedIDs" value="%d">' % (requestID, requestID)) else: checkbox = ' ' if not requestID: requestID = '-' elif requestID == myRequestID: requestID = '<b>%s</b>' % requestID if not client: client = '-' if uri: uri = uri.replace('/', '/' + '<wbr>') else: uri = '-' wr('<tr><td style="text-align:right">', name, '</td><td style="text-align:right">', requestID, '</td><td>', startTime, '</td><td style="text-align:right">', duration, '</td><td>', client, '</td><td>', uri, '</td>') wr('<td style="text-align:center">', checkbox, '</td>') wr('</tr>') if activeThreads: wr('</table>') longIDs = ','.join(map(str, longIDs)) wr('<input type="hidden" name="longIDs" value="%s">' % longIDs) wr('</form>') if threadCount > len(activeThreads): wr('<p>Idle threads waiting for requests: <b>%d</b></p>' % (threadCount - len(activeThreads))) wr('<p>Current time: %s</p>' % strtime(curTime))