def _read_request_line( line: bytes) -> Tuple[str, int, bytes, bytes, bytes, bytes, bytes]: try: method, target, http_version = line.split() port: Optional[int] if target == b"*" or target.startswith(b"/"): scheme, authority, path = b"", b"", target host, port = "", 0 elif method == b"CONNECT": scheme, authority, path = b"", target, b"" host, port = url.parse_authority(authority, check=True) if not port: raise ValueError else: scheme, rest = target.split(b"://", maxsplit=1) authority, path_ = rest.split(b"/", maxsplit=1) path = b"/" + path_ host, port = url.parse_authority(authority, check=True) port = port or url.default_port(scheme) if not port: raise ValueError # TODO: we can probably get rid of this check? url.parse(target) raise_if_http_version_unknown(http_version) except ValueError as e: raise ValueError(f"Bad HTTP request line: {line!r}") from e return host, port, method, scheme, authority, path, http_version
def read_request_headers(self, flow): self.request_message.arrived.wait() self.raise_zombie() if self.pushed: flow.metadata['h2-pushed-stream'] = True # pseudo header must be present, see https://http2.github.io/http2-spec/#rfc.section.8.1.2.3 authority = self.request_message.headers.pop(':authority', "") method = self.request_message.headers.pop(':method') scheme = self.request_message.headers.pop(':scheme') path = self.request_message.headers.pop(':path') host, port = url.parse_authority(authority, check=True) port = port or url.default_port(scheme) or 0 return http.HTTPRequest( host, port, method.encode(), scheme.encode(), authority.encode(), path.encode(), b"HTTP/2.0", self.request_message.headers, None, None, self.timestamp_start, self.timestamp_end, )
def _read_request_line(rfile): try: line = _get_first_line(rfile) except exceptions.HttpReadDisconnect: # We want to provide a better error message. raise exceptions.HttpReadDisconnect("Client disconnected") try: method, target, http_version = line.split() if target == b"*" or target.startswith(b"/"): scheme, authority, path = b"", b"", target host, port = "", 0 elif method == b"CONNECT": scheme, authority, path = b"", target, b"" host, port = url.parse_authority(authority, check=True) if not port: raise ValueError else: scheme, rest = target.split(b"://", maxsplit=1) authority, path_ = rest.split(b"/", maxsplit=1) path = b"/" + path_ host, port = url.parse_authority(authority, check=True) port = port or url.default_port(scheme) if not port: raise ValueError # TODO: we can probably get rid of this check? url.parse(target) _check_http_version(http_version) except ValueError: raise exceptions.HttpSyntaxException(f"Bad HTTP request line: {line}") return host, port, method, scheme, authority, path, http_version
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() # pseudo header must be present, see https://http2.github.io/http2-spec/#rfc.section.8.1.2.3 authority = headers.pop(':authority', "") method = headers.pop(':method', "") scheme = headers.pop(':scheme', "") path = headers.pop(':path', "") host, port = url.parse_authority(authority, check=False) port = port or url.default_port(scheme) or 0 request = mitmproxy.net.http.Request( host=host, port=port, method=method.encode(), scheme=scheme.encode(), authority=authority.encode(), path=path.encode(), http_version=b"HTTP/2.0", headers=headers, content=body, trailers=None, timestamp_start=timestamp_start, timestamp_end=timestamp_end, ) request.stream_id = stream_id return request
def pretty_url(self) -> str: """ Like :py:attr:`url`, but using :py:attr:`pretty_host` instead of :py:attr:`host`. """ if self.first_line_format == "authority": return self.authority host_header = self.host_header if not host_header: return self.url pretty_host, pretty_port = url.parse_authority(host_header, check=False) pretty_port = pretty_port or url.default_port(self.scheme) or 443 return url.unparse(self.scheme, pretty_host, pretty_port, self.path)
def test_default_port(): assert url.default_port("http") == 80 assert url.default_port(b"https") == 443 assert url.default_port(b"qux") is None