Last active
July 6, 2023 20:24
-
-
Save aslushnikov/c3e9d7f2e0f931a52be1242ba81fadb6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pptr from 'puppeteer'; | |
import http from 'http'; | |
const createServer = (port, handler) => { | |
const server = http.createServer(handler); | |
return new Promise(x => server.listen(port, x)); | |
}; | |
// 1. Create a server that serves the main page. | |
// NOTE: this page will create an EventSource to the `/sse` endpoint, but this server DOES NOT | |
// accept requests to the URL. | |
await createServer(3000, (req, res) => { | |
if (req.url.startsWith('/sse')) | |
return res.end(503); | |
res.setHeader('content-type', 'text/html'); | |
res.end(` | |
<!doctype html> | |
<h1></h1> | |
<script type="text/javascript"> | |
const h1 = document.querySelector('h1'); | |
h1.textContent = 'sse: initializing...'; | |
const evtSource = new EventSource("/sse"); | |
evtSource.onerror = () => h1.textContent = 'sse: error'; | |
evtSource.onopen = () => h1.textContent = 'sse: opened'; | |
evtSource.onmessage = () => h1.textContent = 'sse: message received'; | |
</script> | |
`); | |
}); | |
// 2. Create another server that serves `/sse` endpoint. | |
await createServer(4321, (req, res) => { | |
res.statusCode = 200; | |
res.setHeader('Access-Control-Allow-Origin', '*'); | |
res.setHeader('Cache-Control', 'no-cache'); | |
res.setHeader('connection', 'keep-alive'); | |
res.setHeader('Content-Type', 'text/event-stream'); | |
res.write(`id: ${(new Date()).toLocaleTimeString()}\ndata: hello, world!\n\n`); | |
}); | |
// 3. Launch a browser and open a page. | |
const browser = await pptr.launch(); | |
const page = await browser.newPage(); | |
// 4. Setup request interception for the `/sse` URL to redirect request to the second server. | |
await page.setRequestInterception(true); | |
page.on('request', (request) => { | |
if (request.url().match(/sse/)) { | |
console.log('intercepted!', request.url()); | |
request.continue({ url: `http://localhost:4321/sse` }); | |
} else { | |
request.continue(); | |
} | |
}); | |
// 5. Navigate to the page from the first server. | |
// NOTE: The url has to have the query parameters to reproduce the bug; removing query params fixes the issue. | |
await page.goto(`http://localhost:3000?foo=bar`); | |
// 6. Expect the EventSource in the page to successfully connect. | |
// Actual: EventSource yields error when trying to connect | |
// Expected: EventSource connects and receives events just fine | |
await page.waitForSelector('h1'); | |
// Wait until H1 has a proper text value. | |
while (true) { | |
const header = await page.$eval('h1', el => el.textContent); | |
if (/message received/.test(header)) | |
break; | |
await new Promise(x => setTimeout(x, 1000)); | |
console.log(header); | |
} | |
await browser.close(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment