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