11import uuid
22import sys
3+ import json
34
45from httpx import Request
56from typing import Union
7+ from urllib .parse import parse_qs , urlencode , urlparse , urlunparse
68
79from .types import (
810 BeforeRequestHook ,
@@ -37,14 +39,36 @@ def before_request(self, hook_ctx: BeforeRequestContext, request: Request) -> Un
3739 # Customize the User Agent header
3840 headers = self ._customize_user_agent (headers , hook_ctx )
3941
40- return Request (
41- method = request .method ,
42- url = request .url ,
43- headers = headers ,
44- content = request .content ,
42+ # Update request with new headers first
43+ request = Request (
44+ method = request .method ,
45+ url = request .url ,
46+ headers = headers ,
47+ content = request .content ,
4548 extensions = request .extensions
4649 )
47-
50+
51+ # Then populate profile ID and testmode if OAuth (this may update headers again)
52+ if self ._is_oauth_request (headers , hook_ctx ):
53+ request = self ._populate_profile_id_and_testmode (request , hook_ctx )
54+
55+ return request
56+
57+ def _is_oauth_request (self , headers : dict , hook_ctx : BeforeRequestContext ) -> bool :
58+ security = hook_ctx .config .security
59+
60+ if callable (security ):
61+ security = security ()
62+
63+ if security is None :
64+ return False
65+
66+ o_auth = getattr (security , 'o_auth' , None )
67+ if o_auth is None :
68+ return False
69+
70+ return headers .get ("authorization" , None ) == f"Bearer { o_auth } "
71+
4872 def _handle_idempotency_key (self , headers : dict ) -> dict :
4973 idempotency_key = "idempotency-key"
5074 if idempotency_key not in headers or not headers [idempotency_key ]:
@@ -66,3 +90,76 @@ def _customize_user_agent(self, headers: dict, hook_ctx: BeforeRequestContext) -
6690 headers [user_agent_key ] = new_user_agent
6791
6892 return headers
93+
94+ def _populate_profile_id_and_testmode (self , request : Request , hook_ctx : BeforeRequestContext ) -> Request :
95+ client_profile_id = hook_ctx .config .globals .profile_id
96+ client_testmode = hook_ctx .config .globals .testmode
97+
98+ # Get the HTTP method
99+ method = request .method
100+
101+ if method == "GET" :
102+ # Update the query parameters. If testmode or profileId are not present, add them.
103+ parsed_url = urlparse (str (request .url ))
104+ query_params = parse_qs (parsed_url .query , keep_blank_values = True )
105+
106+ # Add profileId if not already present
107+ if client_profile_id is not None and 'profileId' not in query_params :
108+ query_params ['profileId' ] = [client_profile_id ]
109+
110+ # Add testmode if not already present
111+ if client_testmode is not None and 'testmode' not in query_params :
112+ query_params ['testmode' ] = [str (client_testmode ).lower ()]
113+
114+ # Rebuild the URL with updated query parameters
115+ new_query = urlencode (query_params , doseq = True )
116+ new_url = urlunparse ((
117+ parsed_url .scheme ,
118+ parsed_url .netloc ,
119+ parsed_url .path ,
120+ parsed_url .params ,
121+ new_query ,
122+ parsed_url .fragment
123+ ))
124+
125+ return Request (
126+ method = request .method ,
127+ url = new_url ,
128+ headers = request .headers ,
129+ content = request .content ,
130+ extensions = request .extensions
131+ )
132+
133+ # It's POST, DELETE, PATCH
134+ # Update the JSON body. If testmode or profileId are not present, add them.
135+ if request .content :
136+ try :
137+ body = json .loads (request .content )
138+ except (json .JSONDecodeError , TypeError ):
139+ # If it's not JSON, return the request unchanged
140+ return request
141+ else :
142+ body = {}
143+
144+ # Add profileId if not already present
145+ if client_profile_id is not None and 'profileId' not in body :
146+ body ['profileId' ] = client_profile_id
147+
148+ # Add testmode if not already present
149+ if client_testmode is not None and 'testmode' not in body :
150+ body ['testmode' ] = client_testmode
151+
152+ # Create a new request with updated body
153+ new_content = json .dumps (body ).encode ('utf-8' )
154+
155+ # Update headers with correct Content-Length
156+ new_headers = dict (request .headers )
157+ new_headers ['content-length' ] = str (len (new_content ))
158+
159+ return Request (
160+ method = request .method ,
161+ url = request .url ,
162+ headers = new_headers ,
163+ content = new_content ,
164+ extensions = request .extensions
165+ )
0 commit comments