source: trip-planner-front/node_modules/tunnel-agent/index.js@ e29cc2e

Last change on this file since e29cc2e was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.7 KB
Line 
1'use strict'
2
3var net = require('net')
4 , tls = require('tls')
5 , http = require('http')
6 , https = require('https')
7 , events = require('events')
8 , assert = require('assert')
9 , util = require('util')
10 , Buffer = require('safe-buffer').Buffer
11 ;
12
13exports.httpOverHttp = httpOverHttp
14exports.httpsOverHttp = httpsOverHttp
15exports.httpOverHttps = httpOverHttps
16exports.httpsOverHttps = httpsOverHttps
17
18
19function httpOverHttp(options) {
20 var agent = new TunnelingAgent(options)
21 agent.request = http.request
22 return agent
23}
24
25function httpsOverHttp(options) {
26 var agent = new TunnelingAgent(options)
27 agent.request = http.request
28 agent.createSocket = createSecureSocket
29 agent.defaultPort = 443
30 return agent
31}
32
33function httpOverHttps(options) {
34 var agent = new TunnelingAgent(options)
35 agent.request = https.request
36 return agent
37}
38
39function httpsOverHttps(options) {
40 var agent = new TunnelingAgent(options)
41 agent.request = https.request
42 agent.createSocket = createSecureSocket
43 agent.defaultPort = 443
44 return agent
45}
46
47
48function TunnelingAgent(options) {
49 var self = this
50 self.options = options || {}
51 self.proxyOptions = self.options.proxy || {}
52 self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets
53 self.requests = []
54 self.sockets = []
55
56 self.on('free', function onFree(socket, host, port) {
57 for (var i = 0, len = self.requests.length; i < len; ++i) {
58 var pending = self.requests[i]
59 if (pending.host === host && pending.port === port) {
60 // Detect the request to connect same origin server,
61 // reuse the connection.
62 self.requests.splice(i, 1)
63 pending.request.onSocket(socket)
64 return
65 }
66 }
67 socket.destroy()
68 self.removeSocket(socket)
69 })
70}
71util.inherits(TunnelingAgent, events.EventEmitter)
72
73TunnelingAgent.prototype.addRequest = function addRequest(req, options) {
74 var self = this
75
76 // Legacy API: addRequest(req, host, port, path)
77 if (typeof options === 'string') {
78 options = {
79 host: options,
80 port: arguments[2],
81 path: arguments[3]
82 };
83 }
84
85 if (self.sockets.length >= this.maxSockets) {
86 // We are over limit so we'll add it to the queue.
87 self.requests.push({host: options.host, port: options.port, request: req})
88 return
89 }
90
91 // If we are under maxSockets create a new one.
92 self.createConnection({host: options.host, port: options.port, request: req})
93}
94
95TunnelingAgent.prototype.createConnection = function createConnection(pending) {
96 var self = this
97
98 self.createSocket(pending, function(socket) {
99 socket.on('free', onFree)
100 socket.on('close', onCloseOrRemove)
101 socket.on('agentRemove', onCloseOrRemove)
102 pending.request.onSocket(socket)
103
104 function onFree() {
105 self.emit('free', socket, pending.host, pending.port)
106 }
107
108 function onCloseOrRemove(err) {
109 self.removeSocket(socket)
110 socket.removeListener('free', onFree)
111 socket.removeListener('close', onCloseOrRemove)
112 socket.removeListener('agentRemove', onCloseOrRemove)
113 }
114 })
115}
116
117TunnelingAgent.prototype.createSocket = function createSocket(options, cb) {
118 var self = this
119 var placeholder = {}
120 self.sockets.push(placeholder)
121
122 var connectOptions = mergeOptions({}, self.proxyOptions,
123 { method: 'CONNECT'
124 , path: options.host + ':' + options.port
125 , agent: false
126 }
127 )
128 if (connectOptions.proxyAuth) {
129 connectOptions.headers = connectOptions.headers || {}
130 connectOptions.headers['Proxy-Authorization'] = 'Basic ' +
131 Buffer.from(connectOptions.proxyAuth).toString('base64')
132 }
133
134 debug('making CONNECT request')
135 var connectReq = self.request(connectOptions)
136 connectReq.useChunkedEncodingByDefault = false // for v0.6
137 connectReq.once('response', onResponse) // for v0.6
138 connectReq.once('upgrade', onUpgrade) // for v0.6
139 connectReq.once('connect', onConnect) // for v0.7 or later
140 connectReq.once('error', onError)
141 connectReq.end()
142
143 function onResponse(res) {
144 // Very hacky. This is necessary to avoid http-parser leaks.
145 res.upgrade = true
146 }
147
148 function onUpgrade(res, socket, head) {
149 // Hacky.
150 process.nextTick(function() {
151 onConnect(res, socket, head)
152 })
153 }
154
155 function onConnect(res, socket, head) {
156 connectReq.removeAllListeners()
157 socket.removeAllListeners()
158
159 if (res.statusCode === 200) {
160 assert.equal(head.length, 0)
161 debug('tunneling connection has established')
162 self.sockets[self.sockets.indexOf(placeholder)] = socket
163 cb(socket)
164 } else {
165 debug('tunneling socket could not be established, statusCode=%d', res.statusCode)
166 var error = new Error('tunneling socket could not be established, ' + 'statusCode=' + res.statusCode)
167 error.code = 'ECONNRESET'
168 options.request.emit('error', error)
169 self.removeSocket(placeholder)
170 }
171 }
172
173 function onError(cause) {
174 connectReq.removeAllListeners()
175
176 debug('tunneling socket could not be established, cause=%s\n', cause.message, cause.stack)
177 var error = new Error('tunneling socket could not be established, ' + 'cause=' + cause.message)
178 error.code = 'ECONNRESET'
179 options.request.emit('error', error)
180 self.removeSocket(placeholder)
181 }
182}
183
184TunnelingAgent.prototype.removeSocket = function removeSocket(socket) {
185 var pos = this.sockets.indexOf(socket)
186 if (pos === -1) return
187
188 this.sockets.splice(pos, 1)
189
190 var pending = this.requests.shift()
191 if (pending) {
192 // If we have pending requests and a socket gets closed a new one
193 // needs to be created to take over in the pool for the one that closed.
194 this.createConnection(pending)
195 }
196}
197
198function createSecureSocket(options, cb) {
199 var self = this
200 TunnelingAgent.prototype.createSocket.call(self, options, function(socket) {
201 // 0 is dummy port for v0.6
202 var secureSocket = tls.connect(0, mergeOptions({}, self.options,
203 { servername: options.host
204 , socket: socket
205 }
206 ))
207 self.sockets[self.sockets.indexOf(socket)] = secureSocket
208 cb(secureSocket)
209 })
210}
211
212
213function mergeOptions(target) {
214 for (var i = 1, len = arguments.length; i < len; ++i) {
215 var overrides = arguments[i]
216 if (typeof overrides === 'object') {
217 var keys = Object.keys(overrides)
218 for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
219 var k = keys[j]
220 if (overrides[k] !== undefined) {
221 target[k] = overrides[k]
222 }
223 }
224 }
225 }
226 return target
227}
228
229
230var debug
231if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
232 debug = function() {
233 var args = Array.prototype.slice.call(arguments)
234 if (typeof args[0] === 'string') {
235 args[0] = 'TUNNEL: ' + args[0]
236 } else {
237 args.unshift('TUNNEL:')
238 }
239 console.error.apply(console, args)
240 }
241} else {
242 debug = function() {}
243}
244exports.debug = debug // for test
Note: See TracBrowser for help on using the repository browser.