You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem
Hi, am trying to use the ProxyPoolPlugin and i faced an issue which the @request param in before_upstream_connection method , doesn't contain all headers and path, when i try "print(request.headers)" it display only three headers:
# -*- coding: utf-8 -*-""" proxy.py ~~~~~~~~ ⚡⚡⚡ Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on Network monitoring, controls & Application development, testing, debugging. :copyright: (c) 2013-present by Abhinav Singh and contributors. :license: BSD, see LICENSE for more details."""importbase64importrandomimportloggingimportipaddressfromtypingimportAny, Dict, List, Optionalfromproxy.httpimportUrl, httpHeaders, httpMethodsfromproxy.core.baseimportTcpUpstreamConnectionHandlerfromproxy.http.proxyimportHttpProxyBasePluginfromproxy.common.flagimportflagsfromproxy.http.parserimportHttpParserfromproxy.common.utilsimporttext_, bytes_fromproxy.http.exceptionimportHttpProtocolExceptionfromproxy.common.constantsimport (
COLON, ANY_INTERFACE_HOSTNAMES, LOCAL_INTERFACE_HOSTNAMES,
)
logger=logging.getLogger(__name__)
DEFAULT_HTTP_ACCESS_LOG_FORMAT='{client_ip}:{client_port} - '+ \
'{request_method} {server_host}:{server_port}{request_path} -> '+ \
'{upstream_proxy_host}:{upstream_proxy_port} - '+ \
'{response_code} {response_reason} - {response_bytes} bytes - '+ \
'{connection_time_ms} ms'DEFAULT_HTTPS_ACCESS_LOG_FORMAT='{client_ip}:{client_port} - '+ \
'{request_method} {server_host}:{server_port} -> '+ \
'{upstream_proxy_host}:{upstream_proxy_port} - '+ \
'{response_bytes} bytes - {connection_time_ms} ms'classProxyPoolPlugin(TcpUpstreamConnectionHandler, HttpProxyBasePlugin):
"""Proxy pool plugin simply acts as a proxy adapter for proxy.py itself. Imagine this plugin as setting up proxy settings for proxy.py instance itself. All incoming client requests are proxied to configured upstream proxies."""def__init__(self, *args: Any, **kwargs: Any) ->None:
super().__init__(*args, **kwargs)
self._endpoint: Url=self._select_proxy()
# Cached attributes to be used during access log overrideself._metadata: List[Any] = [
None, None, None, None,
]
defhandle_upstream_data(self, raw: memoryview) ->None:
self.client.queue(raw)
defbefore_upstream_connection(
self, request: HttpParser,
) ->Optional[HttpParser]:
"""Avoids establishing the default connection to upstream server by returning None. TODO(abhinavsingh): Ideally connection to upstream proxy endpoints must be bootstrapped within it's own re-usable and garbage collected pool, to avoid establishing a new upstream proxy connection for each client request. See :class:`~proxy.core.connection.pool.UpstreamConnectionPool` which is a work in progress for SSL cache handling. """# We don't want to send private IP requests to remote proxiestry:
ifipaddress.ip_address(text_(request.host)).is_private:
returnrequestexceptValueError:
passifself._endpoint==None:
returnrequest# If chosen proxy is the local instance, bypass upstream proxiesassertself._endpoint.portandself._endpoint.hostnameifself._endpoint.port==8899and \
self._endpoint.hostnameinLOCAL_INTERFACE_HOSTNAMES+ANY_INTERFACE_HOSTNAMES:
returnrequest# Establish connection to chosen upstream proxyendpoint_tuple= (text_(self._endpoint.hostname), self._endpoint.port)
logger.debug('Using endpoint: {0}:{1}'.format(*endpoint_tuple))
self.initialize_upstream(*endpoint_tuple)
assertself.upstreamtry:
self.upstream.connect()
exceptTimeoutError:
raiseHttpProtocolException(
'Timed out connecting to upstream proxy {0}:{1}'.format(
*endpoint_tuple,
),
)
exceptConnectionRefusedError:
# TODO(abhinavsingh): Try another choice, when all (or max configured) choices have# exhausted, retry for configured number of times before giving up.## Failing upstream proxies, must be removed from the pool temporarily.# A periodic health check must put them back in the pool. This can be achieved# using a data structure without having to spawn separate thread/process for health# check.raiseHttpProtocolException(
'Connection refused by upstream proxy {0}:{1}'.format(
*endpoint_tuple,
),
)
logger.debug(
'Established connection to upstream proxy {0}:{1}'.format(
*endpoint_tuple,
),
)
returnNonedefhandle_client_request(
self, request: HttpParser,
) ->Optional[HttpParser]:
"""Only invoked once after client original proxy request has been received completely."""print(request.build(for_proxy=True).decode('utf-8'))
ifnotself.upstream:
returnrequestassertself.upstream# For log sanity (i.e. to avoid None:None), expose upstream host:port from headershost, port=None, None# Browser or applications may sometime send## "CONNECT / HTTP/1.0\r\n\r\n"## for proxy keep alive checks.ifrequest.has_header(b'host'):
url=Url.from_bytes(request.header(b'host'))
asserturl.hostnamehost, port=url.hostname.decode('utf-8'), url.portport=portifportelse (
443ifrequest.is_https_tunnelelse80
)
path=Noneifnotrequest.pathelserequest.path.decode()
self._metadata= [
host, port, path, request.method,
]
# Queue original request optionally with auth headers to upstream proxyifself._endpoint.has_credentials:
assertself._endpoint.usernameandself._endpoint.passwordrequest.add_header(
httpHeaders.PROXY_AUTHORIZATION,
b'Basic '+base64.b64encode(
self._endpoint.username+COLON+self._endpoint.password,
),
)
self.upstream.queue(memoryview(request.build(for_proxy=True)))
returnrequestdefhandle_client_data(self, raw: memoryview) ->Optional[memoryview]:
"""Only invoked when before_upstream_connection returns None"""# Queue data to the proxy endpointassertself.upstreamself.upstream.queue(raw)
returnrawdefhandle_upstream_chunk(self, chunk: memoryview) ->Optional[memoryview]:
"""Will never be called since we didn't establish an upstream connection."""ifnotself.upstream:
returnchunk# pylint: disable=broad-exception-raisedraiseException("This should have never been called")
defon_upstream_connection_close(self) ->None:
"""Called when client connection has been closed."""ifself.upstreamandnotself.upstream.closed:
logger.debug('Closing upstream proxy connection')
self.upstream.close()
self.upstream=Nonedefon_access_log(self, context: Dict[str, Any]) ->Optional[Dict[str, Any]]:
ifnotself.upstream:
returncontextaddr, port= (self.upstream.addr[0], self.upstream.addr[1]) \
ifself.upstreamelse (None, None)
context.update({
'upstream_proxy_host': addr,
'upstream_proxy_port': port,
'server_host': self._metadata[0],
'server_port': self._metadata[1],
'request_path': self._metadata[2],
'response_bytes': self.total_size,
})
self.access_log(context)
returnNonedefaccess_log(self, log_attrs: Dict[str, Any]) ->None:
access_log_format=DEFAULT_HTTPS_ACCESS_LOG_FORMATrequest_method=self._metadata[3]
ifrequest_methodandrequest_method!=httpMethods.CONNECT:
access_log_format=DEFAULT_HTTP_ACCESS_LOG_FORMATlogger.info(access_log_format.format_map(log_attrs))
def_select_proxy(self) ->Url:
"""Choose a random proxy from the pool. TODO: Implement your own logic here e.g. round-robin, least connection etc. """returnNoneimportproxyif__name__=='__main__':
proxy.main(
hostname=ipaddress.IPv4Address('0.0.0.0'),
port=8899,
plugins=[ProxyPoolPlugin],
)
thanks.
The text was updated successfully, but these errors were encountered:
@geckoy You don't see header because its an HTTPS request. You will need TLS interception if you want to inspect the entire request. You can enable TLS interception on your remote proxies. Unfortunately, ProxyPool currently don't work well together w/ TLS interception enabled locally. See #1368 for background.
Problem
Hi, am trying to use the
ProxyPoolPlugin
and i faced an issue which the@request
param inbefore_upstream_connection
method , doesn't contain all headers and path, when i try "print(request.headers)
" it display only three headers:in contrary the host server receives all headers:
Script am using
thanks.
The text was updated successfully, but these errors were encountered: