Use let or const to avoid scope issues and hoisting
var express = require('../')
1'use strict'23var express = require('../')4 , request = require('supertest')5 , assert = require('node:assert')6 , url = require('node:url');78describe('res', function(){9 describe('.location(url)', function(){10 it('should set the header', function(done){11 var app = express();1213 app.use(function(req, res){14 res.location('http://google.com/').end();15 });1617 request(app)18 .get('/')19 .expect('Location', 'http://google.com/')20 .expect(200, done)21 })2223 it('should preserve trailing slashes when not present', function(done){24 var app = express();2526 app.use(function(req, res){27 res.location('http://google.com').end();28 });2930 request(app)31 .get('/')32 .expect('Location', 'http://google.com')33 .expect(200, done)34 })3536 it('should encode "url"', function (done) {37 var app = express()3839 app.use(function (req, res) {40 res.location('https://google.com?q=\u2603 §10').end()41 })4243 request(app)44 .get('/')45 .expect('Location', 'https://google.com?q=%E2%98%83%20%C2%A710')46 .expect(200, done)47 })4849 it('should encode data uri', function (done) {50 var app = express()51 app.use(function (req, res) {52 res.location('data:text/javascript,export default () => { }').end();53 });5455 request(app)56 .get('/')57 .expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D')58 .expect(200, done)59 })6061 it('should consistently handle non-string input: boolean', function (done) {62 var app = express()63 app.use(function (req, res) {64 res.location(true).end();65 });6667 request(app)68 .get('/')69 .expect('Location', 'true')70 .expect(200, done)71 });7273 it('should consistently handle non-string inputs: object', function (done) {74 var app = express()75 app.use(function (req, res) {76 res.location({}).end();77 });7879 request(app)80 .get('/')81 .expect('Location', '[object%20Object]')82 .expect(200, done)83 });8485 it('should consistently handle non-string inputs: array', function (done) {86 var app = express()87 app.use(function (req, res) {88 res.location([]).end();89 });9091 request(app)92 .get('/')93 .expect('Location', '')94 .expect(200, done)95 });9697 it('should consistently handle empty string input', function (done) {98 var app = express()99 app.use(function (req, res) {100 res.location('').end();101 });102103 request(app)104 .get('/')105 .expect('Location', '')106 .expect(200, done)107 });108109110 if (typeof URL !== 'undefined') {111 it('should accept an instance of URL', function (done) {112 var app = express();113114 app.use(function(req, res){115 res.location(new URL('http://google.com/')).end();116 });117118 request(app)119 .get('/')120 .expect('Location', 'http://google.com/')121 .expect(200, done);122 });123 }124 })125126 describe('location header encoding', function() {127 function createRedirectServerForDomain (domain) {128 var app = express();129 app.use(function (req, res) {130 var host = url.parse(req.query.q, false, true).host;131 // This is here to show a basic check one might do which132 // would pass but then the location header would still be bad133 if (host !== domain) {134 res.status(400).end('Bad host: ' + host + ' !== ' + domain);135 }136 res.location(req.query.q).end();137 });138 return app;139 }140141 function testRequestedRedirect (app, inputUrl, expected, expectedHost, done) {142 return request(app)143 // Encode uri because old supertest does not and is required144 // to test older node versions. New supertest doesn't re-encode145 // so this works in both.146 .get('/?q=' + encodeURIComponent(inputUrl))147 .expect('') // No body.148 .expect(200)149 .expect('Location', expected)150 .end(function (err, res) {151 if (err) {152 console.log('headers:', res.headers)153 console.error('error', res.error, err);154 return done(err, res);155 }156157 // Parse the hosts from the input URL and the Location header158 var inputHost = url.parse(inputUrl, false, true).host;159 var locationHost = url.parse(res.headers['location'], false, true).host;160161 assert.strictEqual(locationHost, expectedHost);162163 // Assert that the hosts are the same164 if (inputHost !== locationHost) {165 return done(new Error('Hosts do not match: ' + inputHost + " !== " + locationHost));166 }167168 return done(null, res);169 });170 }171172 it('should not touch already-encoded sequences in "url"', function (done) {173 var app = createRedirectServerForDomain('google.com');174 testRequestedRedirect(175 app,176 'https://google.com?q=%A710',177 'https://google.com?q=%A710',178 'google.com',179 done180 );181 });182183 it('should consistently handle relative urls', function (done) {184 var app = createRedirectServerForDomain(null);185 testRequestedRedirect(186 app,187 '/foo/bar',188 '/foo/bar',189 null,190 done191 );192 });193194 it('should not encode urls in such a way that they can bypass redirect allow lists', function (done) {195 var app = createRedirectServerForDomain('google.com');196 testRequestedRedirect(197 app,198 'http://google.com\\@apple.com',199 'http://google.com\\@apple.com',200 'google.com',201 done202 );203 });204205 it('should not be case sensitive', function (done) {206 var app = createRedirectServerForDomain('google.com');207 testRequestedRedirect(208 app,209 'HTTP://google.com\\@apple.com',210 'HTTP://google.com\\@apple.com',211 'google.com',212 done213 );214 });215216 it('should work with https', function (done) {217 var app = createRedirectServerForDomain('google.com');218 testRequestedRedirect(219 app,220 'https://google.com\\@apple.com',221 'https://google.com\\@apple.com',222 'google.com',223 done224 );225 });226227 it('should correctly encode schemaless paths', function (done) {228 var app = createRedirectServerForDomain('google.com');229 testRequestedRedirect(230 app,231 '//google.com\\@apple.com/',232 '//google.com\\@apple.com/',233 'google.com',234 done235 );236 });237238 it('should keep backslashes in the path', function (done) {239 var app = createRedirectServerForDomain('google.com');240 testRequestedRedirect(241 app,242 'https://google.com/foo\\bar\\baz',243 'https://google.com/foo\\bar\\baz',244 'google.com',245 done246 );247 });248249 it('should escape header splitting for old node versions', function (done) {250 var app = createRedirectServerForDomain('google.com');251 testRequestedRedirect(252 app,253 'http://google.com\\@apple.com/%0d%0afoo:%20bar',254 'http://google.com\\@apple.com/%0d%0afoo:%20bar',255 'google.com',256 done257 );258 });259260 it('should encode unicode correctly', function (done) {261 var app = createRedirectServerForDomain(null);262 testRequestedRedirect(263 app,264 '/%e2%98%83',265 '/%e2%98%83',266 null,267 done268 );269 });270271 it('should encode unicode correctly even with a bad host', function (done) {272 var app = createRedirectServerForDomain('google.com');273 testRequestedRedirect(274 app,275 'http://google.com\\@apple.com/%e2%98%83',276 'http://google.com\\@apple.com/%e2%98%83',277 'google.com',278 done279 );280 });281282 it('should work correctly despite using deprecated url.parse', function (done) {283 var app = createRedirectServerForDomain('google.com');284 testRequestedRedirect(285 app,286 'https://google.com\'.bb.com/1.html',287 'https://google.com\'.bb.com/1.html',288 'google.com',289 done290 );291 });292293 it('should encode file uri path', function (done) {294 var app = createRedirectServerForDomain('');295 testRequestedRedirect(296 app,297 'file:///etc\\passwd',298 'file:///etc\\passwd',299 '',300 done301 );302 });303 });304})
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.