| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 | 
							- 'use strict'
 
- var net = require('net')
 
-   , tls = require('tls')
 
-   , http = require('http')
 
-   , https = require('https')
 
-   , events = require('events')
 
-   , assert = require('assert')
 
-   , util = require('util')
 
-   , Buffer = require('safe-buffer').Buffer
 
-   ;
 
- exports.httpOverHttp = httpOverHttp
 
- exports.httpsOverHttp = httpsOverHttp
 
- exports.httpOverHttps = httpOverHttps
 
- exports.httpsOverHttps = httpsOverHttps
 
- function httpOverHttp(options) {
 
-   var agent = new TunnelingAgent(options)
 
-   agent.request = http.request
 
-   return agent
 
- }
 
- function httpsOverHttp(options) {
 
-   var agent = new TunnelingAgent(options)
 
-   agent.request = http.request
 
-   agent.createSocket = createSecureSocket
 
-   agent.defaultPort = 443
 
-   return agent
 
- }
 
- function httpOverHttps(options) {
 
-   var agent = new TunnelingAgent(options)
 
-   agent.request = https.request
 
-   return agent
 
- }
 
- function httpsOverHttps(options) {
 
-   var agent = new TunnelingAgent(options)
 
-   agent.request = https.request
 
-   agent.createSocket = createSecureSocket
 
-   agent.defaultPort = 443
 
-   return agent
 
- }
 
- function TunnelingAgent(options) {
 
-   var self = this
 
-   self.options = options || {}
 
-   self.proxyOptions = self.options.proxy || {}
 
-   self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets
 
-   self.requests = []
 
-   self.sockets = []
 
-   self.on('free', function onFree(socket, host, port) {
 
-     for (var i = 0, len = self.requests.length; i < len; ++i) {
 
-       var pending = self.requests[i]
 
-       if (pending.host === host && pending.port === port) {
 
-         // Detect the request to connect same origin server,
 
-         // reuse the connection.
 
-         self.requests.splice(i, 1)
 
-         pending.request.onSocket(socket)
 
-         return
 
-       }
 
-     }
 
-     socket.destroy()
 
-     self.removeSocket(socket)
 
-   })
 
- }
 
- util.inherits(TunnelingAgent, events.EventEmitter)
 
- TunnelingAgent.prototype.addRequest = function addRequest(req, options) {
 
-   var self = this
 
-    // Legacy API: addRequest(req, host, port, path)
 
-   if (typeof options === 'string') {
 
-     options = {
 
-       host: options,
 
-       port: arguments[2],
 
-       path: arguments[3]
 
-     };
 
-   }
 
-   if (self.sockets.length >= this.maxSockets) {
 
-     // We are over limit so we'll add it to the queue.
 
-     self.requests.push({host: options.host, port: options.port, request: req})
 
-     return
 
-   }
 
-   // If we are under maxSockets create a new one.
 
-   self.createConnection({host: options.host, port: options.port, request: req})
 
- }
 
- TunnelingAgent.prototype.createConnection = function createConnection(pending) {
 
-   var self = this
 
-   self.createSocket(pending, function(socket) {
 
-     socket.on('free', onFree)
 
-     socket.on('close', onCloseOrRemove)
 
-     socket.on('agentRemove', onCloseOrRemove)
 
-     pending.request.onSocket(socket)
 
-     function onFree() {
 
-       self.emit('free', socket, pending.host, pending.port)
 
-     }
 
-     function onCloseOrRemove(err) {
 
-       self.removeSocket(socket)
 
-       socket.removeListener('free', onFree)
 
-       socket.removeListener('close', onCloseOrRemove)
 
-       socket.removeListener('agentRemove', onCloseOrRemove)
 
-     }
 
-   })
 
- }
 
