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