"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/tunnel-agent/index.js" (11 Apr 2017, 6884 Bytes) of package /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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