def expected_http_body_size(request, response=None): """ Returns: The expected body length: - a positive integer, if the size is known in advance - None, if the size in unknown in advance (chunked encoding) - -1, if all data should be read until end of stream. Raises: exceptions.HttpSyntaxException, if the content length header is invalid """ # Determine response size according to # http://tools.ietf.org/html/rfc7230#section-3.3 if not response: headers = request.headers response_code = None is_request = True else: headers = response.headers response_code = response.status_code is_request = False if is_request: if headers.get("expect", "").lower() == "100-continue": return 0 else: if request.method.upper() == "HEAD": return 0 if 100 <= response_code <= 199: return 0 if response_code == 200 and request.method.upper() == "CONNECT": return 0 if response_code in (204, 304): return 0 if "chunked" in headers.get("transfer-encoding", "").lower(): return None if "content-length" in headers: try: size = int(headers["content-length"]) if size < 0: raise ValueError() return size except ValueError: raise exceptions.HttpSyntaxException("Unparseable Content Length") if is_request: return 0 return -1
def read_response( self, __rfile, request_method=b'', body_size_limit=None, include_body=True, stream_id=None, ): if body_size_limit is not None: raise NotImplementedError() self.perform_connection_preface() timestamp_start = time.time() if hasattr(self.tcp_handler.rfile, "reset_timestamps"): self.tcp_handler.rfile.reset_timestamps() stream_id, headers, body = self._receive_transmission( stream_id=stream_id, include_body=include_body, ) if hasattr(self.tcp_handler.rfile, "first_byte_timestamp"): # more accurate timestamp_start timestamp_start = self.tcp_handler.rfile.first_byte_timestamp if include_body: timestamp_end = time.time() else: timestamp_end = None response = netlib.http.response.Response( b"HTTP/2.0", int(headers.get(':status', 502)), b'', headers, body, timestamp_start=timestamp_start, timestamp_end=timestamp_end, ) response.stream_id = stream_id return response
def read_request( self, __rfile, include_body=True, body_size_limit=None, allow_empty=False, ): if body_size_limit is not None: raise NotImplementedError() self.perform_connection_preface() timestamp_start = time.time() if hasattr(self.tcp_handler.rfile, "reset_timestamps"): self.tcp_handler.rfile.reset_timestamps() stream_id, headers, body = self._receive_transmission( include_body=include_body, ) if hasattr(self.tcp_handler.rfile, "first_byte_timestamp"): # more accurate timestamp_start timestamp_start = self.tcp_handler.rfile.first_byte_timestamp timestamp_end = time.time() authority = headers.get(':authority', b'') method = headers.get(':method', 'GET') scheme = headers.get(':scheme', 'https') path = headers.get(':path', '/') headers.clear(":method") headers.clear(":scheme") headers.clear(":path") host = None port = None if path == '*' or path.startswith("/"): first_line_format = "relative" elif method == 'CONNECT': first_line_format = "authority" if ":" in authority: host, port = authority.split(":", 1) else: host = authority else: first_line_format = "absolute" # FIXME: verify if path or :host contains what we need scheme, host, port, _ = url.parse(path) scheme = scheme.decode('ascii') host = host.decode('ascii') if host is None: host = 'localhost' if port is None: port = 80 if scheme == 'http' else 443 port = int(port) request = netlib.http.request.Request( first_line_format, method.encode('ascii'), scheme.encode('ascii'), host.encode('ascii'), port, path.encode('ascii'), b"HTTP/2.0", headers, body, timestamp_start, timestamp_end, ) request.stream_id = stream_id return request