twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

tunnel.js (4416B)


      1 'use strict'
      2 
      3 var url = require('url')
      4 var tunnel = require('tunnel-agent')
      5 
      6 var defaultProxyHeaderWhiteList = [
      7   'accept',
      8   'accept-charset',
      9   'accept-encoding',
     10   'accept-language',
     11   'accept-ranges',
     12   'cache-control',
     13   'content-encoding',
     14   'content-language',
     15   'content-location',
     16   'content-md5',
     17   'content-range',
     18   'content-type',
     19   'connection',
     20   'date',
     21   'expect',
     22   'max-forwards',
     23   'pragma',
     24   'referer',
     25   'te',
     26   'user-agent',
     27   'via'
     28 ]
     29 
     30 var defaultProxyHeaderExclusiveList = [
     31   'proxy-authorization'
     32 ]
     33 
     34 function constructProxyHost (uriObject) {
     35   var port = uriObject.port
     36   var protocol = uriObject.protocol
     37   var proxyHost = uriObject.hostname + ':'
     38 
     39   if (port) {
     40     proxyHost += port
     41   } else if (protocol === 'https:') {
     42     proxyHost += '443'
     43   } else {
     44     proxyHost += '80'
     45   }
     46 
     47   return proxyHost
     48 }
     49 
     50 function constructProxyHeaderWhiteList (headers, proxyHeaderWhiteList) {
     51   var whiteList = proxyHeaderWhiteList
     52     .reduce(function (set, header) {
     53       set[header.toLowerCase()] = true
     54       return set
     55     }, {})
     56 
     57   return Object.keys(headers)
     58     .filter(function (header) {
     59       return whiteList[header.toLowerCase()]
     60     })
     61     .reduce(function (set, header) {
     62       set[header] = headers[header]
     63       return set
     64     }, {})
     65 }
     66 
     67 function constructTunnelOptions (request, proxyHeaders) {
     68   var proxy = request.proxy
     69 
     70   var tunnelOptions = {
     71     proxy: {
     72       host: proxy.hostname,
     73       port: +proxy.port,
     74       proxyAuth: proxy.auth,
     75       headers: proxyHeaders
     76     },
     77     headers: request.headers,
     78     ca: request.ca,
     79     cert: request.cert,
     80     key: request.key,
     81     passphrase: request.passphrase,
     82     pfx: request.pfx,
     83     ciphers: request.ciphers,
     84     rejectUnauthorized: request.rejectUnauthorized,
     85     secureOptions: request.secureOptions,
     86     secureProtocol: request.secureProtocol
     87   }
     88 
     89   return tunnelOptions
     90 }
     91 
     92 function constructTunnelFnName (uri, proxy) {
     93   var uriProtocol = (uri.protocol === 'https:' ? 'https' : 'http')
     94   var proxyProtocol = (proxy.protocol === 'https:' ? 'Https' : 'Http')
     95   return [uriProtocol, proxyProtocol].join('Over')
     96 }
     97 
     98 function getTunnelFn (request) {
     99   var uri = request.uri
    100   var proxy = request.proxy
    101   var tunnelFnName = constructTunnelFnName(uri, proxy)
    102   return tunnel[tunnelFnName]
    103 }
    104 
    105 function Tunnel (request) {
    106   this.request = request
    107   this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList
    108   this.proxyHeaderExclusiveList = []
    109   if (typeof request.tunnel !== 'undefined') {
    110     this.tunnelOverride = request.tunnel
    111   }
    112 }
    113 
    114 Tunnel.prototype.isEnabled = function () {
    115   var self = this
    116   var request = self.request
    117     // Tunnel HTTPS by default. Allow the user to override this setting.
    118 
    119   // If self.tunnelOverride is set (the user specified a value), use it.
    120   if (typeof self.tunnelOverride !== 'undefined') {
    121     return self.tunnelOverride
    122   }
    123 
    124   // If the destination is HTTPS, tunnel.
    125   if (request.uri.protocol === 'https:') {
    126     return true
    127   }
    128 
    129   // Otherwise, do not use tunnel.
    130   return false
    131 }
    132 
    133 Tunnel.prototype.setup = function (options) {
    134   var self = this
    135   var request = self.request
    136 
    137   options = options || {}
    138 
    139   if (typeof request.proxy === 'string') {
    140     request.proxy = url.parse(request.proxy)
    141   }
    142 
    143   if (!request.proxy || !request.tunnel) {
    144     return false
    145   }
    146 
    147   // Setup Proxy Header Exclusive List and White List
    148   if (options.proxyHeaderWhiteList) {
    149     self.proxyHeaderWhiteList = options.proxyHeaderWhiteList
    150   }
    151   if (options.proxyHeaderExclusiveList) {
    152     self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList
    153   }
    154 
    155   var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList)
    156   var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList)
    157 
    158   // Setup Proxy Headers and Proxy Headers Host
    159   // Only send the Proxy White Listed Header names
    160   var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList)
    161   proxyHeaders.host = constructProxyHost(request.uri)
    162 
    163   proxyHeaderExclusiveList.forEach(request.removeHeader, request)
    164 
    165   // Set Agent from Tunnel Data
    166   var tunnelFn = getTunnelFn(request)
    167   var tunnelOptions = constructTunnelOptions(request, proxyHeaders)
    168   request.agent = tunnelFn(tunnelOptions)
    169 
    170   return true
    171 }
    172 
    173 Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
    174 Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
    175 exports.Tunnel = Tunnel