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