1717import inspect
1818import json
1919import mimetypes
20+ import sys
2021from collections import defaultdict
2122from pathlib import Path
2223from types import SimpleNamespace
3132 Union ,
3233 cast ,
3334)
35+
36+ if sys .version_info >= (3 , 8 ): # pragma: no cover
37+ from typing import TypedDict
38+ else : # pragma: no cover
39+ from typing_extensions import TypedDict
3440from urllib import parse
3541
3642from playwright ._impl ._api_structures import (
4854 from_nullable_channel ,
4955)
5056from playwright ._impl ._event_context_manager import EventContextManagerImpl
51- from playwright ._impl ._helper import FallbackOverrideParameters , locals_to_params
57+ from playwright ._impl ._helper import locals_to_params
5258from playwright ._impl ._wait_helper import WaitHelper
5359
5460if TYPE_CHECKING : # pragma: no cover
5763 from playwright ._impl ._page import Page
5864
5965
66+ class FallbackOverrideParameters (TypedDict , total = False ):
67+ url : Optional [str ]
68+ method : Optional [str ]
69+ headers : Optional [Dict [str , str ]]
70+ postData : Optional [Union [str , bytes ]]
71+
72+
73+ class SerializedFallbackOverrides :
74+ def __init__ (self ) -> None :
75+ self .url : Optional [str ] = None
76+ self .method : Optional [str ] = None
77+ self .headers : Optional [Dict [str , str ]] = None
78+ self .post_data_buffer : Optional [bytes ] = None
79+
80+
6081def serialize_headers (headers : Dict [str , str ]) -> HeadersArray :
6182 return [
6283 {"name" : name , "value" : value }
@@ -90,31 +111,47 @@ def __init__(
90111 }
91112 self ._provisional_headers = RawHeaders (self ._initializer ["headers" ])
92113 self ._all_headers_future : Optional [asyncio .Future [RawHeaders ]] = None
93- self ._fallback_overrides : FallbackOverrideParameters = (
94- FallbackOverrideParameters ()
114+ self ._fallback_overrides : SerializedFallbackOverrides = (
115+ SerializedFallbackOverrides ()
95116 )
117+ base64_post_data = initializer .get ("postData" )
118+ if base64_post_data is not None :
119+ self ._fallback_overrides .post_data_buffer = base64 .b64decode (
120+ base64_post_data
121+ )
96122
97123 def __repr__ (self ) -> str :
98124 return f"<Request url={ self .url !r} method={ self .method !r} >"
99125
100126 def _apply_fallback_overrides (self , overrides : FallbackOverrideParameters ) -> None :
101- self ._fallback_overrides = cast (
102- FallbackOverrideParameters , { ** self ._fallback_overrides , ** overrides }
127+ self ._fallback_overrides . url = overrides . get (
128+ "url" , self ._fallback_overrides . url
103129 )
130+ self ._fallback_overrides .method = overrides .get (
131+ "method" , self ._fallback_overrides .method
132+ )
133+ self ._fallback_overrides .headers = overrides .get (
134+ "headers" , self ._fallback_overrides .headers
135+ )
136+ post_data = overrides .get ("postData" )
137+ if isinstance (post_data , str ):
138+ self ._fallback_overrides .post_data_buffer = post_data .encode ()
139+ elif isinstance (post_data , bytes ):
140+ self ._fallback_overrides .post_data_buffer = post_data
141+ elif post_data is not None :
142+ self ._fallback_overrides .post_data_buffer = json .dumps (post_data ).encode ()
104143
105144 @property
106145 def url (self ) -> str :
107- return cast (str , self ._fallback_overrides .get ( " url" , self ._initializer ["url" ]) )
146+ return cast (str , self ._fallback_overrides .url or self ._initializer ["url" ])
108147
109148 @property
110149 def resource_type (self ) -> str :
111150 return self ._initializer ["resourceType" ]
112151
113152 @property
114153 def method (self ) -> str :
115- return cast (
116- str , self ._fallback_overrides .get ("method" , self ._initializer ["method" ])
117- )
154+ return cast (str , self ._fallback_overrides .method or self ._initializer ["method" ])
118155
119156 async def sizes (self ) -> RequestSizes :
120157 response = await self .response ()
@@ -124,7 +161,7 @@ async def sizes(self) -> RequestSizes:
124161
125162 @property
126163 def post_data (self ) -> Optional [str ]:
127- data = self ._fallback_overrides .get ( "postData" , self . post_data_buffer )
164+ data = self ._fallback_overrides .post_data_buffer
128165 if not data :
129166 return None
130167 return data .decode () if isinstance (data , bytes ) else data
@@ -144,17 +181,7 @@ def post_data_json(self) -> Optional[Any]:
144181
145182 @property
146183 def post_data_buffer (self ) -> Optional [bytes ]:
147- override = self ._fallback_overrides .get ("post_data" )
148- if override :
149- return (
150- override .encode ()
151- if isinstance (override , str )
152- else cast (bytes , override )
153- )
154- b64_content = self ._initializer .get ("postData" )
155- if b64_content is None :
156- return None
157- return base64 .b64decode (b64_content )
184+ return self ._fallback_overrides .post_data_buffer
158185
159186 async def response (self ) -> Optional ["Response" ]:
160187 return from_nullable_channel (await self ._channel .send ("response" ))
@@ -189,7 +216,7 @@ def _set_response_end_timing(self, response_end_timing: float) -> None:
189216
190217 @property
191218 def headers (self ) -> Headers :
192- override = self ._fallback_overrides .get ( " headers" )
219+ override = self ._fallback_overrides .headers
193220 if override :
194221 return RawHeaders ._from_headers_dict_lossy (override ).headers ()
195222 return self ._provisional_headers .headers ()
@@ -204,7 +231,7 @@ async def header_value(self, name: str) -> Optional[str]:
204231 return (await self ._actual_headers ()).get (name )
205232
206233 async def _actual_headers (self ) -> "RawHeaders" :
207- override = self ._fallback_overrides .get ( " headers" )
234+ override = self ._fallback_overrides .headers
208235 if override :
209236 return RawHeaders (serialize_headers (override ))
210237 if not self ._all_headers_future :
@@ -254,6 +281,7 @@ async def fulfill(
254281 status : int = None ,
255282 headers : Dict [str , str ] = None ,
256283 body : Union [str , bytes ] = None ,
284+ json : Any = None ,
257285 path : Union [str , Path ] = None ,
258286 contentType : str = None ,
259287 response : "APIResponse" = None ,
@@ -270,6 +298,8 @@ async def fulfill(
270298 )
271299 from playwright ._impl ._fetch import APIResponse
272300
301+ if json is not None :
302+ body = json .dumps (json )
273303 if body is None and path is None and isinstance (response , APIResponse ):
274304 if response ._request ._connection is self ._connection :
275305 params ["fetchResponseUid" ] = response ._fetch_uid
@@ -295,6 +325,8 @@ async def fulfill(
295325 headers = {k .lower (): str (v ) for k , v in params .get ("headers" , {}).items ()}
296326 if params .get ("contentType" ):
297327 headers ["content-type" ] = params ["contentType" ]
328+ elif json :
329+ headers ["content-type" ] = "application/json"
298330 elif path :
299331 headers ["content-type" ] = (
300332 mimetypes .guess_type (str (Path (path )))[0 ] or "application/octet-stream"
@@ -305,12 +337,24 @@ async def fulfill(
305337 await self ._race_with_page_close (self ._channel .send ("fulfill" , params ))
306338 self ._report_handled (True )
307339
340+ async def fetch (
341+ self ,
342+ url : str = None ,
343+ method : str = None ,
344+ headers : Dict [str , str ] = None ,
345+ postData : Union [Any , str , bytes ] = None ,
346+ ) -> "APIResponse" :
347+ page = self .request .frame ._page
348+ return await page .context .request ._inner_fetch (
349+ self .request , url , method , headers , postData
350+ )
351+
308352 async def fallback (
309353 self ,
310354 url : str = None ,
311355 method : str = None ,
312356 headers : Dict [str , str ] = None ,
313- postData : Union [str , bytes ] = None ,
357+ postData : Union [Any , str , bytes ] = None ,
314358 ) -> None :
315359 overrides = cast (FallbackOverrideParameters , locals_to_params (locals ()))
316360 self ._check_not_handled ()
@@ -322,7 +366,7 @@ async def continue_(
322366 url : str = None ,
323367 method : str = None ,
324368 headers : Dict [str , str ] = None ,
325- postData : Union [str , bytes ] = None ,
369+ postData : Union [Any , str , bytes ] = None ,
326370 ) -> None :
327371 overrides = cast (FallbackOverrideParameters , locals_to_params (locals ()))
328372 self ._check_not_handled ()
@@ -335,23 +379,18 @@ def _internal_continue(
335379 ) -> Coroutine [Any , Any , None ]:
336380 async def continue_route () -> None :
337381 try :
338- post_data_for_wire : Optional [str ] = None
339- post_data_from_overrides = self .request ._fallback_overrides .get (
340- "postData"
341- )
342- if post_data_from_overrides is not None :
343- post_data_for_wire = (
344- base64 .b64encode (post_data_from_overrides .encode ()).decode ()
345- if isinstance (post_data_from_overrides , str )
346- else base64 .b64encode (post_data_from_overrides ).decode ()
347- )
348- params = locals_to_params (
349- cast (Dict [str , str ], self .request ._fallback_overrides )
350- )
382+ params : Dict [str , Any ] = {}
383+ params ["url" ] = self .request ._fallback_overrides .url
384+ params ["method" ] = self .request ._fallback_overrides .method
385+ params ["headers" ] = self .request ._fallback_overrides .headers
386+ if self .request ._fallback_overrides .post_data_buffer is not None :
387+ params ["postData" ] = base64 .b64encode (
388+ self .request ._fallback_overrides .post_data_buffer
389+ ).decode ()
390+ params = locals_to_params (params )
391+
351392 if "headers" in params :
352393 params ["headers" ] = serialize_headers (params ["headers" ])
353- if post_data_for_wire is not None :
354- params ["postData" ] = post_data_for_wire
355394 await self ._connection .wrap_api_call (
356395 lambda : self ._race_with_page_close (
357396 self ._channel .send (
0 commit comments