def _finish(self): self.channel.reply_code = self.status DebugLogger.log('A', id(self.channel), '%d %d' % ( self.status, self.stdout.length)) t = self._tempfile if t is not None: self.stdout.write((file_close_producer(t), 0)) self._tempfile = None self.channel.sendStreamTerminator(FCGI_STDOUT) self.channel.sendEndRecord() self.stdout.close() self.stderr.close() if not self.channel.closed: self.channel.push_with_producer(LoggingProducer(self.channel, self.stdout.length, 'log_request'), 0) if self._shutdownRequested(): config.ZSERVER_EXIT_CODE = self._shutdown_flag self.channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: self.channel.push(None, 0) Wakeup() self.channel = None
def close(self): if not self._channel.closed: data = self._data.getvalue() l = len(data) DebugLogger.log('A', id(self._channel), '%s %s' % (self._channel.reply_code, l)) self._channel.push('%010d%s%010d' % (l, data, 0), 0) self._channel.push( LoggingProducer(self._channel, l, 'log_request'), 0) self._channel.push( CallbackProducer(lambda t= ('E', id(self._channel)): DebugLogger(*t)), 0) if self._shutdown: try: r = self._shutdown[0] except: r = 0 config.ZSERVER_EXIT_CODE = r self._channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: self._channel.push(None, 0) Wakeup() self._data = None self._channel = None
def handle_request(self, request): self.hits.increment() DebugLogger.log('B', id(request), '%s %s' % (request.command.upper(), request.uri)) size = get_header(CONTENT_LENGTH, request.header) if size and size != '0': size = int(size) zhttp_collector(self, request, size) else: sin = StringIO() self.continue_request(sin, request)
def log_request(self, bytes): DebugLogger.log('E', id(self)) if 'HTTP_USER_AGENT' in self.env: user_agent = self.env['HTTP_USER_AGENT'] else: user_agent = '' if 'HTTP_REFERER' in self.env: referer = self.env['HTTP_REFERER'] else: referer = '' if 'PATH_INFO' in self.env: path = self.env['PATH_INFO'] else: path = '' if 'REQUEST_METHOD' in self.env: method = self.env['REQUEST_METHOD'] else: method = "GET" user_name = '-' if 'HTTP_AUTHORIZATION' in self.env: http_authorization = self.env['HTTP_AUTHORIZATION'] if string.lower(http_authorization[:6]) == 'basic ': try: decoded = base64.decodestring(http_authorization[6:]) except base64.binascii.Error: decoded = '' t = string.split(decoded, ':', 1) if len(t) >= 2: user_name = t[0] if self.addr: self.server.logger.log( self.addr[0], '%s - %s [%s] "%s %s" %d %d "%s" "%s"' % (self.addr[1], user_name, time.strftime('%d/%b/%Y:%H:%M:%S ', time.localtime( time.time())) + tz_for_log, method, path, self.reply_code, bytes, referer, user_agent)) else: self.server.logger.log( '127.0.0.1 ', '- %s [%s] "%s %s" %d %d "%s" "%s"' % (user_name, time.strftime('%d/%b/%Y:%H:%M:%S ', time.localtime( time.time())) + tz_for_log, method, path, self.reply_code, bytes, referer, user_agent))
def continue_request(self, sin, request): "continue handling request now that we have the stdin" s = get_header(CONTENT_LENGTH, request.header) if s: s = int(s) else: s = 0 DebugLogger.log('I', id(request), s) env = self.get_environment(request) zresponse = make_response(request, env) if self._force_connection_close: zresponse._http_connection = 'close' zrequest = HTTPRequest(sin, env, zresponse) request.channel.current_request = None request.channel.queue.append((self.module_name, zrequest, zresponse)) request.channel.work()
def found_terminator(self): if self.size is None: # read the next size header # and prepare to read env or stdin self.data.seek(0) self.size = string.atoi(self.data.read()) self.set_terminator(self.size) if self.size == 0: DebugLogger.log('I', id(self), 0) self.set_terminator('\r\n') self.data = StringIO() self.send_response() elif self.size > 1048576: self.data = TemporaryFile('w+b') else: self.data = StringIO() elif not self.env: # read env self.size = None self.data.seek(0) buff = self.data.read() for line in string.split(buff, '\000'): try: k, v = string.split(line, '=', 1) self.env[k] = v except: pass # Hack around broken IIS PATH_INFO # maybe, this should go in ZPublisher... if 'SERVER_SOFTWARE' in self.env and \ string.find(self.env['SERVER_SOFTWARE'], 'Microsoft-IIS') != -1: script = [ _f for _f in string.split( string.strip(self.env['SCRIPT_NAME']), '/') if _f ] path = [ _f for _f in string.split( string.strip(self.env['PATH_INFO']), '/') if _f ] self.env['PATH_INFO'] = '/' + string.join( path[len(script):], '/') self.data = StringIO() DebugLogger.log( 'B', id(self), '%s %s' % (self.env['REQUEST_METHOD'], self.env.get('PATH_INFO', '/'))) # now read the next size header self.set_terminator(10) else: DebugLogger.log('I', id(self), self.terminator) # we're done, we've got both env and stdin self.set_terminator('\r\n') self.data.seek(0) self.send_response()
def continue_request(self, sin, request): "continue handling request now that we have the stdin" s=get_header(CONTENT_LENGTH, request.header) if s: s=int(s) else: s=0 DebugLogger.log('I', id(request), s) env=self.get_environment(request) path = request.uri.split('?', 1)[0] env['PATH_INFO'] += path # why not do the above in self.get_environment(request)? env['stdin'] = sin env['ZServer.medusa.http_server.http_request'] = request try: channel_pipe = ChannelPipe(request) view = self.get_view(env) # mini WSGI server: result = view(env, channel_pipe.start_response) for part in result: # XXX: This needs improvement. Basically, we block ZServer # iterating through the answer. If it's long, The ZServer will # block while the channel gobbles up all the result in memory. # Only after all the result has been absorbed will we return # control to the medusa thread to actually serve the view. # Instead, we should channel.push() a producer for the answer # that iterates the result whenever the medusa thread is ready # to push more content. # # For short content, like debug views, this is ok, but if a # view tried, for example, to stream a huge file, this would # be bad. channel_pipe.write(part) channel_pipe.close() request.channel.current_request=None except: log.exception("Failure calling view for %r with env:\n%s\n" % (path, env)) raise
def continue_request(self, sin, request): "continue handling request now that we have the stdin" s = get_header(CONTENT_LENGTH, request.header) if s: s = int(s) else: s = 0 DebugLogger.log('I', id(request), s) env = self.get_environment(request) version = request.version if version == '1.0' and is_proxying_match(request.request): # a request that was made as if this zope was an http 1.0 proxy. # that means we have to use some slightly different http # headers to manage persistent connections. connection_re = proxying_connection_re else: # a normal http request connection_re = CONNECTION env['http_connection'] = get_header(connection_re, request.header).lower() env['server_version'] = request.channel.server.SERVER_IDENT env['wsgi.output'] = ChannelPipe(request) env['wsgi.input'] = sin env['wsgi.errors'] = sys.stderr env['wsgi.version'] = (1, 0) env['wsgi.multithread'] = True env['wsgi.multiprocess'] = True env['wsgi.run_once'] = True env['wsgi.url_scheme'] = env['SERVER_PROTOCOL'].split('/')[0] request.channel.current_request = None request.channel.queue.append( ('Zope2WSGI', env, env['wsgi.output'].start_response)) request.channel.work()
def continue_request(self, sin, request): "continue handling request now that we have the stdin" s = get_header(CONTENT_LENGTH, request.header) if s: s = int(s) else: s = 0 DebugLogger.log('I', id(request), s) env = self.get_environment(request) version = request.version if version == '1.0' and is_proxying_match(request.request): # a request that was made as if this zope was an http 1.0 proxy. # that means we have to use some slightly different http # headers to manage persistent connections. connection_re = proxying_connection_re else: # a normal http request connection_re = CONNECTION env['http_connection'] = get_header(connection_re, request.header).lower() env['server_version'] = request.channel.server.SERVER_IDENT env['wsgi.output'] = ChannelPipe(request) env['wsgi.input'] = sin env['wsgi.errors'] = sys.stderr env['wsgi.version'] = (1, 0) env['wsgi.multithread'] = True env['wsgi.multiprocess'] = True env['wsgi.run_once'] = True env['wsgi.url_scheme'] = env['SERVER_PROTOCOL'].split('/')[0] request.channel.current_request = None request.channel.queue.append(('Zope2WSGI', env, env['wsgi.output'].start_response)) request.channel.work()
def found_terminator(self): # Are we starting a new record? If so, data is the header. if not self.curRec: self.curRec = FCGIRecord(self.data.getvalue()) if self.curRec.needMore(): self.set_terminator(self.curRec.needMore()) self.data = StringIO() return rec = self.curRec # If waiting for record content, give it to the record. if rec.needContent(): rec.parseContent(self.data.getvalue()) if rec.needMore(): self.set_terminator(rec.needMore()) self.data = StringIO() return if rec.needPadding(): rec.gotPadding() # If we get this far without returning, we've got the whole # record. Figure out what to do with it. if rec.recType in FCGI_ManagementTypes: # Apache mod_fastcgi doesn't send these, but others may self.handleManagementTypes(rec) elif rec.reqId == 0: # It's a management record of unknown type. # Complain about it... r2 = FCGIRecord() r2.recType = FCGI_UNKNOWN_TYPE r2.unknownType = rec.recType self.push(r2.getRecordAsString(), 0) # Since we don't actually have to do anything to ignore the # following conditions, they have been commented out and have # been left in the code for documentation purposes. # Ignore requests that aren't active # elif rec.reqId != self.requestId and rec.recType != FCGI_BEGIN_REQUEST: # pass # # If we're already doing a request, ignore further BEGIN_REQUESTs # elif rec.recType == FCGI_BEGIN_REQUEST and self.requestId != 0: # pass # Begin a new request elif rec.recType == FCGI_BEGIN_REQUEST and self.requestId == 0: self.requestId = rec.reqId if rec.role == FCGI_AUTHORIZER: self.remainingRecs = 1 elif rec.role == FCGI_RESPONDER: self.remainingRecs = 2 elif rec.role == FCGI_FILTER: self.remainingRecs = 3 # Read some name-value pairs (the CGI environment) elif rec.recType == FCGI_PARAMS: if rec.contentLength == 0: # end of the stream if self.env.has_key('REQUEST_METHOD'): method = self.env['REQUEST_METHOD'] else: method = 'GET' if self.env.has_key('PATH_INFO'): path = self.env['PATH_INFO'] else: path = '' DebugLogger.log('B', id(self), '%s %s' % (method, path)) self.remainingRecs = self.remainingRecs - 1 self.content_length = string.atoi( self.env.get('CONTENT_LENGTH', '0')) else: self.env.update(rec.values) # read some stdin data elif rec.recType == FCGI_STDIN: if rec.contentLength == 0: # end of the stream self.remainingRecs = self.remainingRecs - 1 else: # see if stdin is getting too big, and # replace it with a tempfile if necessary if len(rec.content) + self.stdin.tell() > 1048576 and \ not self.using_temp_stdin: t = TemporaryFile() t.write(self.stdin.getvalue()) self.stdin = t self.using_temp_stdin = 1 self.stdin.write(rec.content) # read some filter data elif rec.recType == FCGI_DATA: if rec.contentLength == 0: # end of the stream self.remainingRecs = self.remainingRecs - 1 else: self.filterData.write(rec.content) # We've processed the record. Now what do we do? if self.remainingRecs > 0: # prepare to get the next record self.setInitialState() else: # We've got them all. Let ZPublisher do its thang. DebugLogger.log('I', id(self), self.stdin.tell()) # But first, fixup the auth header if using newest mod_fastcgi. if self.env.has_key('Authorization'): self.env['HTTP_AUTHORIZATION'] = self.env['Authorization'] del self.env['Authorization'] self.stdin.seek(0) self.send_response()
def log_request(self, bytes): DebugLogger.log('E', id(self)) if 'HTTP_USER_AGENT' in self.env: user_agent = self.env['HTTP_USER_AGENT'] else: user_agent = '' if 'HTTP_REFERER' in self.env: referer = self.env['HTTP_REFERER'] else: referer = '' if 'PATH_INFO' in self.env: path = self.env['PATH_INFO'] else: path = '' if 'REQUEST_METHOD' in self.env: method = self.env['REQUEST_METHOD'] else: method = "GET" user_name = '-' if 'HTTP_AUTHORIZATION' in self.env: http_authorization = self.env['HTTP_AUTHORIZATION'] if string.lower(http_authorization[:6]) == 'basic ': try: decoded = base64.decodestring(http_authorization[6:]) except base64.binascii.Error: decoded = '' t = string.split(decoded, ':', 1) if len(t) >= 2: user_name = t[0] if self.addr: self.server.logger.log( self.addr[0], '%s - %s [%s] "%s %s" %d %d "%s" "%s"' % ( self.addr[1], user_name, time.strftime( '%d/%b/%Y:%H:%M:%S ', time.localtime(time.time()) ) + tz_for_log, method, path, self.reply_code, bytes, referer, user_agent ) ) else: self.server.logger.log( '127.0.0.1 ', '- %s [%s] "%s %s" %d %d "%s" "%s"' % ( user_name, time.strftime( '%d/%b/%Y:%H:%M:%S ', time.localtime(time.time()) ) + tz_for_log, method, path, self.reply_code, bytes, referer, user_agent ) )
def found_terminator(self): # Are we starting a new record? If so, data is the header. if not self.curRec: self.curRec = FCGIRecord(self.data.getvalue()) if self.curRec.needMore(): self.set_terminator(self.curRec.needMore()) self.data = StringIO() return rec = self.curRec # If waiting for record content, give it to the record. if rec.needContent(): rec.parseContent(self.data.getvalue()) if rec.needMore(): self.set_terminator(rec.needMore()) self.data = StringIO() return if rec.needPadding(): rec.gotPadding() # If we get this far without returning, we've got the whole # record. Figure out what to do with it. if rec.recType in FCGI_ManagementTypes: # Apache mod_fastcgi doesn't send these, but others may self.handleManagementTypes(rec) elif rec.reqId == 0: # It's a management record of unknown type. # Complain about it... r2 = FCGIRecord() r2.recType = FCGI_UNKNOWN_TYPE r2.unknownType = rec.recType self.push(r2.getRecordAsString(), 0) # Since we don't actually have to do anything to ignore the # following conditions, they have been commented out and have # been left in the code for documentation purposes. # Ignore requests that aren't active # elif (rec.reqId != self.requestId and # rec.recType != FCGI_BEGIN_REQUEST): # pass # # If we're already doing a request, ignore further BEGIN_REQUESTs # elif rec.recType == FCGI_BEGIN_REQUEST and self.requestId != 0: # pass # Begin a new request elif rec.recType == FCGI_BEGIN_REQUEST and self.requestId == 0: self.requestId = rec.reqId if rec.role == FCGI_AUTHORIZER: self.remainingRecs = 1 elif rec.role == FCGI_RESPONDER: self.remainingRecs = 2 elif rec.role == FCGI_FILTER: self.remainingRecs = 3 # Read some name-value pairs (the CGI environment) elif rec.recType == FCGI_PARAMS: if rec.contentLength == 0: # end of the stream if 'REQUEST_METHOD' in self.env: method = self.env['REQUEST_METHOD'] else: method = 'GET' if 'PATH_INFO' in self.env: path = self.env['PATH_INFO'] else: path = '' DebugLogger.log('B', id(self), '%s %s' % (method, path)) self.remainingRecs = self.remainingRecs - 1 self.content_length = string.atoi(self.env.get( 'CONTENT_LENGTH', '0')) else: self.env.update(rec.values) # read some stdin data elif rec.recType == FCGI_STDIN: if rec.contentLength == 0: # end of the stream self.remainingRecs = self.remainingRecs - 1 else: # see if stdin is getting too big, and # replace it with a tempfile if necessary if len(rec.content) + self.stdin.tell() > 1048576 and \ not self.using_temp_stdin: t = TemporaryFile() t.write(self.stdin.getvalue()) self.stdin = t self.using_temp_stdin = 1 self.stdin.write(rec.content) # read some filter data elif rec.recType == FCGI_DATA: if rec.contentLength == 0: # end of the stream self.remainingRecs = self.remainingRecs - 1 else: self.filterData.write(rec.content) # We've processed the record. Now what do we do? if self.remainingRecs > 0: # prepare to get the next record self.setInitialState() else: # We've got them all. Let ZPublisher do its thang. DebugLogger.log('I', id(self), self.stdin.tell()) # But first, fixup the auth header if using newest mod_fastcgi. if 'Authorization' in self.env: self.env['HTTP_AUTHORIZATION'] = self.env['Authorization'] del self.env['Authorization'] self.stdin.seek(0) self.send_response()