Skip to content

Commit 3bd3d8a

Browse files
authored
fix(fetch): send empty form and multipart bodies (#3239)
1 parent ae494b2 commit 3bd3d8a

3 files changed

Lines changed: 50 additions & 3 deletions

File tree

‎playwright/_impl/_fetch.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ async def _inner_fetch(
427427
raise Error(str(e)) from None
428428
else:
429429
raise Error(f"Unsupported 'data' type: {type(data)}")
430-
elif form:
430+
elif form is not None:
431431
if isinstance(form, FormData):
432432
form_data = []
433433
for fd_name, fd_value in form._fields:
@@ -437,8 +437,8 @@ async def _inner_fetch(
437437
)
438438
form_data.append(NameValue(name=fd_name, value=str(fd_value)))
439439
else:
440-
form_data = object_to_array(form)
441-
elif multipart:
440+
form_data = object_to_array(form) or []
441+
elif multipart is not None:
442442
multipart_data = []
443443
if isinstance(multipart, FormData):
444444
for fd_name, fd_value in multipart._fields:

‎tests/async/test_fetch_browser_context.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,31 @@ async def test_should_support_multipart_form_data(
365365
assert request.args[b"file"][0] == file["buffer"]
366366

367367

368+
async def test_should_send_empty_form(context: BrowserContext, server: Server) -> None:
369+
[request, _] = await asyncio.gather(
370+
server.wait_for_request("/empty.html"),
371+
context.request.post(server.EMPTY_PAGE, form={}),
372+
)
373+
assert request.getHeader("Content-Type") == "application/x-www-form-urlencoded"
374+
assert request.getHeader("Content-Length") == "0"
375+
376+
377+
async def test_should_send_empty_multipart(
378+
context: BrowserContext, server: Server
379+
) -> None:
380+
# The test server rejects an empty multipart body in POST requests before handling them.
381+
[request, _] = await asyncio.gather(
382+
server.wait_for_request("/empty.html"),
383+
context.request.put(server.EMPTY_PAGE, multipart={}),
384+
)
385+
assert cast(str, request.getHeader("Content-Type")).startswith(
386+
"multipart/form-data; "
387+
)
388+
assert must(request.getHeader("Content-Length")) == str(
389+
len(must(request.post_body))
390+
)
391+
392+
368393
async def test_should_support_form_data_with_repeated_keys(
369394
context: BrowserContext, server: Server
370395
) -> None:

‎tests/sync/test_fetch_browser_context.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,28 @@ def test_should_support_multipart_form_data(
288288
assert server_req.value.args[b"file"][0] == file["buffer"]
289289

290290

291+
def test_should_send_empty_form(context: BrowserContext, server: Server) -> None:
292+
with server.expect_request("/empty.html") as server_req:
293+
context.request.post(server.EMPTY_PAGE, form={})
294+
assert (
295+
server_req.value.getHeader("Content-Type")
296+
== "application/x-www-form-urlencoded"
297+
)
298+
assert server_req.value.getHeader("Content-Length") == "0"
299+
300+
301+
def test_should_send_empty_multipart(context: BrowserContext, server: Server) -> None:
302+
# The test server rejects an empty multipart body in POST requests before handling them.
303+
with server.expect_request("/empty.html") as server_req:
304+
context.request.put(server.EMPTY_PAGE, multipart={})
305+
content_type = server_req.value.getHeader("Content-Type")
306+
assert content_type
307+
assert content_type.startswith("multipart/form-data; ")
308+
assert server_req.value.getHeader("Content-Length") == str(
309+
len(must(server_req.value.post_body))
310+
)
311+
312+
291313
def test_should_support_form_data_with_repeated_keys(
292314
context: BrowserContext, server: Server
293315
) -> None:

0 commit comments

Comments
 (0)