UNPKG

@request/core

Version:
175 lines (150 loc) 4.51 kB
var url = require('url') var utils = require('../utils') var modules = require('../modules') exports.request = function (req, options) { req._redirect = true if (options.auth && options.auth.sendImmediately === false) { req._auth = true } if (typeof options.redirect !== 'object') { options.redirect = {max: 5, followed: 0, allow: function () {return true}} } else { if (options.redirect.max === undefined) { options.redirect.max = 5 } if (options.redirect.allow === undefined) { options.redirect.allow = function () {return true} } options.redirect.followed = 0 } } exports.response = function (req, res, options) { var loc = location(res, options) if (loc && options.redirect.allow(res)) { options.redirect.followed += 1 if (options.redirect.followed === options.redirect.max) { // req.emit('error', new Error( // 'redirect: Exceeded maxRedirects. ' + // 'Probably stuck in a redirect loop ' + options.url.href)) // req._redirected = true req._redirect = false req._chunks = [] if (req._src) { req._src.close() } return } storeOriginalHost(req, options) // relative path if (!/^https?:/.test(loc)) { loc = url.resolve(options.url.href, loc) } loc = url.parse(loc) cleanup(req, res, options, loc) options.url = loc if (options.proxy) { if (utils.isTunnelEnabled(options)) { var tunnel = modules('tunnel') tunnel(req, res, options) } else { var proxy = modules('proxy') proxy(req, res, options) if (options.agent && options.agent._tunnel) { delete options.agent } } } req._redirected = true req.emit('redirect', res) req.emit('options', options) req.init(utils.filter(options)) if (req._auth) { req._chunks.forEach(function (chunk) { req.write(chunk) }) if (req._src) { req._src.resume() } } if (req._ended) { req.end() } } else { req._redirect = false // if (req._auth) { // req._chunks = [] // if (req._src) { // req._src.resume() // } // } } } function location (res, options) { var location = res.headers.get('location') if (res.statusCode >= 300 && res.statusCode < 400 && location) { if (options.redirect.all) { return location } else if (!/PATCH|PUT|POST|DELETE/.test(options.method)) { return location } } // basic auth else if (res.statusCode === 401) { if (options.headers.get('authorization')) { return options.url.path } } } function storeOriginalHost (req, options) { if (!req._redirected) { // Save the original host before any redirect (if it changes, we need to // remove any authorization headers). Also remember the case of the header // name because lots of broken servers expect Host instead of host and we // want the caller to be able to specify this. options.redirect.host = { name: req._req._headerNames.host, value: req._req._headers.host } } } function cleanup (req, res, options, location) { // handle the case where we change protocol from https to http or vice versa if (options.url.protocol !== location.protocol) { req.update(location.protocol) // delete options.agent } // store redirects // self.redirects.push({ // statusCode: res.statusCode, // location: location // }) if (options.redirect.all && options.method !== 'HEAD' && res.statusCode !== 401 && res.statusCode !== 307) { options.method = 'GET' } if (res.statusCode !== 401 && res.statusCode !== 307) { // Remove parameters from the previous response, // unless this is the second request // for a server that requires digest authentication. delete options.body delete req._src options.headers.remove('host') options.headers.remove('content-type') options.headers.remove('content-length') // Remove authorization if changing hostnames, // but not if just changing ports or protocols. // This matches the behavior of curl: // https://github.com/bagder/curl/blob/6beb0eee/lib/http.c#L710 if (location.hostname !== options.redirect.host.value.split(':')[0]) { options.headers.remove('authorization') } } if (!options.redirect.removeReferer) { options.headers.set('referer', options.url.href) } }