diff --git a/pubnub/request_handlers/async_aiohttp.py b/pubnub/request_handlers/async_aiohttp.py index a67605c2..3b057b66 100644 --- a/pubnub/request_handlers/async_aiohttp.py +++ b/pubnub/request_handlers/async_aiohttp.py @@ -141,7 +141,8 @@ async def async_request(self, options_func, cancellation_event): uuid=uuid, auth_key=auth_key, client_request=None, - client_response=response + client_response=response, + http_version=f"HTTP/{response.version.major}.{response.version.minor}" if response.version else None ) # if body is not None and len(body) > 0 and not options.non_json_response: @@ -172,7 +173,7 @@ async def async_request(self, options_func, cancellation_event): else: data = "N/A" - logger.debug(data) + logger.debug("[%s %s] %s" % (options.operation_type, response_info.http_version, data)) if response.status not in (200, 307, 204): diff --git a/pubnub/request_handlers/async_httpx.py b/pubnub/request_handlers/async_httpx.py index 002d6df1..512e4a56 100644 --- a/pubnub/request_handlers/async_httpx.py +++ b/pubnub/request_handlers/async_httpx.py @@ -43,7 +43,8 @@ def __init__(self, pubnub): async def create_session(self): self._session = httpx.AsyncClient( timeout=httpx.Timeout(self.pubnub.config.connect_timeout), - transport=self._connector + transport=self._connector, + http2=True ) async def close_session(self): @@ -193,7 +194,8 @@ async def async_request(self, options_func, cancellation_event): uuid=uuid, auth_key=auth_key, client_request=None, - client_response=response + client_response=response, + http_version=response.http_version ) # if body is not None and len(body) > 0 and not options.non_json_response: @@ -224,7 +226,7 @@ async def async_request(self, options_func, cancellation_event): else: data = "N/A" - logger.debug(data) + logger.debug("[%s %s] %s" % (options.operation_type, response_info.http_version, data)) if response.status_code not in (200, 307, 204): diff --git a/pubnub/request_handlers/httpx.py b/pubnub/request_handlers/httpx.py index d22e0ee2..d9615072 100644 --- a/pubnub/request_handlers/httpx.py +++ b/pubnub/request_handlers/httpx.py @@ -174,7 +174,7 @@ def _ensure_session(self): with self._session_lock: if self._session is None or self._session.is_closed: logger.debug("Creating new HTTP session") - self._session = httpx.Client() + self._session = httpx.Client(http2=True) return self._session def close(self): @@ -318,7 +318,8 @@ def _build_envelope(self, p_options, e_options): origin=res.url.host, uuid=uuid, auth_key=auth_key, - client_request=res.request + client_request=res.request, + http_version=res.http_version ) if res.status_code not in [200, 204, 307]: @@ -433,15 +434,13 @@ def _invoke_request(self, p_options, e_options, base_origin): try: res = session.request(**args) - # Safely access response text - read content first for streaming responses + try: - logger.debug("GOT %s" % res.text) + logger.debug("[%s %s] %s" % (e_options.operation_type, res.http_version, res.text)) except httpx.ResponseNotRead: - # For streaming responses, we need to read first - logger.debug("GOT %s" % res.content.decode('utf-8', errors='ignore')) + logger.debug("[%s %s] %s" % (e_options.operation_type, res.http_version, res.content.decode('utf-8', errors='ignore'))) except Exception as e: - # Fallback logging in case of any response reading issues - logger.debug("GOT response (content access failed: %s)" % str(e)) + logger.debug("[%s %s] (content access failed: %s)" % (e_options.operation_type, res.http_version, str(e))) except httpx.ConnectError as e: if use_watchdog and self._watchdog.triggered: diff --git a/pubnub/request_handlers/requests.py b/pubnub/request_handlers/requests.py index 14de1448..781d65ec 100644 --- a/pubnub/request_handlers/requests.py +++ b/pubnub/request_handlers/requests.py @@ -174,7 +174,11 @@ def _build_envelope(self, p_options, e_options): origin=url.hostname, uuid=uuid, auth_key=auth_key, - client_request=res.request + client_request=res.request, + http_version=( + f"HTTP/{res.raw.version // 10}.{res.raw.version % 10}" + if res.raw and res.raw.version else None + ) ) if not res.ok: @@ -268,7 +272,12 @@ def _invoke_request(self, p_options, e_options, base_origin): try: res = self.session.request(**args) - logger.debug("GOT %s" % res.text) + http_ver = ( + f"HTTP/{res.raw.version // 10}.{res.raw.version % 10}" + if res.raw and res.raw.version else "unknown" + ) + logger.debug("[%s %s] %s" % (e_options.operation_type, http_ver, res.text)) + except requests.exceptions.ConnectionError as e: raise PubNubException( pn_error=PNERR_CONNECTION_ERROR, diff --git a/pubnub/structures.py b/pubnub/structures.py index a7ca2bb9..af7575c3 100644 --- a/pubnub/structures.py +++ b/pubnub/structures.py @@ -80,7 +80,8 @@ def __init__(self, headers, pn_config): class ResponseInfo(object): - def __init__(self, status_code, tls_enabled, origin, uuid, auth_key, client_request, client_response=None): + def __init__(self, status_code, tls_enabled, origin, uuid, auth_key, client_request, + client_response=None, http_version=None): self.status_code = status_code self.tls_enabled = tls_enabled self.origin = origin @@ -88,6 +89,7 @@ def __init__(self, status_code, tls_enabled, origin, uuid, auth_key, client_requ self.auth_key = auth_key self.client_request = client_request self.client_response = client_response + self.http_version = http_version class Envelope(object): diff --git a/requirements-dev.txt b/requirements-dev.txt index a5e406e4..403f6950 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,7 +5,7 @@ flake8>=7.1.2 pytest>=8.3.5 pytest-asyncio>=1.0.0 httpx>=0.28 -h2>=4.1 +h2>=4.3 requests>=2.32.2 aiohttp>=3.10.11 cbor2>=5.6 diff --git a/setup.py b/setup.py index bae45263..880b9cef 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ install_requires=[ 'pycryptodomex>=3.3', 'httpx>=0.28,<1.0', - 'h2>=4.1', + 'h2>=4.3', 'requests>=2.32.2', 'aiohttp>3.10.11', 'cbor2>=5.6'