async def index(path=None): response = await make_response('{}') if handler: data = await request.get_data() try: result = await run_sync(handler, request, data) except Exception as e: LOG.warning( 'Error in proxy handler for request %s %s: %s %s' % (request.method, request.url, e, traceback.format_exc())) response.status_code = 500 return response if result is not None: is_chunked = uses_chunked_encoding(result) result_content = result.content or '' response = await make_response(result_content) response.status_code = result.status_code if is_chunked: response.headers.pop('Content-Length', None) result.headers.pop('Server', None) result.headers.pop('Date', None) response.headers.update(dict(result.headers)) # set multi-value headers multi_value_headers = getattr(result, 'multi_value_headers', {}) for key, values in multi_value_headers.items(): for value in values: response.headers.add_header(key, value) # set default headers, if required if 'Content-Length' not in response.headers and not is_chunked: response.headers['Content-Length'] = str( len(result_content) if result_content else 0) if 'Connection' not in response.headers: response.headers['Connection'] = 'close' return response
async def index(path=None): response = await make_response("{}") if handler: data = await request.get_data() try: result = await run_sync(handler, request, data) if isinstance(result, Exception): raise result except Exception as e: LOG.warning( "Error in proxy handler for request %s %s: %s %s", request.method, request.url, e, traceback.format_exc(), ) response.status_code = 500 if isinstance(e, HTTPErrorResponse): response.status_code = e.code or response.status_code return response if result is not None: # check if this is an async generator (for HTTP2 push event responses) async_gen = get_async_generator_result(result) if async_gen: return async_gen # prepare and return regular response is_chunked = uses_chunked_encoding(result) result_content = result.content or "" response = await make_response(result_content) response.status_code = result.status_code if is_chunked: response.headers.pop("Content-Length", None) result.headers.pop("Server", None) result.headers.pop("Date", None) headers = { k: str(v).replace("\n", r"\n") for k, v in result.headers.items() } response.headers.update(headers) # set multi-value headers multi_value_headers = getattr(result, "multi_value_headers", {}) for key, values in multi_value_headers.items(): for value in values: response.headers.add_header(key, value) # set default headers, if required if not is_chunked and request.method not in [ "OPTIONS", "HEAD" ]: response_data = await response.get_data() response.headers["Content-Length"] = str( len(response_data or "")) if "Connection" not in response.headers: response.headers["Connection"] = "close" # fix headers for OPTIONS requests (possible fix for Firefox requests) if request.method == "OPTIONS": response.headers.pop("Content-Type", None) if not response.headers.get("Cache-Control"): response.headers["Cache-Control"] = "no-cache" return response
def add_reponse_metadata_headers(response): if response.headers.get('content-language') is None: response.headers['content-language'] = 'en-US' if response.headers.get('cache-control') is None: response.headers['cache-control'] = 'no-cache' if response.headers.get('content-encoding') is None: if not uses_chunked_encoding(response): response.headers['content-encoding'] = 'identity'
async def index(path=None): response = await make_response('{}') if handler: data = await request.get_data() try: result = await run_sync(handler, request, data) if isinstance(result, Exception): raise result except Exception as e: LOG.warning( 'Error in proxy handler for request %s %s: %s %s' % (request.method, request.url, e, traceback.format_exc())) response.status_code = 500 if isinstance(e, HTTPErrorResponse): response.status_code = e.code or response.status_code return response if result is not None: # check if this is an async generator (for HTTP2 push event responses) async_gen = get_async_generator_result(result) if async_gen: return async_gen # prepare and return regular response is_chunked = uses_chunked_encoding(result) result_content = result.content or '' response = await make_response(result_content) response.status_code = result.status_code if is_chunked: response.headers.pop('Content-Length', None) result.headers.pop('Server', None) result.headers.pop('Date', None) headers = { k: str(v).replace('\n', r'\n') for k, v in result.headers.items() } response.headers.update(headers) # set multi-value headers multi_value_headers = getattr(result, 'multi_value_headers', {}) for key, values in multi_value_headers.items(): for value in values: response.headers.add_header(key, value) # set default headers, if required if not is_chunked and request.method not in [ 'OPTIONS', 'HEAD' ]: response_data = await response.get_data() response.headers['Content-Length'] = str( len(response_data or '')) if 'Connection' not in response.headers: response.headers['Connection'] = 'close' return response
def forward(self, method): data = self.data_bytes path = self.path forward_headers = CaseInsensitiveDict(self.headers) # force close connection connection_header = forward_headers.get('Connection') or '' if connection_header.lower() not in ['keep-alive', '']: self.close_connection = 1 client_address = self.client_address[0] server_address = ':'.join(map(str, self.server.server_address)) try: # run the actual response forwarding response = modify_and_forward( method=method, path=path, data_bytes=data, headers=forward_headers, forward_base_url=self.proxy.forward_base_url, listeners=self._listeners(), request_handler=self, client_address=client_address, server_address=server_address) # copy headers and return response self.send_response(response.status_code) # set content for chunked encoding is_chunked = uses_chunked_encoding(response) if is_chunked: response._content = create_chunked_data(response._content) # send headers content_length_sent = False for header_key, header_value in iteritems(response.headers): # filter out certain headers that we don't want to transmit if header_key.lower() not in ('transfer-encoding', 'date', 'server'): self.send_header(header_key, header_value) content_length_sent = content_length_sent or header_key.lower( ) == 'content-length' # fix content-type header if needed if not content_length_sent and not is_chunked: self.send_header( 'Content-Length', '%s' % len(response.content) if response.content else 0) if isinstance(response, LambdaResponse): self.send_multi_value_headers(response.multi_value_headers) self.end_headers() if response.content and len(response.content): self.wfile.write(to_bytes(response.content)) except Exception as e: trace = str(traceback.format_exc()) conn_errors = ('ConnectionRefusedError', 'NewConnectionError', 'Connection aborted', 'Unexpected EOF', 'Connection reset by peer', 'cannot read from timed out object') conn_error = any(e in trace for e in conn_errors) error_msg = 'Error forwarding request: %s %s' % (e, trace) if 'Broken pipe' in trace: LOG.warn( 'Connection prematurely closed by client (broken pipe).') elif not self.proxy.quiet or not conn_error: LOG.error(error_msg) if is_local_test_mode(): # During a test run, we also want to print error messages, because # log messages are delayed until the entire test run is over, and # hence we are missing messages if the test hangs for some reason. print('ERROR: %s' % error_msg) self.send_response(502) # bad gateway self.end_headers() # force close connection self.close_connection = 1 finally: try: self.wfile.flush() except Exception as e: LOG.warning('Unable to flush write file: %s' % e)