diff options
Diffstat (limited to 'deps/npm/node_modules/request/request.js')
-rw-r--r-- | deps/npm/node_modules/request/request.js | 122 |
1 files changed, 106 insertions, 16 deletions
diff --git a/deps/npm/node_modules/request/request.js b/deps/npm/node_modules/request/request.js index 26f70c2084..467524ba4e 100644 --- a/deps/npm/node_modules/request/request.js +++ b/deps/npm/node_modules/request/request.js @@ -28,6 +28,8 @@ var http = require('http') , Multipart = require('./lib/multipart').Multipart , Redirect = require('./lib/redirect').Redirect , Tunnel = require('./lib/tunnel').Tunnel + , now = require('performance-now') + , Buffer = require('safe-buffer').Buffer var safeStringify = helpers.safeStringify , isReadStream = helpers.isReadStream @@ -288,13 +290,10 @@ Request.prototype.init = function (options) { self.setHost = false if (!self.hasHeader('host')) { var hostHeaderName = self.originalHostHeaderName || 'host' - self.setHeader(hostHeaderName, self.uri.hostname) - if (self.uri.port) { - if ( !(self.uri.port === 80 && self.uri.protocol === 'http:') && - !(self.uri.port === 443 && self.uri.protocol === 'https:') ) { - self.setHeader(hostHeaderName, self.getHeader('host') + (':' + self.uri.port) ) - } - } + // When used with an IPv6 address, `host` will provide + // the correct bracketed format, unlike using `hostname` and + // optionally adding the `port` when necessary. + self.setHeader(hostHeaderName, self.uri.host) self.setHost = true } @@ -412,12 +411,14 @@ Request.prototype.init = function (options) { if (options.time) { self.timing = true + + // NOTE: elapsedTime is deprecated in favor of .timings self.elapsedTime = self.elapsedTime || 0 } function setContentLength () { if (isTypedArray(self.body)) { - self.body = new Buffer(self.body) + self.body = Buffer.from(self.body) } if (!self.hasHeader('content-length')) { @@ -713,6 +714,16 @@ Request.prototype.start = function () { // this is usually called on the first write(), end() or on nextTick() var self = this + if (self.timing) { + // All timings will be relative to this request's startTime. In order to do this, + // we need to capture the wall-clock start time (via Date), immediately followed + // by the high-resolution timer (via now()). While these two won't be set + // at the _exact_ same time, they should be close enough to be able to calculate + // high-resolution, monotonically non-decreasing timestamps relative to startTime. + var startTime = new Date().getTime() + var startTimeNow = now() + } + if (self._aborted) { return } @@ -748,7 +759,12 @@ Request.prototype.start = function () { } if (self.timing) { - self.startTime = new Date().getTime() + self.startTime = startTime + self.startTimeNow = startTimeNow + + // Timing values will all be relative to startTime (by comparing to startTimeNow + // so we have an accurate clock) + self.timings = {} } var timeout @@ -766,6 +782,31 @@ Request.prototype.start = function () { self.emit('drain') }) self.req.on('socket', function(socket) { + // `._connecting` was the old property which was made public in node v6.1.0 + var isConnecting = socket._connecting || socket.connecting + if (self.timing) { + self.timings.socket = now() - self.startTimeNow + + if (isConnecting) { + var onLookupTiming = function() { + self.timings.lookup = now() - self.startTimeNow + } + + var onConnectTiming = function() { + self.timings.connect = now() - self.startTimeNow + } + + socket.once('lookup', onLookupTiming) + socket.once('connect', onConnectTiming) + + // clean up timing event listeners if needed on error + self.req.once('error', function() { + socket.removeListener('lookup', onLookupTiming) + socket.removeListener('connect', onConnectTiming) + }) + } + } + var setReqTimeout = function() { // This timeout sets the amount of time to wait *between* bytes sent // from the server once connected. @@ -782,8 +823,6 @@ Request.prototype.start = function () { } }) } - // `._connecting` was the old property which was made public in node v6.1.0 - var isConnecting = socket._connecting || socket.connecting if (timeout !== undefined) { // Only start the connection timer if we're actually connecting a new // socket, otherwise if we're already connected (because this is a @@ -847,12 +886,52 @@ Request.prototype.onRequestError = function (error) { Request.prototype.onRequestResponse = function (response) { var self = this + + if (self.timing) { + self.timings.response = now() - self.startTimeNow + } + debug('onRequestResponse', self.uri.href, response.statusCode, response.headers) response.on('end', function() { if (self.timing) { - self.elapsedTime += (new Date().getTime() - self.startTime) - debug('elapsed time', self.elapsedTime) + self.timings.end = now() - self.startTimeNow + response.timingStart = self.startTime + + // fill in the blanks for any periods that didn't trigger, such as + // no lookup or connect due to keep alive + if (!self.timings.socket) { + self.timings.socket = 0 + } + if (!self.timings.lookup) { + self.timings.lookup = self.timings.socket + } + if (!self.timings.connect) { + self.timings.connect = self.timings.lookup + } + if (!self.timings.response) { + self.timings.response = self.timings.connect + } + + debug('elapsed time', self.timings.end) + + // elapsedTime includes all redirects + self.elapsedTime += Math.round(self.timings.end) + + // NOTE: elapsedTime is deprecated in favor of .timings response.elapsedTime = self.elapsedTime + + // timings is just for the final fetch + response.timings = self.timings + + // pre-calculate phase timings as well + response.timingPhases = { + wait: self.timings.socket, + dns: self.timings.lookup - self.timings.socket, + tcp: self.timings.connect - self.timings.lookup, + firstByte: self.timings.response - self.timings.connect, + download: self.timings.end - self.timings.response, + total: self.timings.end + } } debug('response end', self.uri.href, response.statusCode, response.headers) }) @@ -946,11 +1025,20 @@ Request.prototype.onRequestResponse = function (response) { var contentEncoding = response.headers['content-encoding'] || 'identity' contentEncoding = contentEncoding.trim().toLowerCase() + // Be more lenient with decoding compressed responses, since (very rarely) + // servers send slightly invalid gzip responses that are still accepted + // by common browsers. + // Always using Z_SYNC_FLUSH is what cURL does. + var zlibOptions = { + flush: zlib.Z_SYNC_FLUSH + , finishFlush: zlib.Z_SYNC_FLUSH + } + if (contentEncoding === 'gzip') { - responseContent = zlib.createGunzip() + responseContent = zlib.createGunzip(zlibOptions) response.pipe(responseContent) } else if (contentEncoding === 'deflate') { - responseContent = zlib.createInflate() + responseContent = zlib.createInflate(zlibOptions) response.pipe(responseContent) } else { // Since previous versions didn't check for Content-Encoding header, @@ -992,6 +1080,8 @@ Request.prototype.onRequestResponse = function (response) { responseContent.on('data', function (chunk) { if (self.timing && !self.responseStarted) { self.responseStartTime = (new Date()).getTime() + + // NOTE: responseStartTime is deprecated in favor of .timings response.responseStartTime = self.responseStartTime } self._destdata = true @@ -1076,7 +1166,7 @@ Request.prototype.readResponseBody = function (response) { } debug('emitting complete', self.uri.href) if (typeof response.body === 'undefined' && !self._json) { - response.body = self.encoding === null ? new Buffer(0) : '' + response.body = self.encoding === null ? Buffer.alloc(0) : '' } self.emit('complete', response, response.body) }) |