Skip to content

Commit f65a3a4

Browse files
fix multipart requests
1 parent df23246 commit f65a3a4

1 file changed

Lines changed: 39 additions & 9 deletions

File tree

drift/instrumentation/httpx/instrumentation.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,33 @@ def _get_content_type_header(self, headers: dict) -> str | None:
868868
return value
869869
return None
870870

871+
def _get_request_body_safely(self, request: Any) -> bytes | None:
872+
"""Safely get request body content.
873+
874+
For multipart/streaming requests, the body may not be available
875+
until request.read() is called. This method handles the edge cases.
876+
877+
Args:
878+
request: httpx.Request object
879+
880+
Returns:
881+
bytes content or None if unavailable
882+
"""
883+
try:
884+
# Check if content is already available (non-streaming requests)
885+
if hasattr(request, '_content') and request._content is not None:
886+
return request.content
887+
888+
# For streaming/multipart requests, read the content
889+
# This is safe because:
890+
# - In REPLAY mode: we're not sending the actual request anyway
891+
# - In RECORD mode finalize: the request has already been sent
892+
request.read()
893+
return request.content
894+
except Exception:
895+
# Content not available - could be streaming or error
896+
return None
897+
871898
def _try_get_mock_from_request_sync(
872899
self,
873900
sdk: TuskDrift,
@@ -898,11 +925,12 @@ def _try_get_mock_from_request_sync(
898925
if hasattr(request.url, 'params'):
899926
params = dict(request.url.params)
900927

901-
# Get body from request.content (already bytes)
928+
# Get body from request - handle streaming/multipart bodies
902929
body_base64 = None
903930
body_size = 0
904-
if request.content:
905-
body_base64, body_size = self._encode_body_to_base64(request.content)
931+
request_body = self._get_request_body_safely(request)
932+
if request_body:
933+
body_base64, body_size = self._encode_body_to_base64(request_body)
906934

907935
raw_input_value = {
908936
"method": method,
@@ -1245,11 +1273,12 @@ def _finalize_span_from_request(
12451273
if hasattr(request.url, 'params'):
12461274
params = dict(request.url.params)
12471275

1248-
# Get request body from request.content (already bytes)
1276+
# Get request body - handle streaming/multipart bodies
12491277
body_base64 = None
12501278
body_size = 0
1251-
if request.content:
1252-
body_base64, body_size = self._encode_body_to_base64(request.content)
1279+
request_body = self._get_request_body_safely(request)
1280+
if request_body:
1281+
body_base64, body_size = self._encode_body_to_base64(request_body)
12531282

12541283
input_value = {
12551284
"method": method,
@@ -1610,11 +1639,12 @@ async def _finalize_span_from_request_async(
16101639
if hasattr(request.url, 'params'):
16111640
params = dict(request.url.params)
16121641

1613-
# Get request body from request.content (already bytes)
1642+
# Get request body - handle streaming/multipart bodies
16141643
body_base64 = None
16151644
body_size = 0
1616-
if request.content:
1617-
body_base64, body_size = self._encode_body_to_base64(request.content)
1645+
request_body = self._get_request_body_safely(request)
1646+
if request_body:
1647+
body_base64, body_size = self._encode_body_to_base64(request_body)
16181648

16191649
input_value = {
16201650
"method": method,

0 commit comments

Comments
 (0)