@@ -69,14 +69,16 @@ internals.getResponse = async (request) => {
6969 : new URL ( request . app . storeUrl ) ;
7070
7171 const httpOpts = {
72- headers : {
73- ...internals . getHeaders ( request , { get_template_file : true , get_data_only : true } ) ,
74- host : staplerUrlObject . host ,
75- } ,
72+ headers : internals . buildReqHeaders ( {
73+ request,
74+ stencilOptions : { get_template_file : true , get_data_only : true } ,
75+ extraHeaders : { host : staplerUrlObject . host } ,
76+ } ) ,
7677 // Fetch will break if request body is Stream and server response is redirect,
7778 // so we need to read the data first and then send the request
7879 body : request . payload ? await readFromStream ( request . payload ) : request . payload ,
79- method : 'post' ,
80+ method : request . method ,
81+ redirect : 'manual' ,
8082 } ;
8183
8284 const url = Object . assign ( new URL ( request . url . toString ( ) ) , {
@@ -116,6 +118,8 @@ internals.getResponse = async (request) => {
116118
117119 const response = await fetch ( url , httpOpts ) ;
118120
121+ internals . processResHeaders ( response . headers ) ;
122+
119123 if ( response . status === 401 ) {
120124 return response ;
121125 }
@@ -124,13 +128,6 @@ internals.getResponse = async (request) => {
124128 throw new Error ( 'The BigCommerce server responded with a 500 error' ) ;
125129 }
126130
127- if ( response . headers . get ( 'set-cookie' ) ) {
128- response . headers . set (
129- 'set-cookie' ,
130- utils . stripDomainFromCookies ( response . headers . get ( 'set-cookie' ) ) ,
131- ) ;
132- }
133-
134131 // Response is a redirect
135132 if ( response . status >= 301 && response . status <= 303 ) {
136133 return internals . redirect ( response , request ) ;
@@ -163,32 +160,29 @@ internals.getResponse = async (request) => {
163160 * @returns {* }
164161 */
165162internals . parseResponse = async ( bcAppData , request , response , responseArgs ) => {
166- const configuration = await request . app . themeConfig . getConfig ( ) ;
167163 const { httpOpts, staplerUrlObject, url } = responseArgs ;
168164
169165 if ( typeof bcAppData !== 'object' || ! ( 'pencil_response' in bcAppData ) ) {
170166 response . headers . delete ( 'x-frame-options' ) ;
171167
172168 // this is a raw response not emitted by TemplateEngine
173- return new RawResponse (
174- bcAppData ,
175- _ . fromPairs ( response . headers . entries ( ) ) , // Transform fetch.Headers map to a plain object
176- response . status ,
177- ) ;
169+ return new RawResponse ( bcAppData , response . headers . raw ( ) , response . status ) ;
178170 }
179171
172+ const configuration = await request . app . themeConfig . getConfig ( ) ;
173+
180174 // If a remote call, no need to do a second call to get the data,
181175 // it has already come back
182176 if ( bcAppData . remote ) {
183177 return internals . getPencilResponse ( bcAppData , request , response , configuration ) ;
184178 }
185179
186- const resourcesConfig = internals . getResourceConfig ( bcAppData , request , configuration ) ;
187-
188- httpOpts . headers = {
189- ... internals . getHeaders ( request , { get_data_only : true } , resourcesConfig ) ,
190- host : staplerUrlObject . host ,
191- } ;
180+ httpOpts . headers = internals . buildReqHeaders ( {
181+ request ,
182+ stencilOptions : { get_data_only : true } ,
183+ stencilConfig : internals . getResourceConfig ( bcAppData , request , configuration ) ,
184+ extraHeaders : { host : staplerUrlObject . host } ,
185+ } ) ;
192186
193187 // create request signature for caching
194188 const httpOptsSignature = internals . sha1sum ( _ . omit ( httpOpts . headers , [ 'cookie' ] ) ) ;
@@ -204,31 +198,24 @@ internals.parseResponse = async (bcAppData, request, response, responseArgs) =>
204198 } else {
205199 response2 = await fetch ( url , httpOpts ) ;
206200
201+ internals . processResHeaders ( response2 . headers ) ;
202+
207203 // Response is a redirect
208204 if ( response2 . status >= 301 && response2 . status <= 303 ) {
209205 return internals . redirect ( response2 , request ) ;
210206 }
211207
212- // Response is bad
213208 if ( response2 . status === 500 ) {
214209 throw new Error ( 'The BigCommerce server responded with a 500 error' ) ;
215210 }
216211
217212 data = await response2 . json ( ) ;
218213
219- // Data response is bad
220214 if ( data . status && data . status === 500 ) {
221215 throw new Error ( 'The BigCommerce server responded with a 500 error' ) ;
222216 }
223217
224218 cache . put ( dataRequestSignature , { data, response2 } , internals . cacheTTL ) ;
225-
226- if ( response2 . headers . get ( 'set-cookie' ) ) {
227- response2 . headers . set (
228- 'set-cookie' ,
229- utils . stripDomainFromCookies ( response2 . headers . get ( 'set-cookie' ) ) ,
230- ) ;
231- }
232219 }
233220
234221 return internals . getPencilResponse ( data , request , response2 , configuration ) ;
@@ -298,22 +285,16 @@ internals.getResourceConfig = (data, request, configuration) => {
298285 * @returns {* }
299286 */
300287internals . redirect = async ( response , request ) => {
301- if ( ! response . headers . get ( 'location' ) ) {
288+ const location = response . headers . get ( 'location' ) ;
289+
290+ if ( ! location ) {
302291 throw new Error ( 'StatusCode is set to 30x but there is no location header to redirect to.' ) ;
303292 }
304293
305- const normalizedRedirectUrl = utils . normalizeRedirectUrl (
306- request ,
307- response . headers . get ( 'location' ) ,
308- ) ;
309- response . headers . set ( 'location' , normalizedRedirectUrl ) ;
294+ response . headers . set ( 'location' , utils . normalizeRedirectUrl ( request , location ) ) ;
310295
311296 // return a redirect response
312- return new RedirectResponse (
313- response . headers . get ( 'location' ) ,
314- _ . fromPairs ( response . headers . entries ( ) ) , // Transform fetch.Headers map to a plain object
315- response . status ,
316- ) ;
297+ return new RedirectResponse ( location , response . headers . raw ( ) , response . status ) ;
317298} ;
318299
319300/**
@@ -390,21 +371,30 @@ internals.getPencilResponse = (data, request, response, configuration) => {
390371 translations : data . translations ,
391372 method : request . method ,
392373 acceptLanguage : request . headers [ 'accept-language' ] ,
393- headers : _ . fromPairs ( response . headers . entries ( ) ) , // Transform fetch.Headers map to a plain object
374+ headers : response . headers . raw ( ) ,
394375 statusCode : response . status ,
395376 } ,
396377 internals . themeAssembler ,
397378 ) ;
398379} ;
399380
400381/**
401- * Generate and return headers
382+ * Get headers from request and return a new object with processed headers
402383 *
403- * @param {object } request
384+ * @param {object } request - Hapi request
385+ * @param {[string]: string } request.headers
386+ * @param {object } request.app
404387 * @param {object } [stencilOptions]
405388 * @param {object } [stencilConfig]
389+ * @param {object } [extraHeaders] - extra headers to add to the result
390+ * @returns {object }
406391 */
407- internals . getHeaders = ( request , stencilOptions = { } , stencilConfig ) => {
392+ internals . buildReqHeaders = ( {
393+ request,
394+ stencilOptions = { } ,
395+ stencilConfig = null ,
396+ extraHeaders = { } ,
397+ } ) => {
408398 // Merge in current stencil-options with passed in options
409399 const currentOptions = request . headers [ 'stencil-options' ]
410400 ? JSON . parse ( request . headers [ 'stencil-options' ] )
@@ -429,7 +419,23 @@ internals.getHeaders = (request, stencilOptions = {}, stencilConfig) => {
429419 headers [ 'stencil-store-url' ] = request . app . storeUrl ;
430420 }
431421
432- return { ...request . headers , ...headers } ;
422+ return { ...request . headers , ...headers , ...extraHeaders } ;
423+ } ;
424+
425+ /**
426+ * Process headers from Fetch response
427+ *
428+ * @param {Headers } headers
429+ * @returns {object }
430+ */
431+ internals . processResHeaders = ( headers ) => {
432+ if ( headers . get ( 'set-cookie' ) ) {
433+ // When there are several values for the same header headers.get() returns
434+ // an array joined with comma which is wrong for cookies, so we use the initial raw Array
435+ // https://github.com/node-fetch/node-fetch/issues/251#issuecomment-428143940
436+ // eslint-disable-next-line no-param-reassign
437+ headers . raw ( ) [ 'set-cookie' ] = utils . stripDomainFromCookies ( headers . raw ( ) [ 'set-cookie' ] ) ;
438+ }
433439} ;
434440
435441/**
0 commit comments