1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 var util = require('util');
23 var net = require('net');
24 var EventEmitter = require('events').EventEmitter;
25 var HTTPParser = process.binding('http_parser').HTTPParser;
26 var assert = require('assert').ok;
28 var common = require('_http_common');
30 var httpSocketSetup = common.httpSocketSetup;
31 var parsers = common.parsers;
32 var freeParser = common.freeParser;
33 var debug = common.debug;
35 var IncomingMessage = require('_http_incoming').IncomingMessage;
36 var OutgoingMessage = require('_http_outgoing').OutgoingMessage;
38 var agent = require('_http_agent');
39 var globalAgent = agent.globalAgent;
42 function ClientRequest(options, cb) {
44 OutgoingMessage.call(self);
46 options = util._extend({}, options);
48 self.agent = util.isUndefined(options.agent) ? globalAgent : options.agent;
50 var defaultPort = options.defaultPort || self.agent.defaultPort;
52 var port = options.port = options.port || defaultPort;
53 var host = options.host = options.hostname || options.host || 'localhost';
55 if (util.isUndefined(options.setHost)) {
59 self.socketPath = options.socketPath;
61 var method = self.method = (options.method || 'GET').toUpperCase();
62 self.path = options.path || '/';
64 self.once('response', cb);
67 if (!util.isArray(options.headers)) {
68 if (options.headers) {
69 var keys = Object.keys(options.headers);
70 for (var i = 0, l = keys.length; i < l; i++) {
72 self.setHeader(key, options.headers[key]);
75 if (host && !this.getHeader('host') && setHost) {
76 var hostHeader = host;
77 if (port && +port !== defaultPort) {
78 hostHeader += ':' + port;
80 this.setHeader('Host', hostHeader);
84 if (options.auth && !this.getHeader('Authorization')) {
86 this.setHeader('Authorization', 'Basic ' +
87 new Buffer(options.auth).toString('base64'));
90 if (method === 'GET' ||
92 method === 'DELETE' ||
93 method === 'CONNECT') {
94 self.useChunkedEncodingByDefault = false;
96 self.useChunkedEncodingByDefault = true;
99 if (util.isArray(options.headers)) {
100 self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n',
102 } else if (self.getHeader('expect')) {
103 self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n',
104 self._renderHeaders());
107 if (self.socketPath) {
109 self.shouldKeepAlive = false;
110 var conn = self.agent.createConnection({ path: self.socketPath });
112 } else if (self.agent) {
113 // If there is an agent we should default to Connection:keep-alive,
114 // but only if the Agent will actually reuse the connection!
115 // If it's not a keepAlive agent, and the maxSockets==Infinity, then
116 // there's never a case where this socket will actually be reused
117 var agent = self.agent;
118 if (!agent.keepAlive && !Number.isFinite(agent.maxSockets)) {
120 self.shouldKeepAlive = false;
123 self.shouldKeepAlive = true;
125 self.agent.addRequest(self, options);
127 // No agent, default to Connection:close.
129 self.shouldKeepAlive = false;
130 if (options.createConnection) {
131 var conn = options.createConnection(options);
133 debug('CLIENT use net.createConnection', options);
134 var conn = net.createConnection(options);
139 self._deferToConnect(null, null, function() {
145 util.inherits(ClientRequest, OutgoingMessage);
147 exports.ClientRequest = ClientRequest;
149 ClientRequest.prototype._finish = function() {
150 DTRACE_HTTP_CLIENT_REQUEST(this, this.connection);
151 COUNTER_HTTP_CLIENT_REQUEST();
152 OutgoingMessage.prototype._finish.call(this);
155 ClientRequest.prototype._implicitHeader = function() {
156 this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
157 this._renderHeaders());
160 ClientRequest.prototype.abort = function() {
161 // If we're aborting, we don't care about any more response data.
165 this.once('response', function(res) {
171 this.socket.destroy();
173 // haven't been assigned a socket yet.
174 // this could be more efficient, it could
175 // remove itself from the pending requests
176 this._deferToConnect('destroy', []);
181 function createHangUpError() {
182 var error = new Error('socket hang up');
183 error.code = 'ECONNRESET';
188 function socketCloseListener() {
190 var req = socket._httpMessage;
191 debug('HTTP socket close');
193 // Pull through final chunk, if anything is buffered.
194 // the ondata function will handle it properly, and this
195 // is a no-op if no final chunk remains.
198 // NOTE: Its important to get parser here, because it could be freed by
199 // the `socketOnData`.
200 var parser = socket.parser;
202 if (req.res && req.res.readable) {
203 // Socket closed before we emitted 'end' below.
204 req.res.emit('aborted');
206 res.on('end', function() {
210 } else if (!req.res && !req.socket._hadError) {
211 // This socket error fired before we started to
212 // receive a response. The error needs to
213 // fire on the request.
214 req.emit('error', createHangUpError());
215 req.socket._hadError = true;
218 // Too bad. That output wasn't getting written.
219 // This is pretty terrible that it doesn't raise an error.
220 // Fixed better in v0.10
222 req.output.length = 0;
223 if (req.outputEncodings)
224 req.outputEncodings.length = 0;
228 freeParser(parser, req);
232 function socketErrorListener(err) {
234 var parser = socket.parser;
235 var req = socket._httpMessage;
236 debug('SOCKET ERROR:', err.message, err.stack);
239 req.emit('error', err);
240 // For Safety. Some additional errors might fire later on
241 // and we need to make sure we don't double-fire the error event.
242 req.socket._hadError = true;
247 freeParser(parser, req);
252 function socketOnEnd() {
254 var req = this._httpMessage;
255 var parser = this.parser;
257 if (!req.res && !req.socket._hadError) {
258 // If we don't have a response then we know that the socket
259 // ended prematurely and we need to emit an error on the request.
260 req.emit('error', createHangUpError());
261 req.socket._hadError = true;
265 freeParser(parser, req);
270 function socketOnData(d) {
272 var req = this._httpMessage;
273 var parser = this.parser;
275 assert(parser && parser.socket === socket);
277 var ret = parser.execute(d);
278 if (ret instanceof Error) {
279 debug('parse error');
280 freeParser(parser, req);
282 req.emit('error', ret);
283 req.socket._hadError = true;
284 } else if (parser.incoming && parser.incoming.upgrade) {
285 // Upgrade or CONNECT
286 var bytesParsed = ret;
287 var res = parser.incoming;
290 socket.removeListener('data', socketOnData);
291 socket.removeListener('end', socketOnEnd);
294 var bodyHead = d.slice(bytesParsed, d.length);
296 var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
297 if (EventEmitter.listenerCount(req, eventName) > 0) {
298 req.upgradeOrConnect = true;
301 socket.emit('agentRemove');
302 socket.removeListener('close', socketCloseListener);
303 socket.removeListener('error', socketErrorListener);
305 // TODO(isaacs): Need a way to reset a stream to fresh state
306 // IE, not flowing, and not explicitly paused.
307 socket._readableState.flowing = null;
309 req.emit(eventName, res, socket, bodyHead);
312 // Got Upgrade header or CONNECT method, but have no handler.
315 freeParser(parser, req);
316 } else if (parser.incoming && parser.incoming.complete &&
317 // When the status code is 100 (Continue), the server will
318 // send a final response after this client sends a request
319 // body. So, we must not free the parser.
320 parser.incoming.statusCode !== 100) {
321 socket.removeListener('data', socketOnData);
322 socket.removeListener('end', socketOnEnd);
323 freeParser(parser, req);
329 function parserOnIncomingClient(res, shouldKeepAlive) {
330 var socket = this.socket;
331 var req = socket._httpMessage;
334 // propogate "domain" setting...
335 if (req.domain && !res.domain) {
336 debug('setting "res.domain"');
337 res.domain = req.domain;
340 debug('AGENT incoming response!');
343 // We already have a response object, this means the server
344 // sent a double response.
350 // Responses to CONNECT request is handled as Upgrade.
351 if (req.method === 'CONNECT') {
353 return true; // skip body
356 // Responses to HEAD requests are crazy.
357 // HEAD responses aren't allowed to have an entity-body
358 // but *can* have a content-length which actually corresponds
359 // to the content-length of the entity-body had the request
361 var isHeadResponse = req.method == 'HEAD';
362 debug('AGENT isHeadResponse', isHeadResponse);
364 if (res.statusCode == 100) {
365 // restart the parser, as this is a continue message.
366 delete req.res; // Clear res so that we don't hit double-responses.
367 req.emit('continue');
371 if (req.shouldKeepAlive && !shouldKeepAlive && !req.upgradeOrConnect) {
372 // Server MUST respond with Connection:keep-alive for us to enable it.
373 // If we've been upgraded (via WebSockets) we also shouldn't try to
374 // keep the connection open.
375 req.shouldKeepAlive = false;
379 DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
380 COUNTER_HTTP_CLIENT_RESPONSE();
384 // add our listener first, so that we guarantee socket cleanup
385 res.on('end', responseOnEnd);
386 var handled = req.emit('response', res);
388 // If the user did not listen for the 'response' event, then they
389 // can't possibly read the data, so we ._dump() it into the void
390 // so that the socket doesn't hang there in a paused state.
394 return isHeadResponse;
398 function responseOnEnd() {
401 var socket = req.socket;
403 if (!req.shouldKeepAlive) {
404 if (socket.writable) {
405 debug('AGENT socket.destroySoon()');
406 socket.destroySoon();
408 assert(!socket.writable);
410 debug('AGENT socket keep-alive');
412 socket.setTimeout(0, req.timeoutCb);
413 req.timeoutCb = null;
415 socket.removeListener('close', socketCloseListener);
416 socket.removeListener('error', socketErrorListener);
417 // Mark this socket as available, AFTER user-added end
418 // handlers have a chance to run.
419 process.nextTick(function() {
425 function tickOnSocket(req, socket) {
426 var parser = parsers.alloc();
428 req.connection = socket;
429 parser.reinitialize(HTTPParser.RESPONSE);
430 parser.socket = socket;
431 parser.incoming = null;
434 socket.parser = parser;
435 socket._httpMessage = req;
437 // Setup "drain" propogation.
438 httpSocketSetup(socket);
440 // Propagate headers limit from request object to parser
441 if (util.isNumber(req.maxHeadersCount)) {
442 parser.maxHeaderPairs = req.maxHeadersCount << 1;
444 // Set default value because parser may be reused from FreeList
445 parser.maxHeaderPairs = 2000;
448 parser.onIncoming = parserOnIncomingClient;
449 socket.on('error', socketErrorListener);
450 socket.on('data', socketOnData);
451 socket.on('end', socketOnEnd);
452 socket.on('close', socketCloseListener);
453 req.emit('socket', socket);
456 ClientRequest.prototype.onSocket = function(socket) {
459 process.nextTick(function() {
460 // If a domain was added to the request, attach it to the socket.
462 socket._handle.addAsyncListener(req.domain._listener);
463 tickOnSocket(req, socket);
468 ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) {
469 // This function is for calls that need to happen once the socket is
470 // connected and writable. It's an important promisy thing for all the socket
471 // calls that happen either now (when a socket is assigned) or
472 // in the future (when a socket gets assigned out of the pool and is
473 // eventually writable).
475 var onSocket = function() {
476 if (self.socket.writable) {
478 self.socket[method].apply(self.socket, arguments_);
482 self.socket.once('connect', function() {
484 self.socket[method].apply(self.socket, arguments_);
491 self.once('socket', onSocket);
497 ClientRequest.prototype.setTimeout = function(msecs, callback) {
498 if (callback) this.once('timeout', callback);
501 function emitTimeout() {
502 self.emit('timeout');
505 if (this.socket && this.socket.writable) {
507 this.socket.setTimeout(0, this.timeoutCb);
508 this.timeoutCb = emitTimeout;
509 this.socket.setTimeout(msecs, emitTimeout);
513 // Set timeoutCb so that it'll get cleaned up on request end
514 this.timeoutCb = emitTimeout;
516 var sock = this.socket;
517 this.socket.once('connect', function() {
518 sock.setTimeout(msecs, emitTimeout);
523 this.once('socket', function(sock) {
524 sock.setTimeout(msecs, emitTimeout);
528 ClientRequest.prototype.setNoDelay = function() {
529 this._deferToConnect('setNoDelay', arguments);
531 ClientRequest.prototype.setSocketKeepAlive = function() {
532 this._deferToConnect('setKeepAlive', arguments);
535 ClientRequest.prototype.clearTimeout = function(cb) {
536 this.setTimeout(0, cb);