|
|
@ -66,8 +66,7 @@ function isInvalidPath(s) { |
|
|
|
} |
|
|
|
|
|
|
|
function ClientRequest(options, cb) { |
|
|
|
var self = this; |
|
|
|
OutgoingMessage.call(self); |
|
|
|
OutgoingMessage.call(this); |
|
|
|
|
|
|
|
if (typeof options === 'string') { |
|
|
|
options = url.parse(options); |
|
|
@ -95,12 +94,12 @@ function ClientRequest(options, cb) { |
|
|
|
'Agent option must be an instance of http.Agent, undefined or false.' |
|
|
|
); |
|
|
|
} |
|
|
|
self.agent = agent; |
|
|
|
this.agent = agent; |
|
|
|
|
|
|
|
var protocol = options.protocol || defaultAgent.protocol; |
|
|
|
var expectedProtocol = defaultAgent.protocol; |
|
|
|
if (self.agent && self.agent.protocol) |
|
|
|
expectedProtocol = self.agent.protocol; |
|
|
|
if (this.agent && this.agent.protocol) |
|
|
|
expectedProtocol = this.agent.protocol; |
|
|
|
|
|
|
|
var path; |
|
|
|
if (options.path) { |
|
|
@ -121,15 +120,15 @@ function ClientRequest(options, cb) { |
|
|
|
} |
|
|
|
|
|
|
|
const defaultPort = options.defaultPort || |
|
|
|
self.agent && self.agent.defaultPort; |
|
|
|
this.agent && this.agent.defaultPort; |
|
|
|
|
|
|
|
var port = options.port = options.port || defaultPort || 80; |
|
|
|
var host = options.host = options.hostname || options.host || 'localhost'; |
|
|
|
|
|
|
|
var setHost = (options.setHost === undefined); |
|
|
|
|
|
|
|
self.socketPath = options.socketPath; |
|
|
|
self.timeout = options.timeout; |
|
|
|
this.socketPath = options.socketPath; |
|
|
|
this.timeout = options.timeout; |
|
|
|
|
|
|
|
var method = options.method; |
|
|
|
var methodIsString = (typeof method === 'string'); |
|
|
@ -141,14 +140,14 @@ function ClientRequest(options, cb) { |
|
|
|
if (!common._checkIsHttpToken(method)) { |
|
|
|
throw new TypeError('Method must be a valid HTTP token'); |
|
|
|
} |
|
|
|
method = self.method = method.toUpperCase(); |
|
|
|
method = this.method = method.toUpperCase(); |
|
|
|
} else { |
|
|
|
method = self.method = 'GET'; |
|
|
|
method = this.method = 'GET'; |
|
|
|
} |
|
|
|
|
|
|
|
self.path = options.path || '/'; |
|
|
|
this.path = options.path || '/'; |
|
|
|
if (cb) { |
|
|
|
self.once('response', cb); |
|
|
|
this.once('response', cb); |
|
|
|
} |
|
|
|
|
|
|
|
var headersArray = Array.isArray(options.headers); |
|
|
@ -157,7 +156,7 @@ function ClientRequest(options, cb) { |
|
|
|
var keys = Object.keys(options.headers); |
|
|
|
for (var i = 0; i < keys.length; i++) { |
|
|
|
var key = keys[i]; |
|
|
|
self.setHeader(key, options.headers[key]); |
|
|
|
this.setHeader(key, options.headers[key]); |
|
|
|
} |
|
|
|
} |
|
|
|
if (host && !this.getHeader('host') && setHost) { |
|
|
@ -190,21 +189,22 @@ function ClientRequest(options, cb) { |
|
|
|
method === 'DELETE' || |
|
|
|
method === 'OPTIONS' || |
|
|
|
method === 'CONNECT') { |
|
|
|
self.useChunkedEncodingByDefault = false; |
|
|
|
this.useChunkedEncodingByDefault = false; |
|
|
|
} else { |
|
|
|
self.useChunkedEncodingByDefault = true; |
|
|
|
this.useChunkedEncodingByDefault = true; |
|
|
|
} |
|
|
|
|
|
|
|
if (headersArray) { |
|
|
|
self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n', |
|
|
|
this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', |
|
|
|
options.headers); |
|
|
|
} else if (self.getHeader('expect')) { |
|
|
|
if (self._header) { |
|
|
|
} else if (this.getHeader('expect')) { |
|
|
|
if (this._header) { |
|
|
|
throw new Error('Can\'t render headers after they are sent to the ' + |
|
|
|
'client'); |
|
|
|
} |
|
|
|
self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n', |
|
|
|
self[outHeadersKey]); |
|
|
|
|
|
|
|
this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', |
|
|
|
this[outHeadersKey]); |
|
|
|
} |
|
|
|
|
|
|
|
this._ended = false; |
|
|
@ -216,72 +216,65 @@ function ClientRequest(options, cb) { |
|
|
|
this.maxHeadersCount = null; |
|
|
|
|
|
|
|
var called = false; |
|
|
|
if (self.socketPath) { |
|
|
|
self._last = true; |
|
|
|
self.shouldKeepAlive = false; |
|
|
|
|
|
|
|
const oncreate = (err, socket) => { |
|
|
|
if (called) |
|
|
|
return; |
|
|
|
called = true; |
|
|
|
if (err) { |
|
|
|
process.nextTick(() => this.emit('error', err)); |
|
|
|
return; |
|
|
|
} |
|
|
|
this.onSocket(socket); |
|
|
|
this._deferToConnect(null, null, () => this._flush()); |
|
|
|
}; |
|
|
|
|
|
|
|
if (this.socketPath) { |
|
|
|
this._last = true; |
|
|
|
this.shouldKeepAlive = false; |
|
|
|
const optionsPath = { |
|
|
|
path: self.socketPath, |
|
|
|
timeout: self.timeout |
|
|
|
path: this.socketPath, |
|
|
|
timeout: this.timeout |
|
|
|
}; |
|
|
|
const newSocket = self.agent.createConnection(optionsPath, oncreate); |
|
|
|
const newSocket = this.agent.createConnection(optionsPath, oncreate); |
|
|
|
if (newSocket && !called) { |
|
|
|
called = true; |
|
|
|
self.onSocket(newSocket); |
|
|
|
this.onSocket(newSocket); |
|
|
|
} else { |
|
|
|
return; |
|
|
|
} |
|
|
|
} else if (self.agent) { |
|
|
|
} else if (this.agent) { |
|
|
|
// If there is an agent we should default to Connection:keep-alive,
|
|
|
|
// but only if the Agent will actually reuse the connection!
|
|
|
|
// If it's not a keepAlive agent, and the maxSockets==Infinity, then
|
|
|
|
// there's never a case where this socket will actually be reused
|
|
|
|
if (!self.agent.keepAlive && !Number.isFinite(self.agent.maxSockets)) { |
|
|
|
self._last = true; |
|
|
|
self.shouldKeepAlive = false; |
|
|
|
if (!this.agent.keepAlive && !Number.isFinite(this.agent.maxSockets)) { |
|
|
|
this._last = true; |
|
|
|
this.shouldKeepAlive = false; |
|
|
|
} else { |
|
|
|
self._last = false; |
|
|
|
self.shouldKeepAlive = true; |
|
|
|
this._last = false; |
|
|
|
this.shouldKeepAlive = true; |
|
|
|
} |
|
|
|
self.agent.addRequest(self, options); |
|
|
|
this.agent.addRequest(this, options); |
|
|
|
} else { |
|
|
|
// No agent, default to Connection:close.
|
|
|
|
self._last = true; |
|
|
|
self.shouldKeepAlive = false; |
|
|
|
this._last = true; |
|
|
|
this.shouldKeepAlive = false; |
|
|
|
if (typeof options.createConnection === 'function') { |
|
|
|
const newSocket = options.createConnection(options, oncreate); |
|
|
|
if (newSocket && !called) { |
|
|
|
called = true; |
|
|
|
self.onSocket(newSocket); |
|
|
|
this.onSocket(newSocket); |
|
|
|
} else { |
|
|
|
return; |
|
|
|
} |
|
|
|
} else { |
|
|
|
debug('CLIENT use net.createConnection', options); |
|
|
|
self.onSocket(net.createConnection(options)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function oncreate(err, socket) { |
|
|
|
if (called) |
|
|
|
return; |
|
|
|
called = true; |
|
|
|
if (err) { |
|
|
|
process.nextTick(function() { |
|
|
|
self.emit('error', err); |
|
|
|
}); |
|
|
|
return; |
|
|
|
this.onSocket(net.createConnection(options)); |
|
|
|
} |
|
|
|
self.onSocket(socket); |
|
|
|
self._deferToConnect(null, null, function() { |
|
|
|
self._flush(); |
|
|
|
self = null; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
self._deferToConnect(null, null, function() { |
|
|
|
self._flush(); |
|
|
|
self = null; |
|
|
|
}); |
|
|
|
this._deferToConnect(null, null, () => this._flush()); |
|
|
|
} |
|
|
|
|
|
|
|
util.inherits(ClientRequest, OutgoingMessage); |
|
|
@ -304,7 +297,7 @@ ClientRequest.prototype._implicitHeader = function _implicitHeader() { |
|
|
|
|
|
|
|
ClientRequest.prototype.abort = function abort() { |
|
|
|
if (!this.aborted) { |
|
|
|
process.nextTick(emitAbortNT, this); |
|
|
|
process.nextTick(emitAbortNT.bind(this)); |
|
|
|
} |
|
|
|
// Mark as aborting so we can avoid sending queued request data
|
|
|
|
// This is used as a truthy flag elsewhere. The use of Date.now is for
|
|
|
@ -328,8 +321,8 @@ ClientRequest.prototype.abort = function abort() { |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
function emitAbortNT(self) { |
|
|
|
self.emit('abort'); |
|
|
|
function emitAbortNT() { |
|
|
|
this.emit('abort'); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -681,26 +674,25 @@ function _deferToConnect(method, arguments_, cb) { |
|
|
|
// calls that happen either now (when a socket is assigned) or
|
|
|
|
// in the future (when a socket gets assigned out of the pool and is
|
|
|
|
// eventually writable).
|
|
|
|
var self = this; |
|
|
|
|
|
|
|
function callSocketMethod() { |
|
|
|
const callSocketMethod = () => { |
|
|
|
if (method) |
|
|
|
self.socket[method].apply(self.socket, arguments_); |
|
|
|
this.socket[method].apply(this.socket, arguments_); |
|
|
|
|
|
|
|
if (typeof cb === 'function') |
|
|
|
cb(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var onSocket = function onSocket() { |
|
|
|
if (self.socket.writable) { |
|
|
|
const onSocket = () => { |
|
|
|
if (this.socket.writable) { |
|
|
|
callSocketMethod(); |
|
|
|
} else { |
|
|
|
self.socket.once('connect', callSocketMethod); |
|
|
|
this.socket.once('connect', callSocketMethod); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
if (!self.socket) { |
|
|
|
self.once('socket', onSocket); |
|
|
|
if (!this.socket) { |
|
|
|
this.once('socket', onSocket); |
|
|
|
} else { |
|
|
|
onSocket(); |
|
|
|
} |
|
|
@ -709,10 +701,7 @@ function _deferToConnect(method, arguments_, cb) { |
|
|
|
ClientRequest.prototype.setTimeout = function setTimeout(msecs, callback) { |
|
|
|
if (callback) this.once('timeout', callback); |
|
|
|
|
|
|
|
var self = this; |
|
|
|
function emitTimeout() { |
|
|
|
self.emit('timeout'); |
|
|
|
} |
|
|
|
const emitTimeout = () => this.emit('timeout'); |
|
|
|
|
|
|
|
if (this.socket && this.socket.writable) { |
|
|
|
if (this.timeoutCb) |
|
|
|