Skip to content

Commit c8379d6

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

File tree

2 files changed

+46
-18
lines changed

2 files changed

+46
-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

+29-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ 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 {
10+
addMiddlewareHeaders,
11+
isMiddlewareRequest,
12+
isMiddlewareResponse,
13+
mergeMiddlewareCookies,
14+
} from './middleware.ts'
1015
import { RequestData } from './next-request.ts'
1116
import {
1217
addBasePath,
@@ -116,12 +121,13 @@ export const buildResponse = async ({
116121
}
117122
return rewriter.transform(response.originResponse)
118123
}
119-
const res = new Response(result.response.body, result.response)
124+
125+
const edgeResponse = new Response(result.response.body, result.response)
120126
request.headers.set('x-nf-next-middleware', 'skip')
121127

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')
128+
let rewrite = edgeResponse.headers.get('x-middleware-rewrite')
129+
let redirect = edgeResponse.headers.get('location')
130+
let nextRedirect = edgeResponse.headers.get('x-nextjs-redirect')
125131

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

155-
res.headers.set('x-nextjs-rewrite', relativeUrl)
161+
edgeResponse.headers.set('x-nextjs-rewrite', relativeUrl)
156162
}
157163

158164
if (rewriteUrl.origin !== baseUrl.origin) {
@@ -178,7 +184,7 @@ export const buildResponse = async ({
178184
})
179185
}
180186

181-
return addMiddlewareHeaders(fetch(proxyRequest, { redirect: 'manual' }), res)
187+
return addMiddlewareHeaders(fetch(proxyRequest, { redirect: 'manual' }), edgeResponse)
182188
}
183189

184190
if (isDataReq) {
@@ -197,9 +203,9 @@ export const buildResponse = async ({
197203
logger.withFields({ rewrite_url: rewrite }).debug('Rewrite url is same as original url')
198204
return
199205
}
200-
res.headers.set('x-middleware-rewrite', relativeUrl)
206+
edgeResponse.headers.set('x-middleware-rewrite', relativeUrl)
201207
request.headers.set('x-middleware-rewrite', target)
202-
return addMiddlewareHeaders(context.rewrite(target), res)
208+
return addMiddlewareHeaders(context.rewrite(target), edgeResponse)
203209
}
204210

205211
if (redirect) {
@@ -208,27 +214,32 @@ export const buildResponse = async ({
208214
logger.withFields({ redirect_url: redirect }).debug('Redirect url is same as original url')
209215
return
210216
}
211-
res.headers.set('location', redirect)
217+
edgeResponse.headers.set('location', redirect)
212218
}
213219

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

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

222228
if (nextRedirect && isDataReq) {
223-
res.headers.set('x-nextjs-redirect', normalizeDataUrl(nextRedirect))
229+
edgeResponse.headers.set('x-nextjs-redirect', normalizeDataUrl(nextRedirect))
224230
}
225231

226-
if (res.headers.get('x-middleware-next') === '1') {
227-
res.headers.delete('x-middleware-next')
228-
return addMiddlewareHeaders(context.next(), res)
232+
if (edgeResponse.headers.get('x-middleware-next') === '1') {
233+
edgeResponse.headers.delete('x-middleware-next')
234+
235+
// coookies set in middleware need to be available during the lambda request
236+
const newRequest = new Request(request)
237+
newRequest.headers.set('Cookie', mergeMiddlewareCookies(edgeResponse, newRequest))
238+
239+
return addMiddlewareHeaders(context.next(newRequest), edgeResponse)
229240
}
230241

231-
return res
242+
return edgeResponse
232243
}
233244

234245
/**

0 commit comments

Comments
 (0)