From 14d45a859362b92ae3462a596c2a04853caef71f Mon Sep 17 00:00:00 2001 From: Yevhen Vydolob Date: Wed, 17 Nov 2021 10:04:53 +0200 Subject: [PATCH] Fix redirects in case of relative URL Signed-off-by: Yevhen Vydolob --- src/node/main.ts | 24 +++++++++++++++++++++--- src/test/test.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/node/main.ts b/src/node/main.ts index 9d398e3..86553c4 100644 --- a/src/node/main.ts +++ b/src/node/main.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Url, parse as parseUrl } from 'url'; +import { Url, parse as parseUrl, URL, format } from 'url'; import * as https from 'https'; import * as http from 'http'; import * as zlib from 'zlib'; @@ -57,6 +57,15 @@ export const xhr: XHRRequest = (options: XHROptions): Promise => { isCompleted = true; if (options.followRedirects > 0 && (res.statusCode >= 300 && res.statusCode <= 303 || res.statusCode === 307)) { let location = res.headers['location']; + if(location.startsWith('/')){ + let endpoint = parseUrl(options.url); + location = format({ + protocol: endpoint.protocol, + hostname: endpoint.hostname, + port: endpoint.port, + pathname: location + }); + } if (location) { let newOptions = { type: options.type, url: location, user: options.user, password: options.password, headers: options.headers, @@ -141,8 +150,17 @@ function request(options: XHROptions): Promise { let handler = (res: http.IncomingMessage) => { if (res.statusCode >= 300 && res.statusCode < 400 && options.followRedirects && options.followRedirects > 0 && res.headers['location']) { + let location = res.headers['location']; + if(location.startsWith('/')){ + location = format({ + protocol: endpoint.protocol, + hostname: endpoint.hostname, + port: endpoint.port, + pathname: location + }); + } c(request(assign({}, options, { - url: res.headers['location'], + url: location, followRedirects: options.followRedirects - 1 }))); } else { @@ -234,4 +252,4 @@ function getProxyAgent(rawRequestURL: string, options: ProxyOptions = {}): any { }; return requestURL.protocol === 'http:' ? createHttpProxyAgent(opts) : createHttpsProxyAgent(opts); -} \ No newline at end of file +} diff --git a/src/test/test.ts b/src/test/test.ts index 914c901..365c849 100644 --- a/src/test/test.ts +++ b/src/test/test.ts @@ -7,6 +7,7 @@ import { createServer, createSecureServer, createProxy, createSecureProxy } from import { AddressInfo } from 'net'; import { promises as fs } from 'fs'; import { join } from 'path'; +import { IncomingMessage, ServerResponse } from 'http'; test('text content', async t => { const testContent = JSON.stringify({ hello: 1, world: true}) @@ -82,4 +83,28 @@ test('proxy https to https', async t => { server.close(); proxy.close(); -}) \ No newline at end of file +}); + +test('relative redirect', async t => { + const server = await createServer(); + + server.on('request', (req:IncomingMessage, res: ServerResponse) => { + if(req.url.includes('/foo')) { + res.setHeader('Location', '/bar'); + res.statusCode = 301; + res.end(); + } + if(req.url.includes('/bar')){ + res.end('Bar'); + } + }); + + const serverAddress = server.address() as AddressInfo; + + const response = await xhr({ url: `http://${serverAddress.address}:${serverAddress.port}/foo` }); + + t.deepEqual(response.body.toString(), 'Bar'); + t.is(response.status, 200); + + server.close(); +});