PageRenderTime 75ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/_http_client.js

https://github.com/osfreak/node
JavaScript | 570 lines | 392 code | 84 blank | 94 comment | 103 complexity | 647db6c37bc262d25bc5b031293583fe MD5 | raw file
Possible License(s): 0BSD, BSD-3-Clause, WTFPL, MPL-2.0-no-copyleft-exception, GPL-2.0, Apache-2.0, MIT, AGPL-3.0, ISC
  1. // Copyright Joyent, Inc. and other Node contributors.
  2. //
  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:
  10. //
  11. // The above copyright notice and this permission notice shall be included
  12. // in all copies or substantial portions of the Software.
  13. //
  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.
  21. var util = require('util');
  22. var net = require('net');
  23. var url = require('url');
  24. var EventEmitter = require('events').EventEmitter;
  25. var HTTPParser = process.binding('http_parser').HTTPParser;
  26. var assert = require('assert').ok;
  27. var common = require('_http_common');
  28. var httpSocketSetup = common.httpSocketSetup;
  29. var parsers = common.parsers;
  30. var freeParser = common.freeParser;
  31. var debug = common.debug;
  32. var OutgoingMessage = require('_http_outgoing').OutgoingMessage;
  33. var Agent = require('_http_agent');
  34. function ClientRequest(options, cb) {
  35. var self = this;
  36. OutgoingMessage.call(self);
  37. if (util.isString(options)) {
  38. options = url.parse(options);
  39. } else {
  40. options = util._extend({}, options);
  41. }
  42. var agent = options.agent;
  43. var defaultAgent = options._defaultAgent || Agent.globalAgent;
  44. if (agent === false) {
  45. agent = new defaultAgent.constructor();
  46. } else if (util.isNullOrUndefined(agent) && !options.createConnection) {
  47. agent = defaultAgent;
  48. }
  49. self.agent = agent;
  50. var protocol = options.protocol || defaultAgent.protocol;
  51. var expectedProtocol = defaultAgent.protocol;
  52. if (self.agent && self.agent.protocol)
  53. expectedProtocol = self.agent.protocol;
  54. if (options.path && / /.test(options.path)) {
  55. // The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
  56. // with an additional rule for ignoring percentage-escaped characters
  57. // but that's a) hard to capture in a regular expression that performs
  58. // well, and b) possibly too restrictive for real-world usage. That's
  59. // why it only scans for spaces because those are guaranteed to create
  60. // an invalid request.
  61. throw new TypeError('Request path contains unescaped characters.');
  62. } else if (protocol !== expectedProtocol) {
  63. throw new Error('Protocol "' + protocol + '" not supported. ' +
  64. 'Expected "' + expectedProtocol + '".');
  65. }
  66. var defaultPort = options.defaultPort || self.agent && self.agent.defaultPort;
  67. var port = options.port = options.port || defaultPort || 80;
  68. var host = options.host = options.hostname || options.host || 'localhost';
  69. if (util.isUndefined(options.setHost)) {
  70. var setHost = true;
  71. }
  72. self.socketPath = options.socketPath;
  73. var method = self.method = (options.method || 'GET').toUpperCase();
  74. self.path = options.path || '/';
  75. if (cb) {
  76. self.once('response', cb);
  77. }
  78. if (!util.isArray(options.headers)) {
  79. if (options.headers) {
  80. var keys = Object.keys(options.headers);
  81. for (var i = 0, l = keys.length; i < l; i++) {
  82. var key = keys[i];
  83. self.setHeader(key, options.headers[key]);
  84. }
  85. }
  86. if (host && !this.getHeader('host') && setHost) {
  87. var hostHeader = host;
  88. if (port && +port !== defaultPort) {
  89. hostHeader += ':' + port;
  90. }
  91. this.setHeader('Host', hostHeader);
  92. }
  93. }
  94. if (options.auth && !this.getHeader('Authorization')) {
  95. //basic auth
  96. this.setHeader('Authorization', 'Basic ' +
  97. new Buffer(options.auth).toString('base64'));
  98. }
  99. if (method === 'GET' ||
  100. method === 'HEAD' ||
  101. method === 'DELETE' ||
  102. method === 'OPTIONS' ||
  103. method === 'CONNECT') {
  104. self.useChunkedEncodingByDefault = false;
  105. } else {
  106. self.useChunkedEncodingByDefault = true;
  107. }
  108. if (util.isArray(options.headers)) {
  109. self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n',
  110. options.headers);
  111. } else if (self.getHeader('expect')) {
  112. self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n',
  113. self._renderHeaders());
  114. }
  115. if (self.socketPath) {
  116. self._last = true;
  117. self.shouldKeepAlive = false;
  118. var conn = self.agent.createConnection({ path: self.socketPath });
  119. self.onSocket(conn);
  120. } else if (self.agent) {
  121. // If there is an agent we should default to Connection:keep-alive,
  122. // but only if the Agent will actually reuse the connection!
  123. // If it's not a keepAlive agent, and the maxSockets==Infinity, then
  124. // there's never a case where this socket will actually be reused
  125. if (!self.agent.keepAlive && !Number.isFinite(self.agent.maxSockets)) {
  126. self._last = true;
  127. self.shouldKeepAlive = false;
  128. } else {
  129. self._last = false;
  130. self.shouldKeepAlive = true;
  131. }
  132. self.agent.addRequest(self, options);
  133. } else {
  134. // No agent, default to Connection:close.
  135. self._last = true;
  136. self.shouldKeepAlive = false;
  137. if (options.createConnection) {
  138. var conn = options.createConnection(options);
  139. } else {
  140. debug('CLIENT use net.createConnection', options);
  141. var conn = net.createConnection(options);
  142. }
  143. self.onSocket(conn);
  144. }
  145. self._deferToConnect(null, null, function() {
  146. self._flush();
  147. self = null;
  148. });
  149. }
  150. util.inherits(ClientRequest, OutgoingMessage);
  151. exports.ClientRequest = ClientRequest;
  152. ClientRequest.prototype.aborted = undefined;
  153. ClientRequest.prototype._finish = function() {
  154. DTRACE_HTTP_CLIENT_REQUEST(this, this.connection);
  155. COUNTER_HTTP_CLIENT_REQUEST();
  156. OutgoingMessage.prototype._finish.call(this);
  157. };
  158. ClientRequest.prototype._implicitHeader = function() {
  159. this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
  160. this._renderHeaders());
  161. };
  162. ClientRequest.prototype.abort = function() {
  163. // Mark as aborting so we can avoid sending queued request data
  164. // This is used as a truthy flag elsewhere. The use of Date.now is for
  165. // debugging purposes only.
  166. this.aborted = Date.now();
  167. // If we're aborting, we don't care about any more response data.
  168. if (this.res)
  169. this.res._dump();
  170. else
  171. this.once('response', function(res) {
  172. res._dump();
  173. });
  174. // In the event that we don't have a socket, we will pop out of
  175. // the request queue through handling in onSocket.
  176. if (this.socket) {
  177. // in-progress
  178. this.socket.destroy();
  179. }
  180. };
  181. function createHangUpError() {
  182. var error = new Error('socket hang up');
  183. error.code = 'ECONNRESET';
  184. return error;
  185. }
  186. function socketCloseListener() {
  187. var socket = this;
  188. var req = socket._httpMessage;
  189. debug('HTTP socket close');
  190. // Pull through final chunk, if anything is buffered.
  191. // the ondata function will handle it properly, and this
  192. // is a no-op if no final chunk remains.
  193. socket.read();
  194. // NOTE: Its important to get parser here, because it could be freed by
  195. // the `socketOnData`.
  196. var parser = socket.parser;
  197. req.emit('close');
  198. if (req.res && req.res.readable) {
  199. // Socket closed before we emitted 'end' below.
  200. req.res.emit('aborted');
  201. var res = req.res;
  202. res.on('end', function() {
  203. res.emit('close');
  204. });
  205. res.push(null);
  206. } else if (!req.res && !req.socket._hadError) {
  207. // This socket error fired before we started to
  208. // receive a response. The error needs to
  209. // fire on the request.
  210. req.emit('error', createHangUpError());
  211. req.socket._hadError = true;
  212. }
  213. // Too bad. That output wasn't getting written.
  214. // This is pretty terrible that it doesn't raise an error.
  215. // Fixed better in v0.10
  216. if (req.output)
  217. req.output.length = 0;
  218. if (req.outputEncodings)
  219. req.outputEncodings.length = 0;
  220. if (parser) {
  221. parser.finish();
  222. freeParser(parser, req);
  223. }
  224. }
  225. function socketErrorListener(err) {
  226. var socket = this;
  227. var parser = socket.parser;
  228. var req = socket._httpMessage;
  229. debug('SOCKET ERROR:', err.message, err.stack);
  230. if (req) {
  231. req.emit('error', err);
  232. // For Safety. Some additional errors might fire later on
  233. // and we need to make sure we don't double-fire the error event.
  234. req.socket._hadError = true;
  235. }
  236. if (parser) {
  237. parser.finish();
  238. freeParser(parser, req);
  239. }
  240. socket.destroy();
  241. }
  242. function socketOnEnd() {
  243. var socket = this;
  244. var req = this._httpMessage;
  245. var parser = this.parser;
  246. if (!req.res && !req.socket._hadError) {
  247. // If we don't have a response then we know that the socket
  248. // ended prematurely and we need to emit an error on the request.
  249. req.emit('error', createHangUpError());
  250. req.socket._hadError = true;
  251. }
  252. if (parser) {
  253. parser.finish();
  254. freeParser(parser, req);
  255. }
  256. socket.destroy();
  257. }
  258. function socketOnData(d) {
  259. var socket = this;
  260. var req = this._httpMessage;
  261. var parser = this.parser;
  262. assert(parser && parser.socket === socket);
  263. var ret = parser.execute(d);
  264. if (ret instanceof Error) {
  265. debug('parse error');
  266. freeParser(parser, req);
  267. socket.destroy();
  268. req.emit('error', ret);
  269. req.socket._hadError = true;
  270. } else if (parser.incoming && parser.incoming.upgrade) {
  271. // Upgrade or CONNECT
  272. var bytesParsed = ret;
  273. var res = parser.incoming;
  274. req.res = res;
  275. socket.removeListener('data', socketOnData);
  276. socket.removeListener('end', socketOnEnd);
  277. parser.finish();
  278. var bodyHead = d.slice(bytesParsed, d.length);
  279. var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
  280. if (EventEmitter.listenerCount(req, eventName) > 0) {
  281. req.upgradeOrConnect = true;
  282. // detach the socket
  283. socket.emit('agentRemove');
  284. socket.removeListener('close', socketCloseListener);
  285. socket.removeListener('error', socketErrorListener);
  286. // TODO(isaacs): Need a way to reset a stream to fresh state
  287. // IE, not flowing, and not explicitly paused.
  288. socket._readableState.flowing = null;
  289. req.emit(eventName, res, socket, bodyHead);
  290. req.emit('close');
  291. } else {
  292. // Got Upgrade header or CONNECT method, but have no handler.
  293. socket.destroy();
  294. }
  295. freeParser(parser, req);
  296. } else if (parser.incoming && parser.incoming.complete &&
  297. // When the status code is 100 (Continue), the server will
  298. // send a final response after this client sends a request
  299. // body. So, we must not free the parser.
  300. parser.incoming.statusCode !== 100) {
  301. socket.removeListener('data', socketOnData);
  302. socket.removeListener('end', socketOnEnd);
  303. freeParser(parser, req);
  304. }
  305. }
  306. // client
  307. function parserOnIncomingClient(res, shouldKeepAlive) {
  308. var socket = this.socket;
  309. var req = socket._httpMessage;
  310. // propogate "domain" setting...
  311. if (req.domain && !res.domain) {
  312. debug('setting "res.domain"');
  313. res.domain = req.domain;
  314. }
  315. debug('AGENT incoming response!');
  316. if (req.res) {
  317. // We already have a response object, this means the server
  318. // sent a double response.
  319. socket.destroy();
  320. return;
  321. }
  322. req.res = res;
  323. // Responses to CONNECT request is handled as Upgrade.
  324. if (req.method === 'CONNECT') {
  325. res.upgrade = true;
  326. return true; // skip body
  327. }
  328. // Responses to HEAD requests are crazy.
  329. // HEAD responses aren't allowed to have an entity-body
  330. // but *can* have a content-length which actually corresponds
  331. // to the content-length of the entity-body had the request
  332. // been a GET.
  333. var isHeadResponse = req.method === 'HEAD';
  334. debug('AGENT isHeadResponse', isHeadResponse);
  335. if (res.statusCode === 100) {
  336. // restart the parser, as this is a continue message.
  337. delete req.res; // Clear res so that we don't hit double-responses.
  338. req.emit('continue');
  339. return true;
  340. }
  341. if (req.shouldKeepAlive && !shouldKeepAlive && !req.upgradeOrConnect) {
  342. // Server MUST respond with Connection:keep-alive for us to enable it.
  343. // If we've been upgraded (via WebSockets) we also shouldn't try to
  344. // keep the connection open.
  345. req.shouldKeepAlive = false;
  346. }
  347. DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
  348. COUNTER_HTTP_CLIENT_RESPONSE();
  349. req.res = res;
  350. res.req = req;
  351. // add our listener first, so that we guarantee socket cleanup
  352. res.on('end', responseOnEnd);
  353. var handled = req.emit('response', res);
  354. // If the user did not listen for the 'response' event, then they
  355. // can't possibly read the data, so we ._dump() it into the void
  356. // so that the socket doesn't hang there in a paused state.
  357. if (!handled)
  358. res._dump();
  359. return isHeadResponse;
  360. }
  361. // client
  362. function responseOnEnd() {
  363. var res = this;
  364. var req = res.req;
  365. var socket = req.socket;
  366. if (!req.shouldKeepAlive) {
  367. if (socket.writable) {
  368. debug('AGENT socket.destroySoon()');
  369. socket.destroySoon();
  370. }
  371. assert(!socket.writable);
  372. } else {
  373. debug('AGENT socket keep-alive');
  374. if (req.timeoutCb) {
  375. socket.setTimeout(0, req.timeoutCb);
  376. req.timeoutCb = null;
  377. }
  378. socket.removeListener('close', socketCloseListener);
  379. socket.removeListener('error', socketErrorListener);
  380. // Mark this socket as available, AFTER user-added end
  381. // handlers have a chance to run.
  382. process.nextTick(function() {
  383. socket.emit('free');
  384. });
  385. }
  386. }
  387. function tickOnSocket(req, socket) {
  388. var parser = parsers.alloc();
  389. req.socket = socket;
  390. req.connection = socket;
  391. parser.reinitialize(HTTPParser.RESPONSE);
  392. parser.socket = socket;
  393. parser.incoming = null;
  394. req.parser = parser;
  395. socket.parser = parser;
  396. socket._httpMessage = req;
  397. // Setup "drain" propogation.
  398. httpSocketSetup(socket);
  399. // Propagate headers limit from request object to parser
  400. if (util.isNumber(req.maxHeadersCount)) {
  401. parser.maxHeaderPairs = req.maxHeadersCount << 1;
  402. } else {
  403. // Set default value because parser may be reused from FreeList
  404. parser.maxHeaderPairs = 2000;
  405. }
  406. parser.onIncoming = parserOnIncomingClient;
  407. socket.on('error', socketErrorListener);
  408. socket.on('data', socketOnData);
  409. socket.on('end', socketOnEnd);
  410. socket.on('close', socketCloseListener);
  411. req.emit('socket', socket);
  412. }
  413. ClientRequest.prototype.onSocket = function(socket) {
  414. var req = this;
  415. process.nextTick(function() {
  416. if (req.aborted) {
  417. // If we were aborted while waiting for a socket, skip the whole thing.
  418. socket.emit('free');
  419. } else {
  420. tickOnSocket(req, socket);
  421. }
  422. });
  423. };
  424. ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) {
  425. // This function is for calls that need to happen once the socket is
  426. // connected and writable. It's an important promisy thing for all the socket
  427. // calls that happen either now (when a socket is assigned) or
  428. // in the future (when a socket gets assigned out of the pool and is
  429. // eventually writable).
  430. var self = this;
  431. var onSocket = function() {
  432. if (self.socket.writable) {
  433. if (method) {
  434. self.socket[method].apply(self.socket, arguments_);
  435. }
  436. if (cb) { cb(); }
  437. } else {
  438. self.socket.once('connect', function() {
  439. if (method) {
  440. self.socket[method].apply(self.socket, arguments_);
  441. }
  442. if (cb) { cb(); }
  443. });
  444. }
  445. }
  446. if (!self.socket) {
  447. self.once('socket', onSocket);
  448. } else {
  449. onSocket();
  450. }
  451. };
  452. ClientRequest.prototype.setTimeout = function(msecs, callback) {
  453. if (callback) this.once('timeout', callback);
  454. var self = this;
  455. function emitTimeout() {
  456. self.emit('timeout');
  457. }
  458. if (this.socket && this.socket.writable) {
  459. if (this.timeoutCb)
  460. this.socket.setTimeout(0, this.timeoutCb);
  461. this.timeoutCb = emitTimeout;
  462. this.socket.setTimeout(msecs, emitTimeout);
  463. return;
  464. }
  465. // Set timeoutCb so that it'll get cleaned up on request end
  466. this.timeoutCb = emitTimeout;
  467. if (this.socket) {
  468. var sock = this.socket;
  469. this.socket.once('connect', function() {
  470. sock.setTimeout(msecs, emitTimeout);
  471. });
  472. return;
  473. }
  474. this.once('socket', function(sock) {
  475. sock.setTimeout(msecs, emitTimeout);
  476. });
  477. };
  478. ClientRequest.prototype.setNoDelay = function() {
  479. this._deferToConnect('setNoDelay', arguments);
  480. };
  481. ClientRequest.prototype.setSocketKeepAlive = function() {
  482. this._deferToConnect('setKeepAlive', arguments);
  483. };
  484. ClientRequest.prototype.clearTimeout = function(cb) {
  485. this.setTimeout(0, cb);
  486. };