Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure upgrade request has request meta #51590

Merged
merged 3 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 23 additions & 3 deletions packages/next/src/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,14 @@ export default class NextNodeServer extends BaseServer {
}

protected async handleUpgrade(req: NodeNextRequest, socket: any, head: any) {
await this.router.execute(req, socket, nodeParseUrl(req.url, true), head)
try {
const parsedUrl = nodeParseUrl(req.url, true)
this.attachRequestMeta(req, parsedUrl, true)
await this.router.execute(req, socket, parsedUrl, head)
} catch (err) {
console.error(err)
socket.end('Internal Server Error')
}
}

protected async proxyRequest(
Expand Down Expand Up @@ -1486,6 +1493,15 @@ export default class NextNodeServer extends BaseServer {
},
getRequestMeta(req, '__NEXT_CLONABLE_BODY')?.cloneBodyStream()
)

// if this is an upgrade request just pipe body back
if (!res.setHeader) {
invokeRes.pipe(res as any as ServerResponse)
return {
finished: true,
}
}

const noFallback = invokeRes.headers['x-no-fallback']

if (noFallback) {
Expand Down Expand Up @@ -2748,7 +2764,8 @@ export default class NextNodeServer extends BaseServer {

protected attachRequestMeta(
req: BaseNextRequest,
parsedUrl: NextUrlWithParsedQuery
parsedUrl: NextUrlWithParsedQuery,
isUpgradeReq?: boolean
) {
const protocol = (
(req as NodeNextRequest).originalRequest?.socket as TLSSocket
Expand All @@ -2767,7 +2784,10 @@ export default class NextNodeServer extends BaseServer {
addRequestMeta(req, '__NEXT_INIT_URL', initUrl)
addRequestMeta(req, '__NEXT_INIT_QUERY', { ...parsedUrl.query })
addRequestMeta(req, '_protocol', protocol)
addRequestMeta(req, '__NEXT_CLONABLE_BODY', getCloneableBody(req.body))

if (!isUpgradeReq) {
addRequestMeta(req, '__NEXT_CLONABLE_BODY', getCloneableBody(req.body))
}
}

protected async runEdgeFunction(params: {
Expand Down
4 changes: 4 additions & 0 deletions test/integration/custom-routes/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ module.exports = {
destination:
'http://localhost:__EXTERNAL_PORT__/_next/webpack-hmr?page=/about',
},
{
source: '/websocket-to-page',
destination: '/hello',
},
{
source: '/to-nowhere',
destination: 'http://localhost:12233',
Expand Down
32 changes: 32 additions & 0 deletions test/integration/custom-routes/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,33 @@ const runTests = (isDev = false, isTurbo = false) => {
expect([...externalServerHits]).toEqual(['/_next/webpack-hmr?page=/about'])
})

it('should successfully rewrite a WebSocket request to a page', async () => {
// TODO: remove once test failure has been fixed
if (isTurbo) return

const messages = []
try {
const ws = await new Promise((resolve, reject) => {
let socket = new WebSocket(
`ws://localhost:${appPort}/websocket-to-page`
)
socket.on('message', (data) => {
messages.push(data.toString())
})
socket.on('open', () => resolve(socket))
socket.on('error', (err) => {
console.error(err)
socket.close()
reject()
})
})
ws.close()
} catch (err) {
messages.push(err)
}
expect(stderr).not.toContain('unhandledRejection')
})

it('should not rewrite for _next/data route when a match is found', async () => {
const initial = await fetchViaHTTP(appPort, '/overridden/first')
expect(initial.status).toBe(200)
Expand Down Expand Up @@ -2210,6 +2237,11 @@ const runTests = (isDev = false, isTurbo = false) => {
regex: normalizeRegEx('^\\/to-websocket(?:\\/)?$'),
source: '/to-websocket',
},
{
destination: '/hello',
regex: normalizeRegEx('^\\/websocket-to-page(?:\\/)?$'),
source: '/websocket-to-page',
},
{
destination: 'http://localhost:12233',
regex: normalizeRegEx('^\\/to-nowhere(?:\\/)?$'),
Expand Down