[6a3a178] | 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 | var 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 | var 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({ statusCode: response.statusCode, redirectUri: redirectTo })
|
---|
| 116 |
|
---|
| 117 | if (self.followAllRedirects && request.method !== 'HEAD' &&
|
---|
| 118 | response.statusCode !== 401 && response.statusCode !== 307) {
|
---|
| 119 | request.method = self.followOriginalHttpMethod ? request.method : 'GET'
|
---|
| 120 | }
|
---|
| 121 | // request.method = 'GET' // Force all redirects to use GET || commented out fixes #215
|
---|
| 122 | delete request.src
|
---|
| 123 | delete request.req
|
---|
| 124 | delete request._started
|
---|
| 125 | if (response.statusCode !== 401 && response.statusCode !== 307) {
|
---|
| 126 | // Remove parameters from the previous response, unless this is the second request
|
---|
| 127 | // for a server that requires digest authentication.
|
---|
| 128 | delete request.body
|
---|
| 129 | delete request._form
|
---|
| 130 | if (request.headers) {
|
---|
| 131 | request.removeHeader('host')
|
---|
| 132 | request.removeHeader('content-type')
|
---|
| 133 | request.removeHeader('content-length')
|
---|
| 134 | if (request.uri.hostname !== request.originalHost.split(':')[0]) {
|
---|
| 135 | // Remove authorization if changing hostnames (but not if just
|
---|
| 136 | // changing ports or protocols). This matches the behavior of curl:
|
---|
| 137 | // https://github.com/bagder/curl/blob/6beb0eee/lib/http.c#L710
|
---|
| 138 | request.removeHeader('authorization')
|
---|
| 139 | }
|
---|
| 140 | }
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | if (!self.removeRefererHeader) {
|
---|
| 144 | request.setHeader('referer', uriPrev.href)
|
---|
| 145 | }
|
---|
| 146 |
|
---|
| 147 | request.emit('redirect')
|
---|
| 148 |
|
---|
| 149 | request.init()
|
---|
| 150 |
|
---|
| 151 | return true
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | exports.Redirect = Redirect
|
---|