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 22'use strict'; 23const common = require('../common'); 24const assert = require('assert'); 25const http = require('http'); 26 27const server = http.createServer(common.mustNotCall()); 28 29server.on('connect', common.mustCall((req, socket, firstBodyChunk) => { 30 assert.strictEqual(req.method, 'CONNECT'); 31 assert.strictEqual(req.url, 'google.com:443'); 32 33 // Make sure this socket has detached. 34 assert.strictEqual(socket.listenerCount('close'), 0); 35 assert.strictEqual(socket.listenerCount('drain'), 0); 36 assert.strictEqual(socket.listenerCount('data'), 0); 37 assert.strictEqual(socket.listenerCount('end'), 1); 38 assert.strictEqual(socket.listenerCount('error'), 0); 39 assert.strictEqual(socket.listenerCount('timeout'), 0); 40 41 socket.write('HTTP/1.1 200 Connection established\r\n\r\n'); 42 43 let data = firstBodyChunk.toString(); 44 socket.on('data', (buf) => { 45 data += buf.toString(); 46 }); 47 48 socket.on('end', common.mustCall(() => { 49 socket.end(data); 50 })); 51})); 52 53server.listen(0, common.mustCall(() => { 54 const req = http.request({ 55 port: server.address().port, 56 method: 'CONNECT', 57 path: 'google.com:443', 58 timeout: 20000 59 }, common.mustNotCall()); 60 61 req.on('socket', common.mustCall((socket) => { 62 assert.strictEqual(socket._httpMessage, req); 63 })); 64 65 assert.strictEqual(req.destroyed, false); 66 req.on('close', common.mustCall(() => { 67 assert.strictEqual(req.destroyed, true); 68 })); 69 70 req.on('connect', common.mustCall((res, socket, firstBodyChunk) => { 71 // Make sure this request got removed from the pool. 72 const name = `localhost:${server.address().port}`; 73 assert(!(name in http.globalAgent.sockets)); 74 assert(!(name in http.globalAgent.requests)); 75 76 // Make sure this socket has detached. 77 assert(!socket.ondata); 78 assert(!socket.onend); 79 assert.strictEqual(socket._httpMessage, null); 80 assert.strictEqual(socket.listenerCount('connect'), 0); 81 assert.strictEqual(socket.listenerCount('data'), 0); 82 assert.strictEqual(socket.listenerCount('drain'), 0); 83 assert.strictEqual(socket.listenerCount('end'), 1); 84 assert.strictEqual(socket.listenerCount('free'), 0); 85 assert.strictEqual(socket.listenerCount('close'), 0); 86 assert.strictEqual(socket.listenerCount('error'), 0); 87 assert.strictEqual(socket.listenerCount('agentRemove'), 0); 88 assert.strictEqual(socket.listenerCount('timeout'), 0); 89 90 let data = firstBodyChunk.toString(); 91 socket.on('data', (buf) => { 92 data += buf.toString(); 93 }); 94 95 socket.on('end', common.mustCall(() => { 96 assert.strictEqual(data, 'HeadBody'); 97 server.close(); 98 })); 99 100 socket.write('Body'); 101 socket.end(); 102 })); 103 104 // It is legal for the client to send some data intended for the server 105 // before the "200 Connection established" (or any other success or 106 // error code) is received. 107 req.write('Head'); 108 req.end(); 109})); 110