@@ -198,6 +198,215 @@ describe('request utils', () => {
198
198
data : { xx : 'a' , yy : 'z' } ,
199
199
} ) ;
200
200
} ) ;
201
+
202
+ describe ( 'x-forwarded headers support' , ( ) => {
203
+ it ( 'should prioritize x-forwarded-proto header over explicit protocol parameter' , ( ) => {
204
+ const actual = httpRequestToRequestData ( {
205
+ url : '/test' ,
206
+ headers : {
207
+ host : 'example.com' ,
208
+ 'x-forwarded-proto' : 'https' ,
209
+ } ,
210
+ protocol : 'http' ,
211
+ } ) ;
212
+
213
+ expect ( actual ) . toEqual ( {
214
+ url : 'https://example.com/test' ,
215
+ headers : {
216
+ host : 'example.com' ,
217
+ 'x-forwarded-proto' : 'https' ,
218
+ } ,
219
+ } ) ;
220
+ } ) ;
221
+
222
+ it ( 'should prioritize x-forwarded-proto header even when downgrading from https to http' , ( ) => {
223
+ const actual = httpRequestToRequestData ( {
224
+ url : '/test' ,
225
+ headers : {
226
+ host : 'example.com' ,
227
+ 'x-forwarded-proto' : 'http' ,
228
+ } ,
229
+ protocol : 'https' ,
230
+ } ) ;
231
+
232
+ expect ( actual ) . toEqual ( {
233
+ url : 'http://example.com/test' ,
234
+ headers : {
235
+ host : 'example.com' ,
236
+ 'x-forwarded-proto' : 'http' ,
237
+ } ,
238
+ } ) ;
239
+ } ) ;
240
+
241
+ it ( 'should prioritize x-forwarded-proto header over socket encryption detection' , ( ) => {
242
+ const actual = httpRequestToRequestData ( {
243
+ url : '/test' ,
244
+ headers : {
245
+ host : 'example.com' ,
246
+ 'x-forwarded-proto' : 'https' ,
247
+ } ,
248
+ socket : {
249
+ encrypted : false ,
250
+ } ,
251
+ } ) ;
252
+
253
+ expect ( actual ) . toEqual ( {
254
+ url : 'https://example.com/test' ,
255
+ headers : {
256
+ host : 'example.com' ,
257
+ 'x-forwarded-proto' : 'https' ,
258
+ } ,
259
+ } ) ;
260
+ } ) ;
261
+
262
+ it ( 'should prioritize x-forwarded-host header over standard host header' , ( ) => {
263
+ const actual = httpRequestToRequestData ( {
264
+ url : '/test' ,
265
+ headers : {
266
+ host : 'localhost:3000' ,
267
+ 'x-forwarded-host' : 'example.com' ,
268
+ 'x-forwarded-proto' : 'https' ,
269
+ } ,
270
+ } ) ;
271
+
272
+ expect ( actual ) . toEqual ( {
273
+ url : 'https://example.com/test' ,
274
+ headers : {
275
+ host : 'localhost:3000' ,
276
+ 'x-forwarded-host' : 'example.com' ,
277
+ 'x-forwarded-proto' : 'https' ,
278
+ } ,
279
+ } ) ;
280
+ } ) ;
281
+
282
+ it ( 'should construct URL correctly when both x-forwarded-proto and x-forwarded-host are present' , ( ) => {
283
+ const actual = httpRequestToRequestData ( {
284
+ method : 'POST' ,
285
+ url : '/api/test?param=value' ,
286
+ headers : {
287
+ host : 'localhost:3000' ,
288
+ 'x-forwarded-host' : 'api.example.com' ,
289
+ 'x-forwarded-proto' : 'https' ,
290
+ 'content-type' : 'application/json' ,
291
+ } ,
292
+ protocol : 'http' ,
293
+ } ) ;
294
+
295
+ expect ( actual ) . toEqual ( {
296
+ method : 'POST' ,
297
+ url : 'https://api.example.com/api/test?param=value' ,
298
+ query_string : 'param=value' ,
299
+ headers : {
300
+ host : 'localhost:3000' ,
301
+ 'x-forwarded-host' : 'api.example.com' ,
302
+ 'x-forwarded-proto' : 'https' ,
303
+ 'content-type' : 'application/json' ,
304
+ } ,
305
+ } ) ;
306
+ } ) ;
307
+
308
+ it ( 'should fall back to standard headers when x-forwarded headers are not present' , ( ) => {
309
+ const actual = httpRequestToRequestData ( {
310
+ url : '/test' ,
311
+ headers : {
312
+ host : 'example.com' ,
313
+ } ,
314
+ protocol : 'https' ,
315
+ } ) ;
316
+
317
+ expect ( actual ) . toEqual ( {
318
+ url : 'https://example.com/test' ,
319
+ headers : {
320
+ host : 'example.com' ,
321
+ } ,
322
+ } ) ;
323
+ } ) ;
324
+
325
+ it ( 'should ignore x-forwarded headers when they contain non-string values' , ( ) => {
326
+ const actual = httpRequestToRequestData ( {
327
+ url : '/test' ,
328
+ headers : {
329
+ host : 'example.com' ,
330
+ 'x-forwarded-host' : [ 'forwarded.example.com' ] as any ,
331
+ 'x-forwarded-proto' : [ 'https' ] as any ,
332
+ } ,
333
+ protocol : 'http' ,
334
+ } ) ;
335
+
336
+ expect ( actual ) . toEqual ( {
337
+ url : 'http://example.com/test' ,
338
+ headers : {
339
+ host : 'example.com' ,
340
+ } ,
341
+ } ) ;
342
+ } ) ;
343
+
344
+ it ( 'should correctly transform localhost request to public URL using x-forwarded headers' , ( ) => {
345
+ const actual = httpRequestToRequestData ( {
346
+ method : 'GET' ,
347
+ url : '/' ,
348
+ headers : {
349
+ host : 'localhost:3000' ,
350
+ 'x-forwarded-proto' : 'https' ,
351
+ 'x-forwarded-host' : 'example.com' ,
352
+ } ,
353
+ } ) ;
354
+
355
+ expect ( actual ) . toEqual ( {
356
+ method : 'GET' ,
357
+ url : 'https://example.com/' ,
358
+ headers : {
359
+ host : 'localhost:3000' ,
360
+ 'x-forwarded-proto' : 'https' ,
361
+ 'x-forwarded-host' : 'example.com' ,
362
+ } ,
363
+ } ) ;
364
+ } ) ;
365
+
366
+ it ( 'should respect x-forwarded-proto even when it downgrades from encrypted socket' , ( ) => {
367
+ const actual = httpRequestToRequestData ( {
368
+ url : '/test' ,
369
+ headers : {
370
+ host : 'example.com' ,
371
+ 'x-forwarded-proto' : 'http' ,
372
+ } ,
373
+ socket : {
374
+ encrypted : true ,
375
+ } ,
376
+ } ) ;
377
+
378
+ expect ( actual ) . toEqual ( {
379
+ url : 'http://example.com/test' ,
380
+ headers : {
381
+ host : 'example.com' ,
382
+ 'x-forwarded-proto' : 'http' ,
383
+ } ,
384
+ } ) ;
385
+ } ) ;
386
+
387
+ it ( 'should preserve query parameters when constructing URL with x-forwarded headers' , ( ) => {
388
+ const actual = httpRequestToRequestData ( {
389
+ method : 'GET' ,
390
+ url : '/search?q=test&category=api' ,
391
+ headers : {
392
+ host : 'localhost:8080' ,
393
+ 'x-forwarded-host' : 'search.example.com' ,
394
+ 'x-forwarded-proto' : 'https' ,
395
+ } ,
396
+ } ) ;
397
+
398
+ expect ( actual ) . toEqual ( {
399
+ method : 'GET' ,
400
+ url : 'https://search.example.com/search?q=test&category=api' ,
401
+ query_string : 'q=test&category=api' ,
402
+ headers : {
403
+ host : 'localhost:8080' ,
404
+ 'x-forwarded-host' : 'search.example.com' ,
405
+ 'x-forwarded-proto' : 'https' ,
406
+ } ,
407
+ } ) ;
408
+ } ) ;
409
+ } ) ;
201
410
} ) ;
202
411
203
412
describe ( 'extractQueryParamsFromUrl' , ( ) => {
0 commit comments