Skip to content

Commit f73ce83

Browse files
committed
fix: allow cookies in middleware to be accessible during the same request
1 parent f9a5a34 commit f73ce83

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

edge-runtime/lib/middleware.ts

+17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Context } from '@netlify/edge-functions'
22

33
import type { ElementHandlers } from '../vendor/deno.land/x/[email protected]/src/index.ts'
4+
import { getCookies } from '../vendor/deno.land/[email protected]/http/cookie.ts'
45

56
type NextDataTransform = <T>(data: T) => T
67

@@ -58,3 +59,19 @@ export const addMiddlewareHeaders = async (
5859
})
5960
return response
6061
}
62+
63+
export function mergeMiddlewareCookies(middlewareResponse: Response, request: Request) {
64+
let mergedCookies = getCookies(request.headers)
65+
const middlewareCookies = middlewareResponse.headers.get('x-middleware-set-cookie') || ''
66+
const regex = new RegExp(/,(?!\s)/) // commas that are not followed by whitespace
67+
68+
middlewareCookies.split(regex).forEach((entry) => {
69+
const [cookie] = entry.split(';')
70+
const [name, value] = cookie.split('=')
71+
mergedCookies[name] = value
72+
})
73+
74+
return Object.entries(mergedCookies)
75+
.map(kv => kv.join('='))
76+
.join('; ')
77+
}

edge-runtime/lib/response.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66

77
import { updateModifiedHeaders } from './headers.ts'
88
import type { StructuredLogger } from './logging.ts'
9-
import { addMiddlewareHeaders, isMiddlewareRequest, isMiddlewareResponse } from './middleware.ts'
9+
import { addMiddlewareHeaders, isMiddlewareRequest, isMiddlewareResponse, mergeMiddlewareCookies } from './middleware.ts'
1010
import { RequestData } from './next-request.ts'
1111
import {
1212
addBasePath,
@@ -116,12 +116,13 @@ export const buildResponse = async ({
116116
}
117117
return rewriter.transform(response.originResponse)
118118
}
119-
const res = new Response(result.response.body, result.response)
119+
120+
const edgeResponse = new Response(result.response.body, result.response)
120121
request.headers.set('x-nf-next-middleware', 'skip')
121122

122-
let rewrite = res.headers.get('x-middleware-rewrite')
123-
let redirect = res.headers.get('location')
124-
let nextRedirect = res.headers.get('x-nextjs-redirect')
123+
let rewrite = edgeResponse.headers.get('x-middleware-rewrite')
124+
let redirect = edgeResponse.headers.get('location')
125+
let nextRedirect = edgeResponse.headers.get('x-nextjs-redirect')
125126

126127
// Data requests (i.e. requests for /_next/data ) need special handling
127128
const isDataReq = request.headers.has('x-nextjs-data')
@@ -152,7 +153,7 @@ export const buildResponse = async ({
152153
// Data requests might be rewritten to an external URL
153154
// This header tells the client router the redirect target, and if it's external then it will do a full navigation
154155

155-
res.headers.set('x-nextjs-rewrite', relativeUrl)
156+
edgeResponse.headers.set('x-nextjs-rewrite', relativeUrl)
156157
}
157158

158159
if (rewriteUrl.origin !== baseUrl.origin) {
@@ -178,7 +179,7 @@ export const buildResponse = async ({
178179
})
179180
}
180181

181-
return addMiddlewareHeaders(fetch(proxyRequest, { redirect: 'manual' }), res)
182+
return addMiddlewareHeaders(fetch(proxyRequest, { redirect: 'manual' }), edgeResponse)
182183
}
183184

184185
if (isDataReq) {
@@ -197,9 +198,9 @@ export const buildResponse = async ({
197198
logger.withFields({ rewrite_url: rewrite }).debug('Rewrite url is same as original url')
198199
return
199200
}
200-
res.headers.set('x-middleware-rewrite', relativeUrl)
201+
edgeResponse.headers.set('x-middleware-rewrite', relativeUrl)
201202
request.headers.set('x-middleware-rewrite', target)
202-
return addMiddlewareHeaders(context.rewrite(target), res)
203+
return addMiddlewareHeaders(context.rewrite(target), edgeResponse)
203204
}
204205

205206
if (redirect) {
@@ -208,27 +209,32 @@ export const buildResponse = async ({
208209
logger.withFields({ redirect_url: redirect }).debug('Redirect url is same as original url')
209210
return
210211
}
211-
res.headers.set('location', redirect)
212+
edgeResponse.headers.set('location', redirect)
212213
}
213214

214215
// Data requests shouldn't automatically redirect in the browser (they might be HTML pages): they're handled by the router
215216
if (redirect && isDataReq) {
216-
res.headers.delete('location')
217-
res.headers.set('x-nextjs-redirect', relativizeURL(redirect, request.url))
217+
edgeResponse.headers.delete('location')
218+
edgeResponse.headers.set('x-nextjs-redirect', relativizeURL(redirect, request.url))
218219
}
219220

220-
nextRedirect = res.headers.get('x-nextjs-redirect')
221+
nextRedirect = edgeResponse.headers.get('x-nextjs-redirect')
221222

222223
if (nextRedirect && isDataReq) {
223-
res.headers.set('x-nextjs-redirect', normalizeDataUrl(nextRedirect))
224+
edgeResponse.headers.set('x-nextjs-redirect', normalizeDataUrl(nextRedirect))
224225
}
225226

226-
if (res.headers.get('x-middleware-next') === '1') {
227-
res.headers.delete('x-middleware-next')
228-
return addMiddlewareHeaders(context.next(), res)
227+
if (edgeResponse.headers.get('x-middleware-next') === '1') {
228+
edgeResponse.headers.delete('x-middleware-next')
229+
230+
// coookies set in middleware need to be available during the lambda request
231+
const newRequest = new Request(request)
232+
newRequest.headers.set('Cookie', mergeMiddlewareCookies(edgeResponse, newRequest))
233+
234+
return addMiddlewareHeaders(context.next(newRequest), edgeResponse)
229235
}
230236

231-
return res
237+
return edgeResponse
232238
}
233239

234240
/**

0 commit comments

Comments
 (0)