PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/_http_client.js

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