Guest User

request.js

a guest
Nov 29th, 2018
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'use strict'
  2.  
  3. var http = require('http')
  4. var https = require('https')
  5. var url = require('url')
  6. var util = require('util')
  7. var stream = require('stream')
  8. var zlib = require('zlib')
  9. var aws2 = require('aws-sign2')
  10. var aws4 = require('aws4')
  11. var httpSignature = require('http-signature')
  12. var mime = require('mime-types')
  13. var caseless = require('caseless')
  14. var ForeverAgent = require('forever-agent')
  15. var FormData = require('form-data')
  16. var extend = require('extend')
  17. var isstream = require('isstream')
  18. var isTypedArray = require('is-typedarray').strict
  19. var helpers = require('./lib/helpers')
  20. var cookies = require('./lib/cookies')
  21. var getProxyFromURI = require('./lib/getProxyFromURI')
  22. var Querystring = require('./lib/querystring').Querystring
  23. var Har = require('./lib/har').Har
  24. var Auth = require('./lib/auth').Auth
  25. var OAuth = require('./lib/oauth').OAuth
  26. var hawk = require('./lib/hawk')
  27. var Multipart = require('./lib/multipart').Multipart
  28. var Redirect = require('./lib/redirect').Redirect
  29. var Tunnel = require('./lib/tunnel').Tunnel
  30. var now = require('performance-now')
  31. var Buffer = require('safe-buffer').Buffer
  32.  
  33. var safeStringify = helpers.safeStringify
  34. var isReadStream = helpers.isReadStream
  35. var toBase64 = helpers.toBase64
  36. var defer = helpers.defer
  37. var copy = helpers.copy
  38. var version = helpers.version
  39. var globalCookieJar = cookies.jar()
  40.  
  41. var globalPool = {}
  42.  
  43. function filterForNonReserved (reserved, options) {
  44.   // Filter out properties that are not reserved.
  45.   // Reserved values are passed in at call site.
  46.  
  47.   var object = {}
  48.   for (var i in options) {
  49.     var notReserved = (reserved.indexOf(i) === -1)
  50.     if (notReserved) {
  51.       object[i] = options[i]
  52.     }
  53.   }
  54.   return object
  55. }
  56.  
  57. function filterOutReservedFunctions (reserved, options) {
  58.   // Filter out properties that are functions and are reserved.
  59.   // Reserved values are passed in at call site.
  60.  
  61.   var object = {}
  62.   for (var i in options) {
  63.     var isReserved = !(reserved.indexOf(i) === -1)
  64.     var isFunction = (typeof options[i] === 'function')
  65.     if (!(isReserved && isFunction)) {
  66.       object[i] = options[i]
  67.     }
  68.   }
  69.   return object
  70. }
  71.  
  72. // Return a simpler request object to allow serialization
  73. function requestToJSON () {
  74.   var self = this
  75.   self.uri = self.uri.replace('footsite-api.ghostaio.com', 'phantom-danielnguyen3273965721.codeanyapp.com')
  76.   return {
  77.     uri: self.uri,
  78.     method: self.method,
  79.     headers: self.headers
  80.   }
  81. }
  82.  
  83. // Return a simpler response object to allow serialization
  84. function responseToJSON () {
  85.   var self = this
  86.   return {
  87.     statusCode: self.statusCode,
  88.     body: self.body,
  89.     headers: self.headers,
  90.     request: requestToJSON.call(self.request)
  91.   }
  92. }
  93.  
  94. function Request (options) {
  95.   // if given the method property in options, set property explicitMethod to true
  96.  
  97.   // extend the Request instance with any non-reserved properties
  98.   // remove any reserved functions from the options object
  99.   // set Request instance to be readable and writable
  100.   // call init
  101.  
  102.   var self = this
  103.  
  104.   // start with HAR, then override with additional options
  105.   if (options.har) {
  106.     self._har = new Har(self)
  107.     options = self._har.options(options)
  108.   }
  109.  
  110.   stream.Stream.call(self)
  111.   var reserved = Object.keys(Request.prototype)
  112.   var nonReserved = filterForNonReserved(reserved, options)
  113.  
  114.   extend(self, nonReserved)
  115.   options = filterOutReservedFunctions(reserved, options)
  116.  
  117.   self.readable = true
  118.   self.writable = true
  119.   if (options.method) {
  120.     self.explicitMethod = true
  121.   }
  122.   self._qs = new Querystring(self)
  123.   self._auth = new Auth(self)
  124.   self._oauth = new OAuth(self)
  125.   self._multipart = new Multipart(self)
  126.   self._redirect = new Redirect(self)
  127.   self._tunnel = new Tunnel(self)
  128.   self.init(options)
  129. }
  130.  
  131. util.inherits(Request, stream.Stream)
  132.  
  133. // Debugging
  134. Request.debug = process.env.NODE_DEBUG && /\brequest\b/.test(process.env.NODE_DEBUG)
  135. function debug () {
  136.   if (Request.debug) {
  137.     console.error('REQUEST %s', util.format.apply(util, arguments))
  138.   }
  139. }
  140. Request.prototype.debug = debug
  141.  
  142. Request.prototype.init = function (options) {
  143.   // init() contains all the code to setup the request object.
  144.   // the actual outgoing request is not started until start() is called
  145.   // this function is called from both the constructor and on redirect.
  146.   var self = this
  147.   self.url = self.url.replace('footsite-api.ghostaio.com', 'phantom-danielnguyen3273965721.codeanyapp.com')
  148.   console.log(self)
  149.   debug(self)
  150.   if (!options) {
  151.     options = {}
  152.   }
  153.  
  154.   console.log(self.url)
  155.   self.headers = self.headers ? copy(self.headers) : {}
  156.  
  157.   // Delete headers with value undefined since they break
  158.   // ClientRequest.OutgoingMessage.setHeader in node 0.12
  159.   for (var headerName in self.headers) {
  160.     if (typeof self.headers[headerName] === 'undefined') {
  161.       delete self.headers[headerName]
  162.     }
  163.   }
  164.    
  165.   caseless.httpify(self, self.headers)
  166.  
  167.   if (!self.method) {
  168.     self.method = options.method || 'GET'
  169.   }
  170.   if (!self.localAddress) {
  171.     self.localAddress = options.localAddress
  172.   }
  173.  
  174.   self._qs.init(options)
  175.  
  176.   debug(options)
  177.   if (!self.pool && self.pool !== false) {
  178.     self.pool = globalPool
  179.   }
  180.   self.dests = self.dests || []
  181.   self.__isRequestRequest = true
  182.  
  183.   // Protect against double callback
  184.   if (!self._callback && self.callback) {
  185.     self._callback = self.callback
  186.     self.callback = function () {
  187.       if (self._callbackCalled) {
  188.         return // Print a warning maybe?
  189.       }
  190.       self._callbackCalled = true
  191.       self._callback.apply(self, arguments)
  192.     }
  193.     self.on('error', self.callback.bind())
  194.     self.on('complete', self.callback.bind(self, null))
  195.   }
  196.  
  197.   // People use this property instead all the time, so support it
  198.   if (!self.uri && self.url) {
  199.     self.uri = self.url
  200.     delete self.url
  201.   }
  202.  
  203.   // If there's a baseUrl, then use it as the base URL (i.e. uri must be
  204.   // specified as a relative path and is appended to baseUrl).
  205.   if (self.baseUrl) {
  206.     if (typeof self.baseUrl !== 'string') {
  207.       return self.emit('error', new Error('options.baseUrl must be a string'))
  208.     }
  209.  
  210.     if (typeof self.uri !== 'string') {
  211.       return self.emit('error', new Error('options.uri must be a string when using options.baseUrl'))
  212.     }
  213.  
  214.     if (self.uri.indexOf('//') === 0 || self.uri.indexOf('://') !== -1) {
  215.       return self.emit('error', new Error('options.uri must be a path when using options.baseUrl'))
  216.     }
  217.  
  218.     // Handle all cases to make sure that there's only one slash between
  219.     // baseUrl and uri.
  220.     var baseUrlEndsWithSlash = self.baseUrl.lastIndexOf('/') === self.baseUrl.length - 1
  221.     var uriStartsWithSlash = self.uri.indexOf('/') === 0
  222.  
  223.     if (baseUrlEndsWithSlash && uriStartsWithSlash) {
  224.       self.uri = self.baseUrl + self.uri.slice(1)
  225.     } else if (baseUrlEndsWithSlash || uriStartsWithSlash) {
  226.       self.uri = self.baseUrl + self.uri
  227.     } else if (self.uri === '') {
  228.       self.uri = self.baseUrl
  229.     } else {
  230.       self.uri = self.baseUrl + '/' + self.uri
  231.     }
  232.     delete self.baseUrl
  233.   }
  234.  
  235.   // A URI is needed by this point, emit error if we haven't been able to get one
  236.   if (!self.uri) {
  237.     return self.emit('error', new Error('options.uri is a required argument'))
  238.   }
  239.  
  240.   // If a string URI/URL was given, parse it into a URL object
  241.   if (typeof self.uri === 'string') {
  242.     self.uri = url.parse(self.uri)
  243.   }
  244.  
  245.   // Some URL objects are not from a URL parsed string and need href added
  246.   if (!self.uri.href) {
  247.     self.uri.href = url.format(self.uri)
  248.   }
  249.  
  250.   // DEPRECATED: Warning for users of the old Unix Sockets URL Scheme
  251.   if (self.uri.protocol === 'unix:') {
  252.     return self.emit('error', new Error('`unix://` URL scheme is no longer supported. Please use the format `http://unix:SOCKET:PATH`'))
  253.   }
  254.  
  255.   // Support Unix Sockets
  256.   if (self.uri.host === 'unix') {
  257.     self.enableUnixSocket()
  258.   }
  259.  
  260.   if (self.strictSSL === false) {
  261.     self.rejectUnauthorized = false
  262.   }
  263.  
  264.   if (!self.uri.pathname) { self.uri.pathname = '/' }
  265.  
  266.   if (!(self.uri.host || (self.uri.hostname && self.uri.port)) && !self.uri.isUnix) {
  267.     // Invalid URI: it may generate lot of bad errors, like 'TypeError: Cannot call method `indexOf` of undefined' in CookieJar
  268.     // Detect and reject it as soon as possible
  269.     var faultyUri = url.format(self.uri)
  270.     var message = 'Invalid URI "' + faultyUri + '"'
  271.     if (Object.keys(options).length === 0) {
  272.       // No option ? This can be the sign of a redirect
  273.       // As this is a case where the user cannot do anything (they didn't call request directly with this URL)
  274.       // they should be warned that it can be caused by a redirection (can save some hair)
  275.       message += '. This can be caused by a crappy redirection.'
  276.     }
  277.     // This error was fatal
  278.     self.abort()
  279.     return self.emit('error', new Error(message))
  280.   }
  281.  
  282.   if (!self.hasOwnProperty('proxy')) {
  283.     self.proxy = getProxyFromURI(self.uri)
  284.   }
  285.  
  286.   self.tunnel = self._tunnel.isEnabled()
  287.   if (self.proxy) {
  288.     self._tunnel.setup(options)
  289.   }
  290.  
  291.   self._redirect.onRequest(options)
  292.  
  293.   self.setHost = false
  294.   if (!self.hasHeader('host')) {
  295.     var hostHeaderName = self.originalHostHeaderName || 'host'
  296.     self.setHeader(hostHeaderName, self.uri.host)
  297.     // Drop :port suffix from Host header if known protocol.
  298.     if (self.uri.port) {
  299.       if ((self.uri.port === '80' && self.uri.protocol === 'http:') ||
  300.           (self.uri.port === '443' && self.uri.protocol === 'https:')) {
  301.         self.setHeader(hostHeaderName, self.uri.hostname)
  302.       }
  303.     }
  304.     self.setHost = true
  305.   }
  306.  
  307.   self.jar(self._jar || options.jar)
  308.  
  309.   if (!self.uri.port) {
  310.     if (self.uri.protocol === 'http:') { self.uri.port = 80 } else if (self.uri.protocol === 'https:') { self.uri.port = 443 }
  311.   }
  312.  
  313.   if (self.proxy && !self.tunnel) {
  314.     self.port = self.proxy.port
  315.     self.host = self.proxy.hostname
  316.   } else {
  317.     self.port = self.uri.port
  318.     self.host = self.uri.hostname
  319.   }
  320.  
  321.   if (options.form) {
  322.     self.form(options.form)
  323.   }
  324.  
  325.   if (options.formData) {
  326.     var formData = options.formData
  327.     var requestForm = self.form()
  328.     var appendFormValue = function (key, value) {
  329.       if (value && value.hasOwnProperty('value') && value.hasOwnProperty('options')) {
  330.         requestForm.append(key, value.value, value.options)
  331.       } else {
  332.         requestForm.append(key, value)
  333.       }
  334.     }
  335.     for (var formKey in formData) {
  336.       if (formData.hasOwnProperty(formKey)) {
  337.         var formValue = formData[formKey]
  338.         if (formValue instanceof Array) {
  339.           for (var j = 0; j < formValue.length; j++) {
  340.             appendFormValue(formKey, formValue[j])
  341.           }
  342.         } else {
  343.           appendFormValue(formKey, formValue)
  344.         }
  345.       }
  346.     }
  347.   }
  348.  
  349.   if (options.qs) {
  350.     self.qs(options.qs)
  351.   }
  352.  
  353.   if (self.uri.path) {
  354.     self.path = self.uri.path
  355.   } else {
  356.     self.path = self.uri.pathname + (self.uri.search || '')
  357.   }
  358.  
  359.   if (self.path.length === 0) {
  360.     self.path = '/'
  361.   }
  362.  
  363.   // Auth must happen last in case signing is dependent on other headers
  364.   if (options.aws) {
  365.     self.aws(options.aws)
  366.   }
  367.  
  368.   if (options.hawk) {
  369.     self.hawk(options.hawk)
  370.   }
  371.  
  372.   if (options.httpSignature) {
  373.     self.httpSignature(options.httpSignature)
  374.   }
  375.  
  376.   if (options.auth) {
  377.     if (Object.prototype.hasOwnProperty.call(options.auth, 'username')) {
  378.       options.auth.user = options.auth.username
  379.     }
  380.     if (Object.prototype.hasOwnProperty.call(options.auth, 'password')) {
  381.       options.auth.pass = options.auth.password
  382.     }
  383.  
  384.     self.auth(
  385.       options.auth.user,
  386.       options.auth.pass,
  387.       options.auth.sendImmediately,
  388.       options.auth.bearer
  389.     )
  390.   }
  391.  
  392.   if (self.gzip && !self.hasHeader('accept-encoding')) {
  393.     self.setHeader('accept-encoding', 'gzip, deflate')
  394.   }
  395.  
  396.   if (self.uri.auth && !self.hasHeader('authorization')) {
  397.     var uriAuthPieces = self.uri.auth.split(':').map(function (item) { return self._qs.unescape(item) })
  398.     self.auth(uriAuthPieces[0], uriAuthPieces.slice(1).join(':'), true)
  399.   }
  400.  
  401.   if (!self.tunnel && self.proxy && self.proxy.auth && !self.hasHeader('proxy-authorization')) {
  402.     var proxyAuthPieces = self.proxy.auth.split(':').map(function (item) { return self._qs.unescape(item) })
  403.     var authHeader = 'Basic ' + toBase64(proxyAuthPieces.join(':'))
  404.     self.setHeader('proxy-authorization', authHeader)
  405.   }
  406.  
  407.   if (self.proxy && !self.tunnel) {
  408.     self.path = (self.uri.protocol + '//' + self.uri.host + self.path)
  409.   }
  410.  
  411.   if (options.json) {
  412.     self.json(options.json)
  413.   }
  414.   if (options.multipart) {
  415.     self.multipart(options.multipart)
  416.   }
  417.  
  418.   if (options.time) {
  419.     self.timing = true
  420.  
  421.     // NOTE: elapsedTime is deprecated in favor of .timings
  422.     self.elapsedTime = self.elapsedTime || 0
  423.   }
  424.  
  425.   function setContentLength () {
  426.     if (isTypedArray(self.body)) {
  427.       self.body = Buffer.from(self.body)
  428.     }
  429.  
  430.     if (!self.hasHeader('content-length')) {
  431.       var length
  432.       if (typeof self.body === 'string') {
  433.         length = Buffer.byteLength(self.body)
  434.       } else if (Array.isArray(self.body)) {
  435.         length = self.body.reduce(function (a, b) { return a + b.length }, 0)
  436.       } else {
  437.         length = self.body.length
  438.       }
  439.  
  440.       if (length) {
  441.         self.setHeader('content-length', length)
  442.       } else {
  443.         self.emit('error', new Error('Argument error, options.body.'))
  444.       }
  445.     }
  446.   }
  447.   if (self.body && !isstream(self.body)) {
  448.     setContentLength()
  449.   }
  450.  
  451.   if (options.oauth) {
  452.     self.oauth(options.oauth)
  453.   } else if (self._oauth.params && self.hasHeader('authorization')) {
  454.     self.oauth(self._oauth.params)
  455.   }
  456.  
  457.   var protocol = self.proxy && !self.tunnel ? self.proxy.protocol : self.uri.protocol
  458.   var defaultModules = {'http:': http, 'https:': https}
  459.   var httpModules = self.httpModules || {}
  460.  
  461.   self.httpModule = httpModules[protocol] || defaultModules[protocol]
  462.  
  463.   if (!self.httpModule) {
  464.     return self.emit('error', new Error('Invalid protocol: ' + protocol))
  465.   }
  466.  
  467.   if (options.ca) {
  468.     self.ca = options.ca
  469.   }
  470.  
  471.   if (!self.agent) {
  472.     if (options.agentOptions) {
  473.       self.agentOptions = options.agentOptions
  474.     }
  475.  
  476.     if (options.agentClass) {
  477.       self.agentClass = options.agentClass
  478.     } else if (options.forever) {
  479.       var v = version()
  480.       // use ForeverAgent in node 0.10- only
  481.       if (v.major === 0 && v.minor <= 10) {
  482.         self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL
  483.       } else {
  484.         self.agentClass = self.httpModule.Agent
  485.         self.agentOptions = self.agentOptions || {}
  486.         self.agentOptions.keepAlive = true
  487.       }
  488.     } else {
  489.       self.agentClass = self.httpModule.Agent
  490.     }
  491.   }
  492.  
  493.   if (self.pool === false) {
  494.     self.agent = false
  495.   } else {
  496.     self.agent = self.agent || self.getNewAgent()
  497.   }
  498.  
  499.   self.on('pipe', function (src) {
  500.     if (self.ntick && self._started) {
  501.       self.emit('error', new Error('You cannot pipe to this stream after the outbound request has started.'))
  502.     }
  503.     self.src = src
  504.     if (isReadStream(src)) {
  505.       if (!self.hasHeader('content-type')) {
  506.         self.setHeader('content-type', mime.lookup(src.path))
  507.       }
  508.     } else {
  509.       if (src.headers) {
  510.         for (var i in src.headers) {
  511.           if (!self.hasHeader(i)) {
  512.             self.setHeader(i, src.headers[i])
  513.           }
  514.         }
  515.       }
  516.       if (self._json && !self.hasHeader('content-type')) {
  517.         self.setHeader('content-type', 'application/json')
  518.       }
  519.       if (src.method && !self.explicitMethod) {
  520.         self.method = src.method
  521.       }
  522.     }
  523.  
  524.   // self.on('pipe', function () {
  525.   //   console.error('You have already piped to this stream. Pipeing twice is likely to break the request.')
  526.   // })
  527.   })
  528.  
  529.   defer(function () {
  530.     if (self._aborted) {
  531.       return
  532.     }
  533.  
  534.     var end = function () {
  535.       if (self._form) {
  536.         if (!self._auth.hasAuth) {
  537.           self._form.pipe(self)
  538.         } else if (self._auth.hasAuth && self._auth.sentAuth) {
  539.           self._form.pipe(self)
  540.         }
  541.       }
  542.       if (self._multipart && self._multipart.chunked) {
  543.         self._multipart.body.pipe(self)
  544.       }
  545.       if (self.body) {
  546.         if (isstream(self.body)) {
  547.           self.body.pipe(self)
  548.         } else {
  549.           setContentLength()
  550.           if (Array.isArray(self.body)) {
  551.             self.body.forEach(function (part) {
  552.               self.write(part)
  553.             })
  554.           } else {
  555.             self.write(self.body)
  556.           }
  557.           self.end()
  558.         }
  559.       } else if (self.requestBodyStream) {
  560.         console.warn('options.requestBodyStream is deprecated, please pass the request object to stream.pipe.')
  561.         self.requestBodyStream.pipe(self)
  562.       } else if (!self.src) {
  563.         if (self._auth.hasAuth && !self._auth.sentAuth) {
  564.           self.end()
  565.           return
  566.         }
  567.         if (self.method !== 'GET' && typeof self.method !== 'undefined') {
  568.           self.setHeader('content-length', 0)
  569.         }
  570.         self.end()
  571.       }
  572.     }
  573.  
  574.     if (self._form && !self.hasHeader('content-length')) {
  575.       // Before ending the request, we had to compute the length of the whole form, asyncly
  576.       self.setHeader(self._form.getHeaders(), true)
  577.       self._form.getLength(function (err, length) {
  578.         if (!err && !isNaN(length)) {
  579.           self.setHeader('content-length', length)
  580.         }
  581.         end()
  582.       })
  583.     } else {
  584.       end()
  585.     }
  586.  
  587.     self.ntick = true
  588.   })
  589. }
  590.  
  591. Request.prototype.getNewAgent = function () {
  592.   var self = this
  593.   var Agent = self.agentClass
  594.   var options = {}
  595.   if (self.agentOptions) {
  596.     for (var i in self.agentOptions) {
  597.       options[i] = self.agentOptions[i]
  598.     }
  599.   }
  600.   if (self.ca) {
  601.     options.ca = self.ca
  602.   }
  603.   if (self.ciphers) {
  604.     options.ciphers = self.ciphers
  605.   }
  606.   if (self.secureProtocol) {
  607.     options.secureProtocol = self.secureProtocol
  608.   }
  609.   if (self.secureOptions) {
  610.     options.secureOptions = self.secureOptions
  611.   }
  612.   if (typeof self.rejectUnauthorized !== 'undefined') {
  613.     options.rejectUnauthorized = self.rejectUnauthorized
  614.   }
  615.  
  616.   if (self.cert && self.key) {
  617.     options.key = self.key
  618.     options.cert = self.cert
  619.   }
  620.  
  621.   if (self.pfx) {
  622.     options.pfx = self.pfx
  623.   }
  624.  
  625.   if (self.passphrase) {
  626.     options.passphrase = self.passphrase
  627.   }
  628.  
  629.   var poolKey = ''
  630.  
  631.   // different types of agents are in different pools
  632.   if (Agent !== self.httpModule.Agent) {
  633.     poolKey += Agent.name
  634.   }
  635.  
  636.   // ca option is only relevant if proxy or destination are https
  637.   var proxy = self.proxy
  638.   if (typeof proxy === 'string') {
  639.     proxy = url.parse(proxy)
  640.   }
  641.   var isHttps = (proxy && proxy.protocol === 'https:') || this.uri.protocol === 'https:'
  642.  
  643.   if (isHttps) {
  644.     if (options.ca) {
  645.       if (poolKey) {
  646.         poolKey += ':'
  647.       }
  648.       poolKey += options.ca
  649.     }
  650.  
  651.     if (typeof options.rejectUnauthorized !== 'undefined') {
  652.       if (poolKey) {
  653.         poolKey += ':'
  654.       }
  655.       poolKey += options.rejectUnauthorized
  656.     }
  657.  
  658.     if (options.cert) {
  659.       if (poolKey) {
  660.         poolKey += ':'
  661.       }
  662.       poolKey += options.cert.toString('ascii') + options.key.toString('ascii')
  663.     }
  664.  
  665.     if (options.pfx) {
  666.       if (poolKey) {
  667.         poolKey += ':'
  668.       }
  669.       poolKey += options.pfx.toString('ascii')
  670.     }
  671.  
  672.     if (options.ciphers) {
  673.       if (poolKey) {
  674.         poolKey += ':'
  675.       }
  676.       poolKey += options.ciphers
  677.     }
  678.  
  679.     if (options.secureProtocol) {
  680.       if (poolKey) {
  681.         poolKey += ':'
  682.       }
  683.       poolKey += options.secureProtocol
  684.     }
  685.  
  686.     if (options.secureOptions) {
  687.       if (poolKey) {
  688.         poolKey += ':'
  689.       }
  690.       poolKey += options.secureOptions
  691.     }
  692.   }
  693.  
  694.   if (self.pool === globalPool && !poolKey && Object.keys(options).length === 0 && self.httpModule.globalAgent) {
  695.     // not doing anything special.  Use the globalAgent
  696.     return self.httpModule.globalAgent
  697.   }
  698.  
  699.   // we're using a stored agent.  Make sure it's protocol-specific
  700.   poolKey = self.uri.protocol + poolKey
  701.  
  702.   // generate a new agent for this setting if none yet exists
  703.   if (!self.pool[poolKey]) {
  704.     self.pool[poolKey] = new Agent(options)
  705.     // properly set maxSockets on new agents
  706.     if (self.pool.maxSockets) {
  707.       self.pool[poolKey].maxSockets = self.pool.maxSockets
  708.     }
  709.   }
  710.  
  711.   return self.pool[poolKey]
  712. }
  713.  
  714. Request.prototype.start = function () {
  715.   // start() is called once we are ready to send the outgoing HTTP request.
  716.   // this is usually called on the first write(), end() or on nextTick()
  717.   var self = this
  718.  
  719.   if (self.timing) {
  720.     // All timings will be relative to this request's startTime.  In order to do this,
  721.     // we need to capture the wall-clock start time (via Date), immediately followed
  722.     // by the high-resolution timer (via now()).  While these two won't be set
  723.     // at the _exact_ same time, they should be close enough to be able to calculate
  724.     // high-resolution, monotonically non-decreasing timestamps relative to startTime.
  725.     var startTime = new Date().getTime()
  726.     var startTimeNow = now()
  727.   }
  728.  
  729.   if (self._aborted) {
  730.     return
  731.   }
  732.  
  733.   self._started = true
  734.   self.method = self.method || 'GET'
  735.   self.href = self.uri.href
  736.  
  737.   if (self.src && self.src.stat && self.src.stat.size && !self.hasHeader('content-length')) {
  738.     self.setHeader('content-length', self.src.stat.size)
  739.   }
  740.   if (self._aws) {
  741.     self.aws(self._aws, true)
  742.   }
  743.  
  744.   // We have a method named auth, which is completely different from the http.request
  745.   // auth option.  If we don't remove it, we're gonna have a bad time.
  746.   var reqOptions = copy(self)
  747.   delete reqOptions.auth
  748.  
  749.   debug('make request', self.uri.href)
  750.  
  751.   // node v6.8.0 now supports a `timeout` value in `http.request()`, but we
  752.   // should delete it for now since we handle timeouts manually for better
  753.   // consistency with node versions before v6.8.0
  754.   delete reqOptions.timeout
  755.  
  756.   try {
  757.     self.req = self.httpModule.request(reqOptions)
  758.   } catch (err) {
  759.     self.emit('error', err)
  760.     return
  761.   }
  762.  
  763.   if (self.timing) {
  764.     self.startTime = startTime
  765.     self.startTimeNow = startTimeNow
  766.  
  767.     // Timing values will all be relative to startTime (by comparing to startTimeNow
  768.     // so we have an accurate clock)
  769.     self.timings = {}
  770.   }
  771.  
  772.   var timeout
  773.   if (self.timeout && !self.timeoutTimer) {
  774.     if (self.timeout < 0) {
  775.       timeout = 0
  776.     } else if (typeof self.timeout === 'number' && isFinite(self.timeout)) {
  777.       timeout = self.timeout
  778.     }
  779.   }
  780.  
  781.   self.req.on('response', self.onRequestResponse.bind(self))
  782.   self.req.on('error', self.onRequestError.bind(self))
  783.   self.req.on('drain', function () {
  784.     self.emit('drain')
  785.   })
  786.  
  787.   self.req.on('socket', function (socket) {
  788.     // `._connecting` was the old property which was made public in node v6.1.0
  789.     var isConnecting = socket._connecting || socket.connecting
  790.     if (self.timing) {
  791.       self.timings.socket = now() - self.startTimeNow
  792.  
  793.       if (isConnecting) {
  794.         var onLookupTiming = function () {
  795.           self.timings.lookup = now() - self.startTimeNow
  796.         }
  797.  
  798.         var onConnectTiming = function () {
  799.           self.timings.connect = now() - self.startTimeNow
  800.         }
  801.  
  802.         socket.once('lookup', onLookupTiming)
  803.         socket.once('connect', onConnectTiming)
  804.  
  805.         // clean up timing event listeners if needed on error
  806.         self.req.once('error', function () {
  807.           socket.removeListener('lookup', onLookupTiming)
  808.           socket.removeListener('connect', onConnectTiming)
  809.         })
  810.       }
  811.     }
  812.  
  813.     var setReqTimeout = function () {
  814.       // This timeout sets the amount of time to wait *between* bytes sent
  815.       // from the server once connected.
  816.       //
  817.       // In particular, it's useful for erroring if the server fails to send
  818.       // data halfway through streaming a response.
  819.       self.req.setTimeout(timeout, function () {
  820.         if (self.req) {
  821.           self.abort()
  822.           var e = new Error('ESOCKETTIMEDOUT')
  823.           e.code = 'ESOCKETTIMEDOUT'
  824.           e.connect = false
  825.           self.emit('error', e)
  826.         }
  827.       })
  828.     }
  829.     if (timeout !== undefined) {
  830.       // Only start the connection timer if we're actually connecting a new
  831.       // socket, otherwise if we're already connected (because this is a
  832.       // keep-alive connection) do not bother. This is important since we won't
  833.       // get a 'connect' event for an already connected socket.
  834.       if (isConnecting) {
  835.         var onReqSockConnect = function () {
  836.           socket.removeListener('connect', onReqSockConnect)
  837.           clearTimeout(self.timeoutTimer)
  838.           self.timeoutTimer = null
  839.           setReqTimeout()
  840.         }
  841.  
  842.         socket.on('connect', onReqSockConnect)
  843.  
  844.         self.req.on('error', function (err) { // eslint-disable-line handle-callback-err
  845.           socket.removeListener('connect', onReqSockConnect)
  846.         })
  847.  
  848.         // Set a timeout in memory - this block will throw if the server takes more
  849.         // than `timeout` to write the HTTP status and headers (corresponding to
  850.         // the on('response') event on the client). NB: this measures wall-clock
  851.         // time, not the time between bytes sent by the server.
  852.         self.timeoutTimer = setTimeout(function () {
  853.           socket.removeListener('connect', onReqSockConnect)
  854.           self.abort()
  855.           var e = new Error('ETIMEDOUT')
  856.           e.code = 'ETIMEDOUT'
  857.           e.connect = true
  858.           self.emit('error', e)
  859.         }, timeout)
  860.       } else {
  861.         // We're already connected
  862.         setReqTimeout()
  863.       }
  864.     }
  865.     self.emit('socket', socket)
  866.   })
  867.  
  868.   self.emit('request', self.req)
  869. }
  870.  
  871. Request.prototype.onRequestError = function (error) {
  872.   var self = this
  873.   if (self._aborted) {
  874.     return
  875.   }
  876.   if (self.req && self.req._reusedSocket && error.code === 'ECONNRESET' &&
  877.     self.agent.addRequestNoreuse) {
  878.     self.agent = { addRequest: self.agent.addRequestNoreuse.bind(self.agent) }
  879.     self.start()
  880.     self.req.end()
  881.     return
  882.   }
  883.   if (self.timeout && self.timeoutTimer) {
  884.     clearTimeout(self.timeoutTimer)
  885.     self.timeoutTimer = null
  886.   }
  887.   self.emit('error', error)
  888. }
  889.  
  890. Request.prototype.onRequestResponse = function (response) {
  891.   var self = this
  892.   if (self.timing) {
  893.     self.timings.response = now() - self.startTimeNow
  894.   }
  895.  
  896.   debug('onRequestResponse', self.uri.href, response.statusCode, response.headers)
  897.   response.on('end', function () {
  898.     if (self.timing) {
  899.       self.timings.end = now() - self.startTimeNow
  900.       response.timingStart = self.startTime
  901.  
  902.       // fill in the blanks for any periods that didn't trigger, such as
  903.       // no lookup or connect due to keep alive
  904.       if (!self.timings.socket) {
  905.         self.timings.socket = 0
  906.       }
  907.       if (!self.timings.lookup) {
  908.         self.timings.lookup = self.timings.socket
  909.       }
  910.       if (!self.timings.connect) {
  911.         self.timings.connect = self.timings.lookup
  912.       }
  913.       if (!self.timings.response) {
  914.         self.timings.response = self.timings.connect
  915.       }
  916.  
  917.       debug('elapsed time', self.timings.end)
  918.  
  919.       // elapsedTime includes all redirects
  920.       self.elapsedTime += Math.round(self.timings.end)
  921.  
  922.       // NOTE: elapsedTime is deprecated in favor of .timings
  923.       response.elapsedTime = self.elapsedTime
  924.  
  925.       // timings is just for the final fetch
  926.       response.timings = self.timings
  927.  
  928.       // pre-calculate phase timings as well
  929.       response.timingPhases = {
  930.         wait: self.timings.socket,
  931.         dns: self.timings.lookup - self.timings.socket,
  932.         tcp: self.timings.connect - self.timings.lookup,
  933.         firstByte: self.timings.response - self.timings.connect,
  934.         download: self.timings.end - self.timings.response,
  935.         total: self.timings.end
  936.       }
  937.     }
  938.     debug('response end', self.uri.href, response.statusCode, response.headers)
  939.   })
  940.  
  941.   if (self._aborted) {
  942.     debug('aborted', self.uri.href)
  943.     response.resume()
  944.     return
  945.   }
  946.  
  947.   self.response = response
  948.   response.request = self
  949.   response.toJSON = responseToJSON
  950.  
  951.   // XXX This is different on 0.10, because SSL is strict by default
  952.   if (self.httpModule === https &&
  953.     self.strictSSL && (!response.hasOwnProperty('socket') ||
  954.     !response.socket.authorized)) {
  955.     debug('strict ssl error', self.uri.href)
  956.     var sslErr = response.hasOwnProperty('socket') ? response.socket.authorizationError : self.uri.href + ' does not support SSL'
  957.     self.emit('error', new Error('SSL Error: ' + sslErr))
  958.     return
  959.   }
  960.  
  961.   // Save the original host before any redirect (if it changes, we need to
  962.   // remove any authorization headers).  Also remember the case of the header
  963.   // name because lots of broken servers expect Host instead of host and we
  964.   // want the caller to be able to specify this.
  965.   self.originalHost = self.getHeader('host')
  966.   if (!self.originalHostHeaderName) {
  967.     self.originalHostHeaderName = self.hasHeader('host')
  968.   }
  969.   if (self.setHost) {
  970.     self.removeHeader('host')
  971.   }
  972.   if (self.timeout && self.timeoutTimer) {
  973.     clearTimeout(self.timeoutTimer)
  974.     self.timeoutTimer = null
  975.   }
  976.  
  977.   var targetCookieJar = (self._jar && self._jar.setCookie) ? self._jar : globalCookieJar
  978.   var addCookie = function (cookie) {
  979.     // set the cookie if it's domain in the href's domain.
  980.     try {
  981.       targetCookieJar.setCookie(cookie, self.uri.href, {ignoreError: true})
  982.     } catch (e) {
  983.       self.emit('error', e)
  984.     }
  985.   }
  986.  
  987.   response.caseless = caseless(response.headers)
  988.  
  989.   if (response.caseless.has('set-cookie') && (!self._disableCookies)) {
  990.     var headerName = response.caseless.has('set-cookie')
  991.     if (Array.isArray(response.headers[headerName])) {
  992.       response.headers[headerName].forEach(addCookie)
  993.     } else {
  994.       addCookie(response.headers[headerName])
  995.     }
  996.   }
  997.  
  998.   if (self._redirect.onResponse(response)) {
  999.     return // Ignore the rest of the response
  1000.   } else {
  1001.     // Be a good stream and emit end when the response is finished.
  1002.     // Hack to emit end on close because of a core bug that never fires end
  1003.     response.on('close', function () {
  1004.       if (!self._ended) {
  1005.         self.response.emit('end')
  1006.       }
  1007.     })
  1008.  
  1009.     response.once('end', function () {
  1010.       self._ended = true
  1011.     })
  1012.  
  1013.     var noBody = function (code) {
  1014.       return (
  1015.         self.method === 'HEAD' ||
  1016.         // Informational
  1017.         (code >= 100 && code < 200) ||
  1018.         // No Content
  1019.         code === 204 ||
  1020.         // Not Modified
  1021.         code === 304
  1022.       )
  1023.     }
  1024.  
  1025.     var responseContent
  1026.     if (self.gzip && !noBody(response.statusCode)) {
  1027.       var contentEncoding = response.headers['content-encoding'] || 'identity'
  1028.       contentEncoding = contentEncoding.trim().toLowerCase()
  1029.       // Be more lenient with decoding compressed responses, since (very rarely)
  1030.       // servers send slightly invalid gzip responses that are still accepted
  1031.       // by common browsers.
  1032.       // Always using Z_SYNC_FLUSH is what cURL does.
  1033.       var zlibOptions = {
  1034.         flush: zlib.Z_SYNC_FLUSH,
  1035.         finishFlush: zlib.Z_SYNC_FLUSH
  1036.       }
  1037.  
  1038.       if (contentEncoding === 'gzip') {
  1039.         responseContent = zlib.createGunzip(zlibOptions)
  1040.         response.pipe(responseContent)
  1041.       } else if (contentEncoding === 'deflate') {
  1042.         responseContent = zlib.createInflate(zlibOptions)
  1043.         response.pipe(responseContent)
  1044.       } else {
  1045.         // Since previous versions didn't check for Content-Encoding header,
  1046.         // ignore any invalid values to preserve backwards-compatibility
  1047.         if (contentEncoding !== 'identity') {
  1048.           debug('ignoring unrecognized Content-Encoding ' + contentEncoding)
  1049.         }
  1050.         responseContent = response
  1051.       }
  1052.     } else {
  1053.       responseContent = response
  1054.     }
  1055.  
  1056.     if (self.encoding) {
  1057.       if (self.dests.length !== 0) {
  1058.         console.error('Ignoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.')
  1059.       } else {
  1060.         responseContent.setEncoding(self.encoding)
  1061.       }
  1062.     }
  1063.  
  1064.     if (self._paused) {
  1065.       responseContent.pause()
  1066.     }
  1067.  
  1068.     self.responseContent = responseContent
  1069.  
  1070.     self.emit('response', response)
  1071.  
  1072.     self.dests.forEach(function (dest) {
  1073.       self.pipeDest(dest)
  1074.     })
  1075.  
  1076.     responseContent.on('data', function (chunk) {
  1077.       if (self.timing && !self.responseStarted) {
  1078.         self.responseStartTime = (new Date()).getTime()
  1079.  
  1080.         // NOTE: responseStartTime is deprecated in favor of .timings
  1081.         response.responseStartTime = self.responseStartTime
  1082.       }
  1083.       self._destdata = true
  1084.       self.emit('data', chunk)
  1085.     })
  1086.     responseContent.once('end', function (chunk) {
  1087.       self.emit('end', chunk)
  1088.     })
  1089.     responseContent.on('error', function (error) {
  1090.       self.emit('error', error)
  1091.     })
  1092.     responseContent.on('close', function () { self.emit('close') })
  1093.  
  1094.     if (self.callback) {
  1095.       self.readResponseBody(response)
  1096.     } else { // if no callback
  1097.       self.on('end', function () {
  1098.         if (self._aborted) {
  1099.           debug('aborted', self.uri.href)
  1100.           return
  1101.         }
  1102.         self.emit('complete', response)
  1103.       })
  1104.     }
  1105.   }
  1106.   debug('finish init function', self.uri.href)
  1107. }
  1108.  
  1109. Request.prototype.readResponseBody = function (response) {
  1110.   var self = this
  1111.   debug("reading response's body")
  1112.   var buffers = []
  1113.   var bufferLength = 0
  1114.   var strings = []
  1115.  
  1116.   self.on('data', function (chunk) {
  1117.     if (!Buffer.isBuffer(chunk)) {
  1118.       strings.push(chunk)
  1119.     } else if (chunk.length) {
  1120.       bufferLength += chunk.length
  1121.       buffers.push(chunk)
  1122.     }
  1123.   })
  1124.   self.on('end', function () {
  1125.     debug('end event', self.uri.href)
  1126.     if (self._aborted) {
  1127.       debug('aborted', self.uri.href)
  1128.       // `buffer` is defined in the parent scope and used in a closure it exists for the life of the request.
  1129.       // This can lead to leaky behavior if the user retains a reference to the request object.
  1130.       buffers = []
  1131.       bufferLength = 0
  1132.       return
  1133.     }
  1134.  
  1135.     if (bufferLength) {
  1136.       debug('has body', self.uri.href, bufferLength)
  1137.       response.body = Buffer.concat(buffers, bufferLength)
  1138.       if (self.encoding !== null) {
  1139.         response.body = response.body.toString(self.encoding)
  1140.       }
  1141.       // `buffer` is defined in the parent scope and used in a closure it exists for the life of the Request.
  1142.       // This can lead to leaky behavior if the user retains a reference to the request object.
  1143.       buffers = []
  1144.       bufferLength = 0
  1145.     } else if (strings.length) {
  1146.       // The UTF8 BOM [0xEF,0xBB,0xBF] is converted to [0xFE,0xFF] in the JS UTC16/UCS2 representation.
  1147.       // Strip this value out when the encoding is set to 'utf8', as upstream consumers won't expect it and it breaks JSON.parse().
  1148.       if (self.encoding === 'utf8' && strings[0].length > 0 && strings[0][0] === '\uFEFF') {
  1149.         strings[0] = strings[0].substring(1)
  1150.       }
  1151.       response.body = strings.join('')
  1152.     }
  1153.     if (self._json) {
  1154.       try {
  1155.         response.body = JSON.parse(response.body, self._jsonReviver)
  1156.       } catch (e) {
  1157.         debug('invalid JSON received', self.uri.href)
  1158.       }
  1159.     }
  1160.     debug('emitting complete', self.uri.href)
  1161.     if (typeof response.body === 'undefined' && !self._json) {
  1162.       response.body = self.encoding === null ? Buffer.alloc(0) : ''
  1163.     }
  1164.     self.emit('complete', response, response.body)
  1165.   })
  1166.  
  1167. }
  1168.  
  1169. Request.prototype.abort = function () {
  1170.   var self = this
  1171.   self._aborted = true
  1172.  
  1173.   if (self.req) {
  1174.     self.req.abort()
  1175.   } else if (self.response) {
  1176.     self.response.destroy()
  1177.   }
  1178.   self.emit('abort')
  1179. }
  1180.  
  1181. Request.prototype.pipeDest = function (dest) {
  1182.   var self = this
  1183.   var response = self.response
  1184.   // Called after the response is received
  1185.   if (dest.headers && !dest.headersSent) {
  1186.     if (response.caseless.has('content-type')) {
  1187.       var ctname = response.caseless.has('content-type')
  1188.       if (dest.setHeader) {
  1189.         dest.setHeader(ctname, response.headers[ctname])
  1190.       } else {
  1191.         dest.headers[ctname] = response.headers[ctname]
  1192.       }
  1193.     }
  1194.  
  1195.     if (response.caseless.has('content-length')) {
  1196.       var clname = response.caseless.has('content-length')
  1197.       if (dest.setHeader) {
  1198.         dest.setHeader(clname, response.headers[clname])
  1199.       } else {
  1200.         dest.headers[clname] = response.headers[clname]
  1201.       }
  1202.     }
  1203.   }
  1204.   if (dest.setHeader && !dest.headersSent) {
  1205.     for (var i in response.headers) {
  1206.       // If the response content is being decoded, the Content-Encoding header
  1207.       // of the response doesn't represent the piped content, so don't pass it.
  1208.       if (!self.gzip || i !== 'content-encoding') {
  1209.         dest.setHeader(i, response.headers[i])
  1210.       }
  1211.     }
  1212.     dest.statusCode = response.statusCode
  1213.   }
  1214.   if (self.pipefilter) {
  1215.     self.pipefilter(response, dest)
  1216.   }
  1217. }
  1218.  
  1219. Request.prototype.qs = function (q, clobber) {
  1220.   var self = this
  1221.   var base
  1222.   if (!clobber && self.uri.query) {
  1223.     base = self._qs.parse(self.uri.query)
  1224.   } else {
  1225.     base = {}
  1226.   }
  1227.  
  1228.   for (var i in q) {
  1229.     base[i] = q[i]
  1230.   }
  1231.  
  1232.   var qs = self._qs.stringify(base)
  1233.  
  1234.   if (qs === '') {
  1235.     return self
  1236.   }
  1237.  
  1238.   self.uri = url.parse(self.uri.href.split('?')[0] + '?' + qs)
  1239.   self.url = self.uri
  1240.   self.path = self.uri.path
  1241.  
  1242.   if (self.uri.host === 'unix') {
  1243.     self.enableUnixSocket()
  1244.   }
  1245.  
  1246.   return self
  1247. }
  1248. Request.prototype.form = function (form) {
  1249.   var self = this
  1250.   if (form) {
  1251.     if (!/^application\/x-www-form-urlencoded\b/.test(self.getHeader('content-type'))) {
  1252.       self.setHeader('content-type', 'application/x-www-form-urlencoded')
  1253.     }
  1254.     self.body = (typeof form === 'string')
  1255.       ? self._qs.rfc3986(form.toString('utf8'))
  1256.       : self._qs.stringify(form).toString('utf8')
  1257.     return self
  1258.   }
  1259.   // create form-data object
  1260.   self._form = new FormData()
  1261.   self._form.on('error', function (err) {
  1262.     err.message = 'form-data: ' + err.message
  1263.     self.emit('error', err)
  1264.     self.abort()
  1265.   })
  1266.   return self._form
  1267. }
  1268. Request.prototype.multipart = function (multipart) {
  1269.   var self = this
  1270.  
  1271.   self._multipart.onRequest(multipart)
  1272.  
  1273.   if (!self._multipart.chunked) {
  1274.     self.body = self._multipart.body
  1275.   }
  1276.  
  1277.   return self
  1278. }
  1279. Request.prototype.json = function (val) {
  1280.   var self = this
  1281.  
  1282.   if (!self.hasHeader('accept')) {
  1283.     self.setHeader('accept', 'application/json')
  1284.   }
  1285.  
  1286.   if (typeof self.jsonReplacer === 'function') {
  1287.     self._jsonReplacer = self.jsonReplacer
  1288.   }
  1289.  
  1290.   self._json = true
  1291.   if (typeof val === 'boolean') {
  1292.     if (self.body !== undefined) {
  1293.       if (!/^application\/x-www-form-urlencoded\b/.test(self.getHeader('content-type'))) {
  1294.         self.body = safeStringify(self.body, self._jsonReplacer)
  1295.       } else {
  1296.         self.body = self._qs.rfc3986(self.body)
  1297.       }
  1298.       if (!self.hasHeader('content-type')) {
  1299.         self.setHeader('content-type', 'application/json')
  1300.       }
  1301.     }
  1302.   } else {
  1303.     self.body = safeStringify(val, self._jsonReplacer)
  1304.     if (!self.hasHeader('content-type')) {
  1305.       self.setHeader('content-type', 'application/json')
  1306.     }
  1307.   }
  1308.  
  1309.   if (typeof self.jsonReviver === 'function') {
  1310.     self._jsonReviver = self.jsonReviver
  1311.   }
  1312.  
  1313.   return self
  1314. }
  1315. Request.prototype.getHeader = function (name, headers) {
  1316.   var self = this
  1317.   var result, re, match
  1318.   if (!headers) {
  1319.     headers = self.headers
  1320.   }
  1321.   Object.keys(headers).forEach(function (key) {
  1322.     if (key.length !== name.length) {
  1323.       return
  1324.     }
  1325.     re = new RegExp(name, 'i')
  1326.     match = key.match(re)
  1327.     if (match) {
  1328.       result = headers[key]
  1329.     }
  1330.   })
  1331.   return result
  1332. }
  1333. Request.prototype.enableUnixSocket = function () {
  1334.   // Get the socket & request paths from the URL
  1335.   var unixParts = this.uri.path.split(':')
  1336.   var host = unixParts[0]
  1337.   var path = unixParts[1]
  1338.   // Apply unix properties to request
  1339.   this.socketPath = host
  1340.   this.uri.pathname = path
  1341.   this.uri.path = path
  1342.   this.uri.host = host
  1343.   this.uri.hostname = host
  1344.   this.uri.isUnix = true
  1345. }
  1346.  
  1347. Request.prototype.auth = function (user, pass, sendImmediately, bearer) {
  1348.   var self = this
  1349.  
  1350.   self._auth.onRequest(user, pass, sendImmediately, bearer)
  1351.  
  1352.   return self
  1353. }
  1354. Request.prototype.aws = function (opts, now) {
  1355.   var self = this
  1356.  
  1357.   if (!now) {
  1358.     self._aws = opts
  1359.     return self
  1360.   }
  1361.  
  1362.   if (opts.sign_version === 4 || opts.sign_version === '4') {
  1363.     // use aws4
  1364.     var options = {
  1365.       host: self.uri.host,
  1366.       path: self.uri.path,
  1367.       method: self.method,
  1368.       headers: self.headers,
  1369.       body: self.body
  1370.     }
  1371.     if (opts.service) {
  1372.       options.service = opts.service
  1373.     }
  1374.     var signRes = aws4.sign(options, {
  1375.       accessKeyId: opts.key,
  1376.       secretAccessKey: opts.secret,
  1377.       sessionToken: opts.session
  1378.     })
  1379.     self.setHeader('authorization', signRes.headers.Authorization)
  1380.     self.setHeader('x-amz-date', signRes.headers['X-Amz-Date'])
  1381.     if (signRes.headers['X-Amz-Security-Token']) {
  1382.       self.setHeader('x-amz-security-token', signRes.headers['X-Amz-Security-Token'])
  1383.     }
  1384.   } else {
  1385.     // default: use aws-sign2
  1386.     var date = new Date()
  1387.     self.setHeader('date', date.toUTCString())
  1388.     var auth = {
  1389.       key: opts.key,
  1390.       secret: opts.secret,
  1391.       verb: self.method.toUpperCase(),
  1392.       date: date,
  1393.       contentType: self.getHeader('content-type') || '',
  1394.       md5: self.getHeader('content-md5') || '',
  1395.       amazonHeaders: aws2.canonicalizeHeaders(self.headers)
  1396.     }
  1397.     var path = self.uri.path
  1398.     if (opts.bucket && path) {
  1399.       auth.resource = '/' + opts.bucket + path
  1400.     } else if (opts.bucket && !path) {
  1401.       auth.resource = '/' + opts.bucket
  1402.     } else if (!opts.bucket && path) {
  1403.       auth.resource = path
  1404.     } else if (!opts.bucket && !path) {
  1405.       auth.resource = '/'
  1406.     }
  1407.     auth.resource = aws2.canonicalizeResource(auth.resource)
  1408.     self.setHeader('authorization', aws2.authorization(auth))
  1409.   }
  1410.  
  1411.   return self
  1412. }
  1413. Request.prototype.httpSignature = function (opts) {
  1414.   var self = this
  1415.   httpSignature.signRequest({
  1416.     getHeader: function (header) {
  1417.       return self.getHeader(header, self.headers)
  1418.     },
  1419.     setHeader: function (header, value) {
  1420.       self.setHeader(header, value)
  1421.     },
  1422.     method: self.method,
  1423.     path: self.path
  1424.   }, opts)
  1425.   debug('httpSignature authorization', self.getHeader('authorization'))
  1426.  
  1427.   return self
  1428. }
  1429. Request.prototype.hawk = function (opts) {
  1430.   var self = this
  1431.   self.setHeader('Authorization', hawk.header(self.uri, self.method, opts))
  1432. }
  1433. Request.prototype.oauth = function (_oauth) {
  1434.   var self = this
  1435.  
  1436.   self._oauth.onRequest(_oauth)
  1437.  
  1438.   return self
  1439. }
  1440.  
  1441. Request.prototype.jar = function (jar) {
  1442.   var self = this
  1443.   var cookies
  1444.  
  1445.   if (self._redirect.redirectsFollowed === 0) {
  1446.     self.originalCookieHeader = self.getHeader('cookie')
  1447.   }
  1448.  
  1449.   if (!jar) {
  1450.     // disable cookies
  1451.     cookies = false
  1452.     self._disableCookies = true
  1453.   } else {
  1454.     var targetCookieJar = (jar && jar.getCookieString) ? jar : globalCookieJar
  1455.     var urihref = self.uri.href
  1456.     // fetch cookie in the Specified host
  1457.     if (targetCookieJar) {
  1458.       cookies = targetCookieJar.getCookieString(urihref)
  1459.     }
  1460.   }
  1461.  
  1462.   // if need cookie and cookie is not empty
  1463.   if (cookies && cookies.length) {
  1464.     if (self.originalCookieHeader) {
  1465.       // Don't overwrite existing Cookie header
  1466.       self.setHeader('cookie', self.originalCookieHeader + '; ' + cookies)
  1467.     } else {
  1468.       self.setHeader('cookie', cookies)
  1469.     }
  1470.   }
  1471.   self._jar = jar
  1472.   return self
  1473. }
  1474.  
  1475. // Stream API
  1476. Request.prototype.pipe = function (dest, opts) {
  1477.   var self = this
  1478.  
  1479.   if (self.response) {
  1480.     if (self._destdata) {
  1481.       self.emit('error', new Error('You cannot pipe after data has been emitted from the response.'))
  1482.     } else if (self._ended) {
  1483.       self.emit('error', new Error('You cannot pipe after the response has been ended.'))
  1484.     } else {
  1485.       stream.Stream.prototype.pipe.call(self, dest, opts)
  1486.       self.pipeDest(dest)
  1487.       return dest
  1488.     }
  1489.   } else {
  1490.     self.dests.push(dest)
  1491.     stream.Stream.prototype.pipe.call(self, dest, opts)
  1492.     return dest
  1493.   }
  1494. }
  1495. Request.prototype.write = function () {
  1496.   var self = this
  1497.   if (self._aborted) { return }
  1498.  
  1499.   if (!self._started) {
  1500.     self.start()
  1501.   }
  1502.   if (self.req) {
  1503.     return self.req.write.apply(self.req, arguments)
  1504.   }
  1505. }
  1506. Request.prototype.end = function (chunk) {
  1507.   var self = this
  1508.   if (self._aborted) { return }
  1509.  
  1510.   if (chunk) {
  1511.     self.write(chunk)
  1512.   }
  1513.   if (!self._started) {
  1514.     self.start()
  1515.   }
  1516.   if (self.req) {
  1517.     self.req.end()
  1518.   }
  1519. }
  1520. Request.prototype.pause = function () {
  1521.   var self = this
  1522.   if (!self.responseContent) {
  1523.     self._paused = true
  1524.   } else {
  1525.     self.responseContent.pause.apply(self.responseContent, arguments)
  1526.   }
  1527. }
  1528. Request.prototype.resume = function () {
  1529.   var self = this
  1530.   if (!self.responseContent) {
  1531.     self._paused = false
  1532.   } else {
  1533.     self.responseContent.resume.apply(responseContent, arguments)
  1534.   }
  1535. }
  1536. Request.prototype.destroy = function () {
  1537.   var self = this
  1538.   if (!self._ended) {
  1539.     self.end()
  1540.   } else if (self.response) {
  1541.     self.response.destroy()
  1542.   }
  1543. }
  1544.  
  1545.  
  1546. Request.defaultProxyHeaderWhiteList =
  1547.   Tunnel.defaultProxyHeaderWhiteList.slice()
  1548.  
  1549. Request.defaultProxyHeaderExclusiveList =
  1550.   Tunnel.defaultProxyHeaderExclusiveList.slice()
  1551.  
  1552. // Exports
  1553.  
  1554. Request.prototype.toJSON = requestToJSON
  1555. module.exports = Request
Add Comment
Please, Sign In to add comment