Skip to content

Commit

Permalink
http: optimize short path validation
Browse files Browse the repository at this point in the history
PR-URL: #10654
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
  • Loading branch information
mscdex committed Jan 13, 2017
1 parent 6782577 commit 5c2ef14
Showing 1 changed file with 42 additions and 8 deletions.
50 changes: 42 additions & 8 deletions lib/_http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ const Agent = require('_http_agent');
const Buffer = require('buffer').Buffer;
const urlToOptions = require('internal/url').urlToOptions;

// The actual list of disallowed characters in regexp form is more like:
// /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
// with an additional rule for ignoring percentage-escaped characters, but
// that's a) hard to capture in a regular expression that performs well, and
// b) possibly too restrictive for real-world usage. So instead we restrict the
// filter to just control characters and spaces.
//
// This function is used in the case of small paths, where manual character code
// checks can greatly outperform the equivalent regexp (tested in V8 5.4).
function isInvalidPath(s) {
var i = 0;
if (s.charCodeAt(0) <= 32) return true;
if (++i >= s.length) return false;
if (s.charCodeAt(1) <= 32) return true;
if (++i >= s.length) return false;
if (s.charCodeAt(2) <= 32) return true;
if (++i >= s.length) return false;
if (s.charCodeAt(3) <= 32) return true;
if (++i >= s.length) return false;
if (s.charCodeAt(4) <= 32) return true;
if (++i >= s.length) return false;
if (s.charCodeAt(5) <= 32) return true;
++i;
for (; i < s.length; ++i)
if (s.charCodeAt(i) <= 32) return true;
return false;
}

function ClientRequest(options, cb) {
var self = this;
OutgoingMessage.call(self);
Expand Down Expand Up @@ -45,14 +73,20 @@ function ClientRequest(options, cb) {
if (self.agent && self.agent.protocol)
expectedProtocol = self.agent.protocol;

if (options.path && /[\u0000-\u0020]/.test(options.path)) {
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
// with an additional rule for ignoring percentage-escaped characters
// but that's a) hard to capture in a regular expression that performs
// well, and b) possibly too restrictive for real-world usage.
// Restrict the filter to control characters and spaces.
throw new TypeError('Request path contains unescaped characters');
} else if (protocol !== expectedProtocol) {
var path;
if (options.path) {
path = '' + options.path;
var invalidPath;
if (path.length <= 39) { // Determined experimentally in V8 5.4
invalidPath = isInvalidPath(path);
} else {
invalidPath = /[\u0000-\u0020]/.test(path);
}
if (invalidPath)
throw new TypeError('Request path contains unescaped characters');
}

if (protocol !== expectedProtocol) {
throw new Error('Protocol "' + protocol + '" not supported. ' +
'Expected "' + expectedProtocol + '"');
}
Expand Down

0 comments on commit 5c2ef14

Please sign in to comment.