1+ import * as cookie from 'cookie' ;
2+ import * as set_cookie_parser from 'set-cookie-parser' ;
13import { normalize } from '../../load.js' ;
24import { respond } from '../index.js' ;
35import { is_root_relative , resolve } from '../../../utils/url.js' ;
46import { create_prerendering_url_proxy } from './utils.js' ;
57import { is_pojo , lowercase_keys , normalize_request_method } from '../utils.js' ;
68import { coalesce_to_error } from '../../../utils/error.js' ;
9+ import { domain_matches , path_matches } from './cookie.js' ;
710
811/**
912 * @param {{
@@ -41,10 +44,10 @@ export async function load_node({
4144 /** @type {Array<import('./types').Fetched> } */
4245 const fetched = [ ] ;
4346
44- /**
45- * @type { string[] }
46- */
47- let set_cookie_headers = [ ] ;
47+ const cookies = cookie . parse ( event . request . headers . get ( 'cookie' ) || '' ) ;
48+
49+ /** @type { import('set-cookie-parser').Cookie[] } */
50+ const new_cookies = [ ] ;
4851
4952 /** @type {import('types').LoadOutput } */
5053 let loaded ;
@@ -60,7 +63,9 @@ export async function load_node({
6063 : { } ;
6164
6265 if ( shadow . cookies ) {
63- set_cookie_headers . push ( ...shadow . cookies ) ;
66+ shadow . cookies . forEach ( ( header ) => {
67+ new_cookies . push ( set_cookie_parser . parseString ( header ) ) ;
68+ } ) ;
6469 }
6570
6671 if ( shadow . error ) {
@@ -166,9 +171,23 @@ export async function load_node({
166171 if ( opts . credentials !== 'omit' ) {
167172 uses_credentials = true ;
168173
169- const cookie = event . request . headers . get ( 'cookie' ) ;
170174 const authorization = event . request . headers . get ( 'authorization' ) ;
171175
176+ // combine cookies from the initiating request with any that were
177+ // added via set-cookie
178+ const combined_cookies = { ...cookies } ;
179+
180+ for ( const cookie of new_cookies ) {
181+ if ( ! domain_matches ( event . url . hostname , cookie . domain ) ) continue ;
182+ if ( ! path_matches ( resolved , cookie . path ) ) continue ;
183+
184+ combined_cookies [ cookie . name ] = cookie . value ;
185+ }
186+
187+ const cookie = Object . entries ( combined_cookies )
188+ . map ( ( [ name , value ] ) => `${ name } =${ value } ` )
189+ . join ( '; ' ) ;
190+
172191 if ( cookie ) {
173192 opts . headers . set ( 'cookie' , cookie ) ;
174193 }
@@ -231,6 +250,15 @@ export async function load_node({
231250 response = await options . hooks . externalFetch . call ( null , external_request ) ;
232251 }
233252
253+ const set_cookie = response . headers . get ( 'set-cookie' ) ;
254+ if ( set_cookie ) {
255+ new_cookies . push (
256+ ...set_cookie_parser
257+ . splitCookiesString ( set_cookie )
258+ . map ( ( str ) => set_cookie_parser . parseString ( str ) )
259+ ) ;
260+ }
261+
234262 const proxy = new Proxy ( response , {
235263 get ( response , key , _receiver ) {
236264 async function text ( ) {
@@ -239,9 +267,8 @@ export async function load_node({
239267 /** @type {import('types').ResponseHeaders } */
240268 const headers = { } ;
241269 for ( const [ key , value ] of response . headers ) {
242- if ( key === 'set-cookie' ) {
243- set_cookie_headers = set_cookie_headers . concat ( value ) ;
244- } else if ( key !== 'etag' ) {
270+ // TODO skip others besides set-cookie and etag?
271+ if ( key !== 'set-cookie' && key !== 'etag' ) {
245272 headers [ key ] = value ;
246273 }
247274 }
@@ -362,7 +389,11 @@ export async function load_node({
362389 loaded : normalize ( loaded ) ,
363390 stuff : loaded . stuff || stuff ,
364391 fetched,
365- set_cookie_headers,
392+ set_cookie_headers : new_cookies . map ( ( new_cookie ) => {
393+ const { name, value, ...options } = new_cookie ;
394+ // @ts -expect-error
395+ return cookie . serialize ( name , value , options ) ;
396+ } ) ,
366397 uses_credentials
367398 } ;
368399}
0 commit comments