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 req.on('close', common.mustCall()); 66 67 req.on('connect', common.mustCall((res, socket, firstBodyChunk) => { 68 // Make sure this request got removed from the pool. 69 const name = `localhost:${server.address().port}`; 70 assert(!http.globalAgent.sockets.hasOwnProperty(name)); 71 assert(!http.globalAgent.requests.hasOwnProperty(name)); 72 73 // Make sure this socket has detached. 74 assert(!socket.ondata); 75 assert(!socket.onend); 76 assert.strictEqual(socket._httpMessage, null); 77 assert.strictEqual(socket.listenerCount('connect'), 0); 78 assert.strictEqual(socket.listenerCount('data'), 0); 79 assert.strictEqual(socket.listenerCount('drain'), 0); 80 assert.strictEqual(socket.listenerCount('end'), 1); 81 assert.strictEqual(socket.listenerCount('free'), 0); 82 assert.strictEqual(socket.listenerCount('close'), 0); 83 assert.strictEqual(socket.listenerCount('error'), 0); 84 assert.strictEqual(socket.listenerCount('agentRemove'), 0); 85 assert.strictEqual(socket.listenerCount('timeout'), 0); 86 87 let data = firstBodyChunk.toString(); 88 socket.on('data', (buf) => { 89 data += buf.toString(); 90 }); 91 92 socket.on('end', common.mustCall(() => { 93 assert.strictEqual(data, 'HeadBody'); 94 server.close(); 95 })); 96 97 socket.write('Body'); 98 socket.end(); 99 })); 100 101 // It is legal for the client to send some data intended for the server 102 // before the "200 Connection established" (or any other success or 103 // error code) is received. 104 req.write('Head'); 105 req.end(); 106})); 107