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 |
|
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 |
|
91 |
|
92 |
|
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 |
|
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 |
|
125 | delete request.src
|
126 | delete request.req
|
127 | delete request._started
|
128 | if (response.statusCode !== 401 && response.statusCode !== 307) {
|
129 |
|
130 |
|
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 |
|
139 |
|
140 |
|
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
|