[Bug]: XHR PUT FormData postData is null
Version
latest
Steps to reproduce
cant get content of file uploaded
Expected behavior
get asdasdasd in post_data
Actual behavior
in pyptteer i can get this content with
await cdp.send("Network.enable", {
# Buffer up to 10 MB of POST/PUT data
"maxPostDataSize": 0
})
async def on_request_will_be_sent(params):
try:
req = params["request"]
if req.get("method") == "PUT" and "/api/file/raw" in req.get("url", ""):
request_id = params["requestId"]
# Ask Chrome: “Please give me the POST/PUT payload that you buffered.”
resp = await cdp.send(
"Network.getRequestPostData",
{"requestId": request_id}
)
body = resp.get("postData", None)
print("→ Caught PUT to /api/file/raw via Network:")
print(" • request.postData →", body)
# If you want bytes instead of a string, do:
# raw_bytes = body.encode("utf-8")
# print(" • as bytes:", raw_bytes)
except Exception as e:
# If "No post data available" still shows up, check that `maxPostDataSize` was set early enough.
print("ERROR in on_request_will_be_sent:", e)
cdp.on("Network.requestWillBeSent", lambda event: asyncio.create_task(on_request_will_be_sent(event)))
Additional context
No response
Environment
- Operating System: [Ubuntu 22.04]
- CPU: [arm64]
- Browser: [All, Chromium, Firefox, WebKit]
- Python Version: [3.12]
- Other info:
Playwright supports this out of the box: https://playwright.dev/python/docs/api/class-request#request-post-data
def handle_request(request):
print(">>", request.method, request.url)
print(request.post_data)
page.on("request", handle_request)
this not give me content . request.post_data = empty string or mutipart/data without content
Would it be possible to share a repro?
upload file "a.txt" and not see content but if use burp or pyppteer or other tool you will get content
import asyncio
from playwright.async_api import async_playwright
def handle_request(request):
print(">>", request.method, request.url)
print(request.post_data)
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False, channel="chrome") # Set headless=False if you want to see the browser
page = await browser.new_page()
# Navigate to the login page
await page.goto("https://brokencrystals.com/userlogin")
# Fill in the email and password inputs
await page.fill("#email", "admin")
await page.fill("#password", "admin")
# Click the submit button (assuming it’s a <button type="submit">)
await page.click("button[type='submit']")
# Optionally wait for navigation or some selector that appears after login
await page.wait_for_load_state("networkidle")
await page.click("#header > div > div > div > nav > ul > li:nth-child(2) > a")
await asyncio.sleep(1)
page.on("request", handle_request)
await page.set_input_files("#file-input", "a.txt")
await page.set_input_files("#feedback-file-input","a.txt")
# Do other actions here, or close the browser
await browser.close()
if __name__ == "__main__":
asyncio.run(main())
I can reproduce using the following:
it('should return post data for PUT requests with XHR', async ({ page, server }) => {
await page.goto(server.EMPTY_PAGE);
const [request] = await Promise.all([
page.waitForRequest('**'),
page.evaluate(({ url }) => {
return new Promise<void>(resolve => {
const xhr = new XMLHttpRequest();
xhr.open('PUT', url);
xhr.onload = () => resolve();
const payload = new FormData();
const file = new Blob(['hello'], { type: 'text/plain' });
payload.append('value', file);
xhr.send(payload);
});
}, { url: server.PREFIX + '/title.html' })
]);
expect(request.postData()).toContain('hello');
});
Looks like Chromium does not send anything back in the protocol.
Related issue: https://github.com/microsoft/playwright/issues/6479
a.txt not empty file
`import asyncio from playwright.async_api import async_playwright
def handle_request(request): print(">>", request.method, request.url) print(request.post_data)
async def main(): async with async_playwright() as p: browser = await p.chromium.launch(headless=False, channel="chrome") context = await browser.new_context() page = await context.new_page()
# 1) Create a CDP session for this page
client = await context.new_cdp_session(page) # :contentReference[oaicite:0]{index=0}
# 2) Enable Network so we'll get request events
await client.send("Network.enable", {"maxPostDataSize": 0})
# 3) Listen for the first request and grab its requestId
async def on_request_will_be_sent(params):
# you can add filtering here if you only care about specific URLs
try:
request_id = params["requestId"]
result = await client.send(
"Network.getRequestPostData",
{"requestId": request_id}
)
if result:
print(result.items())
print("Post data:", result.get("postData"))
except Exception as e:
pass
client.on("Network.requestWillBeSent", on_request_will_be_sent)
# Now drive your page so that a POST happens...
await page.goto("https://brokencrystals.com/userlogin")
await page.fill("#email", "admin")
await page.fill("#password", "admin")
await page.click("button[type='submit']")
await page.wait_for_load_state("networkidle")
# Navigate to the upload form (adjust selector as needed)
await page.click("#header > div > div > div > nav > ul > li:nth-child(2) > a")
await asyncio.sleep(1)
page.on("request", handle_request)
await page.set_input_files("#file-input", "a.txt")
# Trigger the multipart/form-data or JSON POST
await page.set_input_files("#feedback-file-input","a.txt")
# give the CDP event loop a moment
await asyncio.sleep(1)
await browser.close()
if name == "main": asyncio.run(main()) `
result :
`dict_items([('postData', '{"user":"admin","password":"admin","op":"basic"}')])
Post data: {"user":"admin","password":"admin","op":"basic"}
dict_items([('postData', ' ]>
PUT https://brokencrystals.com/api/users/one/admin/photo None dict_items([('postData', '------WebKitFormBoundaryPtsuD1pJpZxeQqTs\r\nContent-Disposition: form-data; name="admin"; filename="a.txt"\r\nContent-Type: text/plain\r\n\r\n\r\n------WebKitFormBoundaryPtsuD1pJpZxeQqTs--\r\n')]) Post data: ------WebKitFormBoundaryPtsuD1pJpZxeQqTs Content-Disposition: form-data; name="admin"; filename="a.txt" Content-Type: text/plain
------WebKitFormBoundaryPtsuD1pJpZxeQqTs--
PUT https://brokencrystals.com/api/file/raw?path=a.txt None GET https://brokencrystals.com/api/users/one/admin/photo None
Process finished with exit code 0`
Folding into https://github.com/microsoft/playwright/issues/6479