From 881392cfaf51f124d77c100249bbeb67e4b21047 Mon Sep 17 00:00:00 2001 From: Jack Tench Date: Thu, 13 Jul 2017 19:13:37 +0100 Subject: [PATCH 1/3] Add maxAge config option. If set, an Access-Control-Max-Age header with this value (in seconds) will be added. --- README.md | 2 ++ lib/cors-anywhere.js | 11 +++++++--- test/test.js | 52 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 11342f1..a5ec7f6 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ proxy requests. The following options are supported: Example: `["cookie"]` * dictionary of lowercase strings `setHeaders` - Set headers for the request (overwrites existing ones). Example: `{"x-powered-by": "CORS Anywhere"}` +* number `maxAge` - If set, an Access-Control-Max-Age header with this value (in seconds) will be added. + Example: `600` - Allow CORS preflight request to be cached by the browser for 10 minutes. * string `helpFile` - Set the help file (shown at the homepage). Example: `"myCustomHelpText.txt"` diff --git a/lib/cors-anywhere.js b/lib/cors-anywhere.js index d4ee6e2..2b7357f 100644 --- a/lib/cors-anywhere.js +++ b/lib/cors-anywhere.js @@ -50,8 +50,11 @@ function isValidHostName(hostname) { * @param headers {object} Response headers * @param request {ServerRequest} */ -function withCORS(headers, request) { +function withCORS(headers, request, maxAge) { headers['access-control-allow-origin'] = '*'; + if (maxAge) { + headers['access-control-max-age'] = maxAge; + } if (request.headers['access-control-request-method']) { headers['access-control-allow-methods'] = request.headers['access-control-request-method']; delete request.headers['access-control-request-method']; @@ -193,7 +196,7 @@ function onProxyResponse(proxy, proxyReq, proxyRes, req, res) { delete proxyRes.headers['set-cookie2']; proxyRes.headers['x-final-url'] = requestState.location.href; - withCORS(proxyRes.headers, req); + withCORS(proxyRes.headers, req, requestState.maxAge); return true; } @@ -234,6 +237,7 @@ function getHandler(options, proxy) { requireHeader: null, // Require a header to be set? removeHeaders: [], // Strip these request headers. setHeaders: {}, // Set these request headers. + maxAge: null, // If set, an Access-Control-Max-Age header with this value (in seconds) will be added. helpFile: __dirname + '/help.txt', }; @@ -262,7 +266,7 @@ function getHandler(options, proxy) { }; return function(req, res) { - var cors_headers = withCORS({}, req); + var cors_headers = withCORS({}, req, corsAnywhere.maxAge); if (req.method === 'OPTIONS') { // Pre-flight request. Reply successfully: res.writeHead(200, cors_headers); @@ -353,6 +357,7 @@ function getHandler(options, proxy) { location: location, getProxyForUrl: corsAnywhere.getProxyForUrl, maxRedirects: corsAnywhere.maxRedirects, + maxAge: corsAnywhere.maxAge, proxyBaseUrl: proxyBaseUrl, }; diff --git a/test/test.js b/test/test.js index 910f4b7..086ba47 100644 --- a/test/test.js +++ b/test/test.js @@ -810,6 +810,58 @@ describe('setHeaders + removeHeaders', function() { }); }); +describe('Access-Control-Max-Age set', function() { + before(function() { + cors_anywhere = createServer({ + maxAge: 600, + }); + cors_anywhere_port = cors_anywhere.listen(0).address().port; + }); + after(stopServer); + + it('GET /', function(done) { + request(cors_anywhere) + .get('/') + .type('text/plain') + .expect('Access-Control-Allow-Origin', '*') + .expect('Access-Control-Max-Age', '600') + .expect(200, helpText, done); + }); + + it('GET /example.com', function(done) { + request(cors_anywhere) + .get('/example.com') + .expect('Access-Control-Allow-Origin', '*') + .expect('Access-Control-Max-Age', '600') + .expect(200, 'Response from example.com', done);; + }); +}); + +describe('Access-Control-Max-Age not set', function() { + before(function() { + cors_anywhere = createServer(); + cors_anywhere_port = cors_anywhere.listen(0).address().port; + }); + after(stopServer); + + it('GET /', function(done) { + request(cors_anywhere) + .get('/') + .type('text/plain') + .expect('Access-Control-Allow-Origin', '*') + .expectNoHeader('Access-Control-Max-Age') + .expect(200, helpText, done); + }); + + it('GET /example.com', function(done) { + request(cors_anywhere) + .get('/example.com') + .expect('Access-Control-Allow-Origin', '*') + .expectNoHeader('Access-Control-Max-Age') + .expect(200, 'Response from example.com', done); + }); +}); + describe('httpProxyOptions.xfwd=false', function() { before(function() { cors_anywhere = createServer({ From 10df7c9f4a2b1d1c547760d383e314719eeb2b74 Mon Sep 17 00:00:00 2001 From: Jack Tench Date: Fri, 14 Jul 2017 12:29:15 +0100 Subject: [PATCH 2/3] Rename maxAge to corsMaxAge and set the default corsMaxAge to 0. Set corsAnywhereRequestState before calling withCORS and use the state instead of a parameter to get corsMaxAge. --- README.md | 3 ++- lib/cors-anywhere.js | 28 +++++++++++++++------------- test/test.js | 10 +++++++--- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a5ec7f6..6cfff53 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,8 @@ proxy requests. The following options are supported: Example: `["cookie"]` * dictionary of lowercase strings `setHeaders` - Set headers for the request (overwrites existing ones). Example: `{"x-powered-by": "CORS Anywhere"}` -* number `maxAge` - If set, an Access-Control-Max-Age header with this value (in seconds) will be added. +* number `corsMaxAge` - If set, an Access-Control-Max-Age request header with this value (in seconds) will be added. + Defaults to 0. Example: `600` - Allow CORS preflight request to be cached by the browser for 10 minutes. * string `helpFile` - Set the help file (shown at the homepage). Example: `"myCustomHelpText.txt"` diff --git a/lib/cors-anywhere.js b/lib/cors-anywhere.js index 2b7357f..ccdc8ed 100644 --- a/lib/cors-anywhere.js +++ b/lib/cors-anywhere.js @@ -50,10 +50,11 @@ function isValidHostName(hostname) { * @param headers {object} Response headers * @param request {ServerRequest} */ -function withCORS(headers, request, maxAge) { +function withCORS(headers, request) { headers['access-control-allow-origin'] = '*'; - if (maxAge) { - headers['access-control-max-age'] = maxAge; + var corsMaxAge = request.corsAnywhereRequestState.corsMaxAge; + if (corsMaxAge != null) { + headers['access-control-max-age'] = corsMaxAge; } if (request.headers['access-control-request-method']) { headers['access-control-allow-methods'] = request.headers['access-control-request-method']; @@ -196,7 +197,7 @@ function onProxyResponse(proxy, proxyReq, proxyRes, req, res) { delete proxyRes.headers['set-cookie2']; proxyRes.headers['x-final-url'] = requestState.location.href; - withCORS(proxyRes.headers, req, requestState.maxAge); + withCORS(proxyRes.headers, req); return true; } @@ -237,7 +238,7 @@ function getHandler(options, proxy) { requireHeader: null, // Require a header to be set? removeHeaders: [], // Strip these request headers. setHeaders: {}, // Set these request headers. - maxAge: null, // If set, an Access-Control-Max-Age header with this value (in seconds) will be added. + corsMaxAge: 0, // If set, an Access-Control-Max-Age header with this value (in seconds) will be added. helpFile: __dirname + '/help.txt', }; @@ -266,7 +267,13 @@ function getHandler(options, proxy) { }; return function(req, res) { - var cors_headers = withCORS({}, req, corsAnywhere.maxAge); + req.corsAnywhereRequestState = { + getProxyForUrl: corsAnywhere.getProxyForUrl, + maxRedirects: corsAnywhere.maxRedirects, + corsMaxAge: corsAnywhere.corsMaxAge, + }; + + var cors_headers = withCORS({}, req); if (req.method === 'OPTIONS') { // Pre-flight request. Reply successfully: res.writeHead(200, cors_headers); @@ -353,13 +360,8 @@ function getHandler(options, proxy) { req.headers[header] = corsAnywhere.setHeaders[header]; }); - req.corsAnywhereRequestState = { - location: location, - getProxyForUrl: corsAnywhere.getProxyForUrl, - maxRedirects: corsAnywhere.maxRedirects, - maxAge: corsAnywhere.maxAge, - proxyBaseUrl: proxyBaseUrl, - }; + req.corsAnywhereRequestState.location = location; + req.corsAnywhereRequestState.proxyBaseUrl = proxyBaseUrl; proxyRequest(req, res, proxy); }; diff --git a/test/test.js b/test/test.js index 086ba47..c2a3f69 100644 --- a/test/test.js +++ b/test/test.js @@ -50,6 +50,7 @@ describe('Basic functionality', function() { .get('/') .type('text/plain') .expect('Access-Control-Allow-Origin', '*') + .expect('Access-Control-Max-Age', '0') .expect(200, helpText, done); }); @@ -91,6 +92,7 @@ describe('Basic functionality', function() { request(cors_anywhere) .get('/example.com') .expect('Access-Control-Allow-Origin', '*') + .expect('Access-Control-Max-Age', '0') .expect('x-request-url', 'http://example.com/') .expect(200, 'Response from example.com', done); }); @@ -813,7 +815,7 @@ describe('setHeaders + removeHeaders', function() { describe('Access-Control-Max-Age set', function() { before(function() { cors_anywhere = createServer({ - maxAge: 600, + corsMaxAge: 600, }); cors_anywhere_port = cors_anywhere.listen(0).address().port; }); @@ -833,13 +835,15 @@ describe('Access-Control-Max-Age set', function() { .get('/example.com') .expect('Access-Control-Allow-Origin', '*') .expect('Access-Control-Max-Age', '600') - .expect(200, 'Response from example.com', done);; + .expect(200, 'Response from example.com', done); }); }); describe('Access-Control-Max-Age not set', function() { before(function() { - cors_anywhere = createServer(); + cors_anywhere = createServer({ + corsMaxAge: null, + }); cors_anywhere_port = cors_anywhere.listen(0).address().port; }); after(stopServer); From 49d429dd60f9e6186d2269968e601f154ffdb932 Mon Sep 17 00:00:00 2001 From: Jack Tench Date: Fri, 14 Jul 2017 13:22:53 +0100 Subject: [PATCH 3/3] Do not send Access-Control-Max-Age header if corsMaxAge is 0 (default) --- README.md | 3 +-- lib/cors-anywhere.js | 2 +- test/test.js | 6 +----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6cfff53..b264190 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,7 @@ proxy requests. The following options are supported: Example: `["cookie"]` * dictionary of lowercase strings `setHeaders` - Set headers for the request (overwrites existing ones). Example: `{"x-powered-by": "CORS Anywhere"}` -* number `corsMaxAge` - If set, an Access-Control-Max-Age request header with this value (in seconds) will be added. - Defaults to 0. +* number `corsMaxAge` - If set, an Access-Control-Max-Age request header with this value (in seconds) will be added. Example: `600` - Allow CORS preflight request to be cached by the browser for 10 minutes. * string `helpFile` - Set the help file (shown at the homepage). Example: `"myCustomHelpText.txt"` diff --git a/lib/cors-anywhere.js b/lib/cors-anywhere.js index ccdc8ed..e4c722a 100644 --- a/lib/cors-anywhere.js +++ b/lib/cors-anywhere.js @@ -53,7 +53,7 @@ function isValidHostName(hostname) { function withCORS(headers, request) { headers['access-control-allow-origin'] = '*'; var corsMaxAge = request.corsAnywhereRequestState.corsMaxAge; - if (corsMaxAge != null) { + if (corsMaxAge) { headers['access-control-max-age'] = corsMaxAge; } if (request.headers['access-control-request-method']) { diff --git a/test/test.js b/test/test.js index c2a3f69..8ea2870 100644 --- a/test/test.js +++ b/test/test.js @@ -50,7 +50,6 @@ describe('Basic functionality', function() { .get('/') .type('text/plain') .expect('Access-Control-Allow-Origin', '*') - .expect('Access-Control-Max-Age', '0') .expect(200, helpText, done); }); @@ -92,7 +91,6 @@ describe('Basic functionality', function() { request(cors_anywhere) .get('/example.com') .expect('Access-Control-Allow-Origin', '*') - .expect('Access-Control-Max-Age', '0') .expect('x-request-url', 'http://example.com/') .expect(200, 'Response from example.com', done); }); @@ -841,9 +839,7 @@ describe('Access-Control-Max-Age set', function() { describe('Access-Control-Max-Age not set', function() { before(function() { - cors_anywhere = createServer({ - corsMaxAge: null, - }); + cors_anywhere = createServer(); cors_anywhere_port = cors_anywhere.listen(0).address().port; }); after(stopServer);