def _find_service(self): self.serv = registry.get_a_service_by_id(self.ident) if not self.serv: raise KeyError("Nothing known about service %s" % ident) # print >>sys.stderr,"CACHE: %s at %s\n" % (self.ident, self.serv.path) hostname, port = global_config.server_address if not hostname: hostname = "localhost" self.baseurl = "http://%s:%d/%s" % (hostname, port, self.serv.path)
def _find_service(self): self.serv = registry.get_a_service_by_id(self.ident) if not self.serv: raise KeyError("Nothing known about service %s" % ident) # print >>sys.stderr,"CACHE: %s at %s\n" % (self.ident, self.serv.path) hostname,port = global_config.server_address if not hostname: hostname = "localhost" self.baseurl = "http://%s:%d/%s" % (hostname, port, self.serv.path)
def _handle_notify(environ, f, service_list): for service_id in service_list: service = registry.get_a_service_by_id(service_id) service_environ = environ.copy() service_environ["PATH_INFO"] = service.path f.seek(0) new_request(service_environ) try: service.handler(service_environ, ignore_start_response) except Exception: raise # XXX pass
def __call__(self, environ, start_response): # The WSGI entry point for the pipeline logger.debug("Started the %s (%s) pipeline", self.ident, self.path) # Help capture the response of a WSGI request, # so I can forward it as input to the next request. captured_response = [None, None, None] captured_body_length = None def capture_start_response(status, headers, exc_info=None): if exc_info is None: captured_response[:] = [status, headers, False] else: captured_response[:] = [status, headers, True] # Forward this to the real start_response return start_response(status, headers, exc_info) num_stages = len(self.stages) for stage_index, is_first, is_last, stage in _flag_position(self.stages): service = registry.get_a_service_by_id(stage.ident) if service is None: logger.error("Pipeline %r(%r) could not find a %r service", self.ident, self.path, stage.ident) start_response("500 Internal server error", [("Content-Type", "text/plain")]) return ["Broken internal pipeline.\n"] # Construct a new environ for each stage in the pipeline. # We have to make a new one since a stage is free to # do whatever it wants to the environ. (It does not have # free reign over all the contents of the environ.) stage_environ = environ.copy() if not is_first: # The first stage gets the HTTP request method # Everything else gets a POST. stage_environ["REQUEST_METHOD"] = "POST" assert service.path is not None # Can some services/pipelines not be mounted? stage_environ["SCRIPT_NAME"] = service.path #stage_environ["PATH_INFO"] = ... # I think this is best left unchanged. XXX if is_first: # Augment the QUERY_STRING string with any pipeline-defined query string # (You probably shouldn't be doing this. Remove this feature? XXX) if stage.query_string: if stage_environ["QUERY_STRING"]: stage_environ["QUERY_STRING"] += ("&" + stage.query_string) else: stage_environ["QUERY_STRING"] = stage.query_string else: # The other stages get nothing about the HTTP query string # but may get a pipeline-defined query string if stage.query_string: stage_environ["QUERY_STRING"] = stage.query_string else: stage_environ["QUERY_STRING"] = "" if not is_first: # Forward information from the previous stage stage_environ["CONTENT_TYPE"] = _find_header("content-type", captured_response[1]) stage_environ["CONTENT_LENGTH"] = captured_body_length stage_environ["wsgi.input"] = captured_body # Make the previous response headers available to the next stage stage_environ["akara.pipeline_headers"] = captured_response[1] logger.debug("Pipeline %r(%r) at stage %r (%d/%d)", self.ident, self.path, stage.ident, stage_index+1, num_stages) if is_last: # End of the pipeline. Let someone else deal with the response return service.handler(stage_environ, start_response) else: # Intermediate stage output. Collect to forward to the next stage captured_body = StringIO() result = service.handler(stage_environ, capture_start_response) # Did start_response get an exc_info term? (It might not # have been thrown when forwarded to the real start_response.) if captured_response[2]: # It didn't raise an exception. Assume the response contains # the error message. Forward it and stop the pipeline. logger.debug( "Pipeline %r(%r) start_response received exc_info from stage %r. Stopping.", self.ident, self.path, stage.ident) return result # Was there some sort of HTTP error? status = captured_response[0].split(None, 1)[0] # XXX What counts as an error? if status not in ("200", "201"): logger.debug( "Pipeline %r(%r) start_response received status %r from stage %r. Stopping.", self.ident, self.path, status, stage.ident) start_response(captured_response[0], captured_response[1]) # This should contain error information return result # Save the response to the cStringIO try: # We might be able to get some better performance using # a wsgi.file_wrapper. If the chunks come from a file-like # object then we can reach in and get that file-like object # instead of copying it to a new one for chunk in result: captured_body.write(chunk) finally: # Part of the WSGI spec if hasattr(result, "close"): result.close() captured_body_length = captured_body.tell() captured_body.seek(0) raise AssertionErorr("should never get here")