Skip to content

Commit df8c736

Browse files
authored
Merge pull request #749 from http-party/fix-dos-vuln
fix crash on redirect with formfeed in URL
2 parents a7d08e1 + 2aa7e0e commit df8c736

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

lib/core/index.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ function decodePathname(pathname) {
3131
? normalized.replace(/\\/g, '/') : normalized;
3232
}
3333

34+
const nonUrlSafeCharsRgx = /[\x00-\x1F\x20\x7F-\uFFFF]+/g;
35+
function ensureUriEncoded(text) {
36+
return text
37+
return String(text).replace(nonUrlSafeCharsRgx, encodeURIComponent);
38+
}
3439

3540
// Check to see if we should try to compress a file with gzip.
3641
function shouldCompressGzip(req) {
@@ -161,7 +166,8 @@ module.exports = function createMiddleware(_dir, _options) {
161166
if (opts.weakCompare && clientEtag !== serverEtag
162167
&& clientEtag !== `W/${serverEtag}` && `W/${clientEtag}` !== serverEtag) {
163168
return false;
164-
} else if (!opts.weakCompare && (clientEtag !== serverEtag || clientEtag.indexOf('W/') === 0)) {
169+
}
170+
if (!opts.weakCompare && (clientEtag !== serverEtag || clientEtag.indexOf('W/') === 0)) {
165171
return false;
166172
}
167173
}
@@ -340,8 +346,10 @@ module.exports = function createMiddleware(_dir, _options) {
340346
}, res, next);
341347
} else {
342348
// Try to serve default ./404.html
349+
const rawUrl = (handleError ? `/${path.join(baseDir, `404.${defaultExt}`)}` : req.url);
350+
const encodedUrl = ensureUriEncoded(rawUrl);
343351
middleware({
344-
url: (handleError ? `/${path.join(baseDir, `404.${defaultExt}`)}` : req.url),
352+
url: encodedUrl,
345353
headers: req.headers,
346354
statusCode: 404,
347355
}, res, next);
@@ -359,7 +367,10 @@ module.exports = function createMiddleware(_dir, _options) {
359367
if (!pathname.match(/\/$/)) {
360368
res.statusCode = 302;
361369
const q = parsed.query ? `?${parsed.query}` : '';
362-
res.setHeader('location', `${parsed.pathname}/${q}`);
370+
res.setHeader(
371+
'location',
372+
ensureUriEncoded(`${parsed.pathname}/${q}`)
373+
);
363374
res.end();
364375
return;
365376
}

test/main.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ test('http-server main', (t) => {
8787
.indexOf('X-Test') >= 0, 204);
8888
}).catch(err => t.fail(err.toString())),
8989

90+
t.test(
91+
"Regression: don't crash on control characters in query strings",
92+
{},
93+
(t) => {
94+
requestAsync({
95+
uri: encodeURI('http://localhost:8080/file?\x0cfoo'),
96+
}).then(res => {
97+
t.equal(res.statusCode, 200);
98+
}).catch(err => t.fail(err.toString()))
99+
.finally(() => t.end());
100+
}
101+
),
102+
90103
// Light compression testing. Heavier compression tests exist in
91104
// compression.test.js
92105
requestAsync({

0 commit comments

Comments
 (0)