Last active
April 13, 2023 00:09
-
-
Save meyt/cd4d89a396b5b46960d5f839671678ae to your computer and use it in GitHub Desktop.
Measure HTTP request and response time in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socks | |
from time import time | |
from dataclasses import dataclass | |
from http.client import HTTPConnection, HTTPSConnection, HTTPResponse | |
from urllib.parse import urlparse | |
USER_AGENT = ( | |
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " | |
"Chrome/112.0.0.0 Safari/537.36" | |
) | |
class TimedHTTPResponse(HTTPResponse): | |
_statusts = None | |
def _read_status(self, *args, **kwargs): | |
r = super()._read_status(*args, **kwargs) | |
if self._statusts is None: # in case of HTTP:100 | |
self._statusts = time() | |
return r | |
@dataclass | |
class HttpResult: | |
response: HTTPResponse | |
body: bytes | |
time_request: float | |
time_startresponse: float | |
time_download: float | |
def httpcall( | |
url, | |
method="get", | |
socks5=None, | |
headers=None, | |
body=None, | |
useragent=None, | |
debuglevel=0, | |
): | |
method = method.upper() | |
url = urlparse(url) | |
path = url.path | |
if not path: | |
path = "/" | |
elif url.query: | |
path = f"{path}?{url.query}" | |
_headers = {"user-agent": useragent or USER_AGENT} | |
if headers is not None: | |
_headers.update(headers) | |
# create connection | |
conn_cls = HTTPSConnection if url.scheme == "https" else HTTPConnection | |
if socks5: | |
proxy_host, proxy_port = socks5.split(":") | |
proxy_port = int(proxy_port) | |
conn = conn_cls(proxy_host, proxy_port) | |
conn.set_tunnel(url.netloc, url.port) | |
conn.sock = socks.socksocket() | |
conn.sock.set_proxy(socks.PROXY_TYPE_SOCKS5, proxy_host, proxy_port) | |
conn.sock.connect((url.netloc, url.port)) | |
else: | |
conn = conn_cls(url.netloc) | |
conn.response_class = TimedHTTPResponse | |
conn.set_debuglevel(debuglevel) | |
ts1 = time() | |
# send request | |
conn.request(method, path, headers=_headers, body=body) | |
ts2 = time() | |
# get response | |
res = conn.getresponse() | |
body = res.read() | |
ts3 = time() | |
return HttpResult( | |
time_request=ts2 - ts1, | |
time_startresponse=res._statusts - ts2, | |
time_download=ts3 - res._statusts, | |
response=res, | |
body=body, | |
) | |
""" | |
Usage: | |
r = httpcall("http://httpbin.org/get") | |
print( | |
r.time_request, | |
r.time_startresponse, | |
r.time_download, | |
r.response.status, | |
r.response.reason, | |
r.body, | |
) | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment