fix: disable Network buffering by default to fix SSE streaming
Fixes #22 CDP's Network.enable buffers response bodies by default, which breaks SSE/streaming - data arrives at Chrome but ReadableStream never receives it. Changes: - Intercept Network.enable in relay, default maxTotalBufferSize: 0 - Agents can re-enable buffering via Network.disable + Network.enable with explicit buffer sizes when they need response.body() - Added test and documentation for reading response bodies
This commit is contained in:
@@ -359,6 +359,23 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
||||
})
|
||||
}
|
||||
|
||||
// Network.enable: Default to zero buffering to fix SSE streaming issues.
|
||||
// CDP's Network domain buffers response bodies by default, which breaks ReadableStream
|
||||
// for SSE/streaming responses. Setting maxTotalBufferSize: 0 disables this buffering.
|
||||
// Agents can re-enable buffering by calling Network.disable then Network.enable with
|
||||
// explicit buffer sizes if they need to read response bodies via Network.getResponseBody.
|
||||
case 'Network.enable': {
|
||||
const modifiedParams = {
|
||||
maxTotalBufferSize: 0,
|
||||
maxResourceBufferSize: 0,
|
||||
...params
|
||||
}
|
||||
return await sendToExtension({
|
||||
method: 'forwardCDPCommand',
|
||||
params: { sessionId, method, params: modifiedParams }
|
||||
})
|
||||
}
|
||||
|
||||
case 'Runtime.enable': {
|
||||
if (!sessionId) {
|
||||
break
|
||||
|
||||
@@ -3668,6 +3668,56 @@ describe('Service Worker Target Tests', () => {
|
||||
await browser.close()
|
||||
await page.close()
|
||||
}, 60000)
|
||||
|
||||
it('should allow reading response bodies after re-enabling Network buffering', async () => {
|
||||
// By default, the relay sets maxTotalBufferSize: 0 to fix SSE streaming.
|
||||
// This test verifies that agents can re-enable buffering to read response bodies
|
||||
// using Playwright's response.body() API after re-enabling Network buffering via CDP.
|
||||
|
||||
const browserContext = getBrowserContext()
|
||||
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
||||
|
||||
const page = await browserContext.newPage()
|
||||
await page.goto('https://example.com/')
|
||||
await page.bringToFront()
|
||||
|
||||
await serviceWorker.evaluate(async () => {
|
||||
await globalThis.toggleExtensionForActiveTab()
|
||||
})
|
||||
await new Promise(r => setTimeout(r, 100))
|
||||
|
||||
const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }))
|
||||
const cdpPage = browser.contexts()[0].pages().find(p => p.url().includes('example.com'))
|
||||
expect(cdpPage).toBeDefined()
|
||||
|
||||
// Get CDP session to re-enable buffering (must use getCDPSessionForPage, not newCDPSession)
|
||||
const wsUrl = getCdpUrl({ port: TEST_PORT })
|
||||
const cdpSession = await getCDPSessionForPage({ page: cdpPage!, wsUrl })
|
||||
|
||||
// Re-enable Network domain with buffering to allow response.body() to work
|
||||
await cdpSession.send('Network.disable')
|
||||
await cdpSession.send('Network.enable', {
|
||||
maxTotalBufferSize: 10000000,
|
||||
maxResourceBufferSize: 5000000
|
||||
})
|
||||
|
||||
// Use Playwright's response API to capture and read response body
|
||||
const [response] = await Promise.all([
|
||||
cdpPage!.waitForResponse(resp => resp.url() === 'https://example.com/'),
|
||||
cdpPage!.goto('https://example.com/')
|
||||
])
|
||||
|
||||
// Now response.body() should work because we re-enabled buffering
|
||||
const body = await response.text()
|
||||
|
||||
expect(body).toBeDefined()
|
||||
expect(body).toContain('Example Domain')
|
||||
expect(body).toContain('</html>')
|
||||
|
||||
cdpSession.close()
|
||||
await browser.close()
|
||||
await page.close()
|
||||
}, 60000)
|
||||
})
|
||||
|
||||
describe('Auto-enable Tests', () => {
|
||||
|
||||
@@ -356,6 +356,31 @@ console.log(data);
|
||||
|
||||
Clean up listeners when done: `page.removeAllListeners('request'); page.removeAllListeners('response');`
|
||||
|
||||
## reading response bodies
|
||||
|
||||
By default, playwriter disables CDP response body buffering to ensure SSE streaming works properly. If you need to read response bodies (e.g., for HAR recording or inspecting API responses), re-enable buffering first:
|
||||
|
||||
```js
|
||||
// Get CDP session and re-enable Network buffering
|
||||
const cdp = await getCDPSession({ page });
|
||||
await cdp.send('Network.disable');
|
||||
await cdp.send('Network.enable', {
|
||||
maxTotalBufferSize: 10000000, // 10MB total buffer
|
||||
maxResourceBufferSize: 5000000 // 5MB per resource
|
||||
});
|
||||
|
||||
// Now use Playwright's response API - it will work because buffering is enabled
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse(resp => resp.url().includes('/api/data')),
|
||||
page.click('button.load-data')
|
||||
]);
|
||||
|
||||
const body = await response.text(); // or response.json(), response.body()
|
||||
console.log(body);
|
||||
```
|
||||
|
||||
**Note**: This may cause SSE/streaming responses to buffer. Only enable when you specifically need response bodies.
|
||||
|
||||
## capabilities
|
||||
|
||||
Examples of what playwriter can do:
|
||||
|
||||
Reference in New Issue
Block a user