- TunnelingAgent.prototype.createSocket = function createSocket(options, cb) {
 
-   var self = this
 
-   var placeholder = {}
 
-   self.sockets.push(placeholder)
 
-   var connectOptions = mergeOptions({}, self.proxyOptions,
 
-     { method: 'CONNECT'
 
-     , path: options.host + ':' + options.port
 
-     , agent: false
 
-     }
 
-   )
 
-   if (connectOptions.proxyAuth) {
 
-     connectOptions.headers = connectOptions.headers || {}
 
-     connectOptions.headers['Proxy-Authorization'] = 'Basic ' +
 
-         Buffer.from(connectOptions.proxyAuth).toString('base64')
 
-   }
 
-   debug('making CONNECT request')
 
-   var connectReq = self.request(connectOptions)
 
-   connectReq.useChunkedEncodingByDefault = false // for v0.6
 
-   connectReq.once('response', onResponse) // for v0.6
 
-   connectReq.once('upgrade', onUpgrade)   // for v0.6
 
-   connectReq.once('connect', onConnect)   // for v0.7 or later
 
-   connectReq.once('error', onError)
 
-   connectReq.end()
 
-   function onResponse(res) {
 
-     // Very hacky. This is necessary to avoid http-parser leaks.
 
-     res.upgrade = true
 
-   }
 
-   function onUpgrade(res, socket, head) {
 
-     // Hacky.
 
-     process.nextTick(function() {
 
-       onConnect(res, socket, head)
 
-     })
 
-   }
 
-   function onConnect(res, socket, head) {
 
-     connectReq.removeAllListeners()
 
-     socket.removeAllListeners()
 
-     if (res.statusCode === 200) {
 
-       assert.equal(head.length, 0)
 
-       debug('tunneling connection has established')
 
-       self.sockets[self.sockets.indexOf(placeholder)] = socket
 
-       cb(socket)
 
-     } else {
 
-       debug('tunneling socket could not be established, statusCode=%d', res.statusCode)
 
-       var error = new Error('tunneling socket could not be established, ' + 'statusCode=' + res.statusCode)
 
-       error.code = 'ECONNRESET'
 
-       options.request.emit('error', error)
 
-       self.removeSocket(placeholder)
 
-     }
 
-   }
 
-   function onError(cause) {
 
-     connectReq.removeAllListeners()
 
-     debug('tunneling socket could not be established, cause=%s\n', cause.message, cause.stack)
 
-     var error = new Error('tunneling socket could not be established, ' + 'cause=' + cause.message)
 
-     error.code = 'ECONNRESET'
 
-     options.request.emit('error', error)
 
-     self.removeSocket(placeholder)
 
-   }
 
- }
 
- TunnelingAgent.prototype.removeSocket = function removeSocket(socket) {
 
-   var pos = this.sockets.indexOf(socket)
 
-   if (pos === -1) return
 
-   this.sockets.splice(pos, 1)
 
-   var pending = this.requests.shift()
 
-   if (pending) {
 
-     // If we have pending requests and a socket gets closed a new one
 
-     // needs to be created to take over in the pool for the one that closed.
 
-     this.createConnection(pending)
 
-   }
 
- }
 
- function createSecureSocket(options, cb) {
 
-   var self = this
 
-   TunnelingAgent.prototype.createSocket.call(self, options, function(socket) {
 
-     // 0 is dummy port for v0.6
 
-     var secureSocket = tls.connect(0, mergeOptions({}, self.options,
 
-       { servername: options.host
 
-       , socket: socket
 
-       }
 
-     ))
 
-     self.sockets[self.sockets.indexOf(socket)] = secureSocket
 
-     cb(secureSocket)
 
-   })
 
- }
 
- function mergeOptions(target) {
 
-   for (var i = 1, len = arguments.length; i < len; ++i) {
 
-     var overrides = arguments[i]
 
-     if (typeof overrides === 'object') {
 
-       var keys = Object.keys(overrides)
 
-       for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
 
-         var k = keys[j]
 
-         if (overrides[k] !== undefined) {
 
-           target[k] = overrides[k]
 
-         }
 
-       }
 
-     }
 
-   }
 
-   return target
 
- }
 
- var debug
 
- if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
 
-   debug = function() {
 
-     var args = Array.prototype.slice.call(arguments)
 
-     if (typeof args[0] === 'string') {
 
-       args[0] = 'TUNNEL: ' + args[0]
 
-     } else {
 
-       args.unshift('TUNNEL:')
 
-     }
 
-     console.error.apply(console, args)
 
-   }
 
- } else {
 
-   debug = function() {}
 
- }
 
- exports.debug = debug // for test
 
 
  |