class HttpProtocolHandler: PROXY_TUNNEL_ESTABLISHED_RESPONSE_PKT = build_http_response( 200, reason=b'Connection established') def __init__(self, client_conn: socket.socket, client_addr, flags, req): self.start_time: float = time.time() self.client = client_conn self.req = req self.client_addr = client_addr # host and socket_fd self.flags = flags self.request_parser = HttpParser(0) # 0 - parse only requests self.response_parser = HttpParser(1) # 1 - parse only responses self.total_response_size: int = 0 self.upstream: Optional[urlparse.SplitResultBytes] = None self.host = None self.port = None self.upstream_url = None self.server: Optional[socket.socket] = None def parse_url(self, parser): url = parser.get_url() method = parser.get_method() protocol_pos = url.find('://') if protocol_pos != -1: url = url[(protocol_pos + 3):] port_pos = url.find(':') host_pos = url.find('/') if host_pos == -1: host_pos = len(url) if port_pos == -1 or host_pos < port_pos: port = 443 if method == "CONNECT" else DEFAULT_HTTP_PORT else: port = int((url[port_pos + 1:])[:host_pos - port_pos - 1]) port_ind = url.find(':') if port_ind != -1: url = url[:port_ind] self.upstream = urlparse.urlsplit('http://' + url + '/') self.upstream_url = self.build_upstream_relative_path() host = self.upstream.hostname port_ind = host.find(':') if port_ind != -1: host = host[:port_ind] return host, port def run(self) -> None: p = HttpParser() try: p.execute(self.req, len(self.req)) url = p.get_url() metopd = p.get_method() http_pos = url.find('://') if http_pos == -1: temp = url else: temp = url[(http_pos + 3):] port_pos = temp.find(':') host_pos = temp.find('/') if host_pos == -1: host_pos = len(temp) if port_pos == -1 or host_pos < port_pos: port = 443 if metopd == "CONNECT" else 80 else: port = int((temp[port_pos + 1:])[:host_pos - port_pos - 1]) host = p.get_headers()['host'] port_ind = host.find(':') if port_ind != -1: host = host[:port_ind] if metopd == "CONNECT": https_proxy(host, port, self.client) else: proxy(host, port, self.client, self.req) except Exception as e: print(e) pass def access_log(self): server_host, server_port = self.upstream.hostname, self.upstream.port \ if self.upstream.port else DEFAULT_HTTP_PORT connection_time_ms = (time.time() - self.start_time) * 1000 method = self.request_parser.get_method() if method == httpMethods.CONNECT: pass elif method: print('pid:%s | %s:%s - %s %s:%s%s - %s %s - %s bytes - %.2f ms' % (str(getpid()), self.client_addr[0], self.client_addr[1], method, server_host, server_port, self.request_parser.get_path(), self.response_parser.get_status_code(), self.response_parser.get_errno(), self.total_response_size, connection_time_ms))