summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/request/request.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/request/request.js')
-rw-r--r--deps/npm/node_modules/request/request.js122
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)
})