test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /**
  2. * Module dependencies.
  3. */
  4. var fs = require('fs');
  5. var url = require('url');
  6. var net = require('net');
  7. var tls = require('tls');
  8. var http = require('http');
  9. var https = require('https');
  10. var WebSocket = require('ws');
  11. var assert = require('assert');
  12. var events = require('events');
  13. var inherits = require('util').inherits;
  14. var semver = require('semver');
  15. var Agent = require('../');
  16. describe('Agent', function () {
  17. describe('subclass', function () {
  18. it('should be subclassable', function (done) {
  19. function MyAgent () {
  20. Agent.call(this);
  21. }
  22. inherits(MyAgent, Agent);
  23. MyAgent.prototype.callback = function (req, opts, fn) {
  24. assert.equal(req.path, '/foo');
  25. assert.equal(req.getHeader('host'), '127.0.0.1:1234');
  26. assert.equal(opts.secureEndpoint, true);
  27. done();
  28. };
  29. var info = url.parse('https://127.0.0.1:1234/foo');
  30. info.agent = new MyAgent;
  31. https.get(info);
  32. });
  33. });
  34. describe('"error" event', function () {
  35. it('should be invoked on `http.ClientRequest` instance if `callback()` has not been defined', function (done) {
  36. var agent = new Agent();
  37. var info = url.parse('http://127.0.0.1/foo');
  38. info.agent = agent;
  39. var req = http.get(info);
  40. req.on('error', function (err) {
  41. assert.equal('"agent-base" has no default implementation, you must subclass and override `callback()`', err.message);
  42. done();
  43. });
  44. });
  45. it('should be invoked on `http.ClientRequest` instance if Error passed to callback function on the first tick', function (done) {
  46. var agent = new Agent(function (req, opts, fn) {
  47. fn(new Error('is this caught?'));
  48. });
  49. var info = url.parse('http://127.0.0.1/foo');
  50. info.agent = agent;
  51. var req = http.get(info);
  52. req.on('error', function (err) {
  53. assert.equal('is this caught?', err.message);
  54. done();
  55. });
  56. });
  57. it('should be invoked on `http.ClientRequest` instance if Error passed to callback function after the first tick', function (done) {
  58. var agent = new Agent(function (req, opts, fn) {
  59. setTimeout(function () {
  60. fn(new Error('is this caught?'));
  61. }, 10);
  62. });
  63. var info = url.parse('http://127.0.0.1/foo');
  64. info.agent = agent;
  65. var req = http.get(info);
  66. req.on('error', function (err) {
  67. assert.equal('is this caught?', err.message);
  68. done();
  69. });
  70. });
  71. });
  72. describe('artificial "streams"', function () {
  73. it('should send a GET request', function (done) {
  74. var stream = new events.EventEmitter();
  75. // needed for the `http` module to call .write() on the stream
  76. stream.writable = true;
  77. stream.write = function (str) {
  78. assert(0 == str.indexOf('GET / HTTP/1.1'));
  79. done();
  80. };
  81. // needed for `http` module in Node.js 4
  82. stream.cork = function () {
  83. };
  84. var opts = {
  85. method: 'GET',
  86. host: '127.0.0.1',
  87. path: '/',
  88. port: 80,
  89. agent: new Agent(function (req, opts, fn) {
  90. fn(null, stream);
  91. })
  92. };
  93. var req = http.request(opts);
  94. req.end();
  95. });
  96. it('should receive a GET response', function (done) {
  97. var stream = new events.EventEmitter();
  98. var opts = {
  99. method: 'GET',
  100. host: '127.0.0.1',
  101. path: '/',
  102. port: 80,
  103. agent: new Agent(function (req, opts, fn) {
  104. fn(null, stream);
  105. })
  106. };
  107. var req = http.request(opts, function (res) {
  108. assert.equal('0.9', res.httpVersion);
  109. assert.equal(111, res.statusCode);
  110. assert.equal('bar', res.headers.foo);
  111. done();
  112. });
  113. req.end();
  114. // have to nextTick() since `http.ClientRequest` doesn't *actually*
  115. // attach the listeners to the "stream" until the next tick :\
  116. process.nextTick(function () {
  117. var buf = new Buffer('HTTP/0.9 111\r\n' +
  118. 'Foo: bar\r\n' +
  119. 'Set-Cookie: 1\r\n' +
  120. 'Set-Cookie: 2\r\n\r\n');
  121. if ('function' == typeof stream.ondata) {
  122. // node <= v0.11.3
  123. stream.ondata(buf, 0, buf.length);
  124. } else {
  125. // node > v0.11.3
  126. stream.emit('data', buf);
  127. }
  128. });
  129. });
  130. });
  131. });
  132. describe('"http" module', function () {
  133. var server;
  134. var port;
  135. // setup test HTTP server
  136. before(function (done) {
  137. server = http.createServer();
  138. server.listen(0, function () {
  139. port = server.address().port;
  140. done();
  141. });
  142. });
  143. // shut down test HTTP server
  144. after(function (done) {
  145. server.once('close', function () {
  146. done();
  147. });
  148. server.close();
  149. });
  150. it('should work for basic HTTP requests', function (done) {
  151. var called = false;
  152. var agent = new Agent(function (req, opts, fn) {
  153. called = true;
  154. var socket = net.connect(opts);
  155. fn(null, socket);
  156. });
  157. // add HTTP server "request" listener
  158. var gotReq = false;
  159. server.once('request', function (req, res) {
  160. gotReq = true;
  161. res.setHeader('X-Foo', 'bar');
  162. res.setHeader('X-Url', req.url);
  163. res.end();
  164. });
  165. var info = url.parse('http://127.0.0.1:' + port + '/foo');
  166. info.agent = agent;
  167. http.get(info, function (res) {
  168. assert.equal('bar', res.headers['x-foo']);
  169. assert.equal('/foo', res.headers['x-url']);
  170. assert(gotReq);
  171. assert(called);
  172. done();
  173. });
  174. });
  175. it('should set the `Connection: close` response header', function (done) {
  176. var called = false;
  177. var agent = new Agent(function (req, opts, fn) {
  178. called = true;
  179. var socket = net.connect(opts);
  180. fn(null, socket);
  181. });
  182. // add HTTP server "request" listener
  183. var gotReq = false;
  184. server.once('request', function (req, res) {
  185. gotReq = true;
  186. res.setHeader('X-Url', req.url);
  187. assert.equal('close', req.headers.connection);
  188. res.end();
  189. });
  190. var info = url.parse('http://127.0.0.1:' + port + '/bar');
  191. info.agent = agent;
  192. http.get(info, function (res) {
  193. assert.equal('/bar', res.headers['x-url']);
  194. assert.equal('close', res.headers.connection);
  195. assert(gotReq);
  196. assert(called);
  197. done();
  198. });
  199. });
  200. it('should pass through options from `http.request()`', function (done) {
  201. var agent = new Agent(function (req, opts, fn) {
  202. assert.equal('google.com', opts.host);
  203. assert.equal('bar', opts.foo);
  204. done();
  205. });
  206. http.get({
  207. host: 'google.com',
  208. foo: 'bar',
  209. agent: agent
  210. });
  211. });
  212. it('should default to port 80', function (done) {
  213. var agent = new Agent(function (req, opts, fn) {
  214. assert.equal(80, opts.port);
  215. done();
  216. });
  217. // (probably) not hitting a real HTTP server here,
  218. // so no need to add a httpServer request listener
  219. http.get({
  220. host: '127.0.0.1',
  221. path: '/foo',
  222. agent: agent
  223. });
  224. });
  225. });
  226. describe('"https" module', function () {
  227. var server;
  228. var port;
  229. // setup test HTTPS server
  230. before(function (done) {
  231. var options = {
  232. key: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.key'),
  233. cert: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.pem')
  234. };
  235. server = https.createServer(options);
  236. server.listen(0, function () {
  237. port = server.address().port;
  238. done();
  239. });
  240. });
  241. // shut down test HTTP server
  242. after(function (done) {
  243. server.once('close', function () {
  244. done();
  245. });
  246. server.close();
  247. });
  248. it('should work for basic HTTPS requests', function (done) {
  249. var called = false;
  250. var agent = new Agent(function (req, opts, fn) {
  251. called = true;
  252. assert(opts.secureEndpoint);
  253. var socket = tls.connect(opts);
  254. fn(null, socket);
  255. });
  256. // add HTTPS server "request" listener
  257. var gotReq = false;
  258. server.once('request', function (req, res) {
  259. gotReq = true;
  260. res.setHeader('X-Foo', 'bar');
  261. res.setHeader('X-Url', req.url);
  262. res.end();
  263. });
  264. var info = url.parse('https://127.0.0.1:' + port + '/foo');
  265. info.agent = agent;
  266. info.rejectUnauthorized = false;
  267. https.get(info, function (res) {
  268. assert.equal('bar', res.headers['x-foo']);
  269. assert.equal('/foo', res.headers['x-url']);
  270. assert(gotReq);
  271. assert(called);
  272. done();
  273. });
  274. });
  275. it('should pass through options from `https.request()`', function (done) {
  276. var agent = new Agent(function (req, opts, fn) {
  277. assert.equal('google.com', opts.host);
  278. assert.equal('bar', opts.foo);
  279. done();
  280. });
  281. https.get({
  282. host: 'google.com',
  283. foo: 'bar',
  284. agent: agent
  285. });
  286. });
  287. it('should default to port 443', function (done) {
  288. var agent = new Agent(function (req, opts, fn) {
  289. assert.equal(true, opts.secureEndpoint);
  290. assert.equal(false, opts.rejectUnauthorized);
  291. assert.equal(443, opts.port);
  292. done();
  293. });
  294. // (probably) not hitting a real HTTPS server here,
  295. // so no need to add a httpsServer request listener
  296. https.get({
  297. host: '127.0.0.1',
  298. path: '/foo',
  299. agent: agent,
  300. rejectUnauthorized: false
  301. });
  302. });
  303. });
  304. describe('"ws" server', function () {
  305. var wss;
  306. var server;
  307. var port;
  308. // setup test HTTP server
  309. before(function (done) {
  310. server = http.createServer()
  311. wss = new WebSocket.Server({ server: server });
  312. server.listen(0, function () {
  313. port = server.address().port;
  314. done();
  315. });
  316. });
  317. // shut down test HTTP server
  318. after(function (done) {
  319. server.once('close', function () {
  320. done();
  321. });
  322. server.close();
  323. });
  324. it('should work for basic WebSocket connections', function (done) {
  325. function onconnection(ws) {
  326. ws.on('message', function (data) {
  327. assert.equal('ping', data);
  328. ws.send('pong');
  329. });
  330. }
  331. wss.on('connection', onconnection);
  332. var agent = new Agent(function (req, opts, fn) {
  333. var socket = net.connect(opts);
  334. fn(null, socket);
  335. });
  336. var client = new WebSocket('ws://127.0.0.1:' + port + '/', {
  337. agent: agent
  338. });
  339. client.on('open', function () {
  340. client.send('ping');
  341. });
  342. client.on('message', function (data) {
  343. assert.equal('pong', data);
  344. client.close();
  345. wss.removeListener('connection', onconnection);
  346. done();
  347. });
  348. });
  349. });
  350. describe('"wss" server', function () {
  351. var wss;
  352. var server;
  353. var port;
  354. // setup test HTTP server
  355. before(function (done) {
  356. var options = {
  357. key: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.key'),
  358. cert: fs.readFileSync(__dirname + '/ssl-cert-snakeoil.pem')
  359. };
  360. server = https.createServer(options);
  361. wss = new WebSocket.Server({ server: server });
  362. server.listen(0, function () {
  363. port = server.address().port;
  364. done();
  365. });
  366. });
  367. // shut down test HTTP server
  368. after(function (done) {
  369. server.once('close', function () {
  370. done();
  371. });
  372. server.close();
  373. });
  374. it('should work for secure WebSocket connections', function (done) {
  375. function onconnection(ws) {
  376. ws.on('message', function (data) {
  377. assert.equal('ping', data);
  378. ws.send('pong');
  379. });
  380. }
  381. wss.on('connection', onconnection);
  382. var agent = new Agent(function (req, opts, fn) {
  383. var socket = tls.connect(opts);
  384. fn(null, socket);
  385. });
  386. var client = new WebSocket('wss://127.0.0.1:' + port + '/', {
  387. agent: agent,
  388. rejectUnauthorized: false
  389. });
  390. client.on('open', function () {
  391. client.send('ping');
  392. });
  393. client.on('message', function (data) {
  394. assert.equal('pong', data);
  395. client.close();
  396. wss.removeListener('connection', onconnection);
  397. done();
  398. });
  399. });
  400. });