Initial commit
[yaffs-website] / node_modules / request / lib / redirect.js
1 'use strict'
2
3 var url = require('url')
4 var isUrl = /^https?:/
5
6 function Redirect (request) {
7   this.request = request
8   this.followRedirect = true
9   this.followRedirects = true
10   this.followAllRedirects = false
11   this.followOriginalHttpMethod = false
12   this.allowRedirect = function () {return true}
13   this.maxRedirects = 10
14   this.redirects = []
15   this.redirectsFollowed = 0
16   this.removeRefererHeader = false
17 }
18
19 Redirect.prototype.onRequest = function (options) {
20   var self = this
21
22   if (options.maxRedirects !== undefined) {
23     self.maxRedirects = options.maxRedirects
24   }
25   if (typeof options.followRedirect === 'function') {
26     self.allowRedirect = options.followRedirect
27   }
28   if (options.followRedirect !== undefined) {
29     self.followRedirects = !!options.followRedirect
30   }
31   if (options.followAllRedirects !== undefined) {
32     self.followAllRedirects = options.followAllRedirects
33   }
34   if (self.followRedirects || self.followAllRedirects) {
35     self.redirects = self.redirects || []
36   }
37   if (options.removeRefererHeader !== undefined) {
38     self.removeRefererHeader = options.removeRefererHeader
39   }
40   if (options.followOriginalHttpMethod !== undefined) {
41     self.followOriginalHttpMethod = options.followOriginalHttpMethod
42   }
43 }
44
45 Redirect.prototype.redirectTo = function (response) {
46   var self = this
47     , request = self.request
48
49   var redirectTo = null
50   if (response.statusCode >= 300 && response.statusCode < 400 && response.caseless.has('location')) {
51     var location = response.caseless.get('location')
52     request.debug('redirect', location)
53
54     if (self.followAllRedirects) {
55       redirectTo = location
56     } else if (self.followRedirects) {
57       switch (request.method) {
58         case 'PATCH':
59         case 'PUT':
60         case 'POST':
61         case 'DELETE':
62           // Do not follow redirects
63           break
64         default:
65           redirectTo = location
66           break
67       }
68     }
69   } else if (response.statusCode === 401) {
70     var authHeader = request._auth.onResponse(response)
71     if (authHeader) {
72       request.setHeader('authorization', authHeader)
73       redirectTo = request.uri
74     }
75   }
76   return redirectTo
77 }
78
79 Redirect.prototype.onResponse = function (response) {
80   var self = this
81     , request = self.request
82
83   var redirectTo = self.redirectTo(response)
84   if (!redirectTo || !self.allowRedirect.call(request, response)) {
85     return false
86   }
87
88   request.debug('redirect to', redirectTo)
89
90   // ignore any potential response body.  it cannot possibly be useful
91   // to us at this point.
92   // response.resume should be defined, but check anyway before calling. Workaround for browserify.
93   if (response.resume) {
94     response.resume()
95   }
96
97   if (self.redirectsFollowed >= self.maxRedirects) {
98     request.emit('error', new Error('Exceeded maxRedirects. Probably stuck in a redirect loop ' + request.uri.href))
99     return false
100   }
101   self.redirectsFollowed += 1
102
103   if (!isUrl.test(redirectTo)) {
104     redirectTo = url.resolve(request.uri.href, redirectTo)
105   }
106
107   var uriPrev = request.uri
108   request.uri = url.parse(redirectTo)
109
110   // handle the case where we change protocol from https to http or vice versa
111   if (request.uri.protocol !== uriPrev.protocol) {
112     delete request.agent
113   }
114
115   self.redirects.push(
116     { statusCode : response.statusCode
117     , redirectUri: redirectTo
118     }
119   )
120   if (self.followAllRedirects && request.method !== 'HEAD'
121     && response.statusCode !== 401 && response.statusCode !== 307) {
122     request.method = self.followOriginalHttpMethod ? request.method : 'GET'
123   }
124   // request.method = 'GET' // Force all redirects to use GET || commented out fixes #215
125   delete request.src
126   delete request.req
127   delete request._started
128   if (response.statusCode !== 401 && response.statusCode !== 307) {
129     // Remove parameters from the previous response, unless this is the second request
130     // for a server that requires digest authentication.
131     delete request.body
132     delete request._form
133     if (request.headers) {
134       request.removeHeader('host')
135       request.removeHeader('content-type')
136       request.removeHeader('content-length')
137       if (request.uri.hostname !== request.originalHost.split(':')[0]) {
138         // Remove authorization if changing hostnames (but not if just
139         // changing ports or protocols).  This matches the behavior of curl:
140         // https://github.com/bagder/curl/blob/6beb0eee/lib/http.c#L710
141         request.removeHeader('authorization')
142       }
143     }
144   }
145
146   if (!self.removeRefererHeader) {
147     request.setHeader('referer', uriPrev.href)
148   }
149
150   request.emit('redirect')
151
152   request.init()
153
154   return true
155 }
156
157 exports.Redirect = Redirect