From 2c193317b115168ffa5aea6e18b489b8715cfc0e Mon Sep 17 00:00:00 2001 From: Jack Bates Date: Tue, 13 Sep 2016 10:36:03 -0700 Subject: [PATCH] Cross-origin HTTP redirect workaround --- lib/webconn.js | 52 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/lib/webconn.js b/lib/webconn.js index c52dad6d..133f7383 100644 --- a/lib/webconn.js +++ b/lib/webconn.js @@ -124,12 +124,7 @@ WebConn.prototype.httpRequest = function (pieceIndex, offset, length, cb) { range: 'bytes=' + start + '-' + end } } - get.concat(opts, function (err, res, data) { - if (hasError) return - if (err) { - hasError = true - return cb(err) - } + function onResponse (res, data) { if (res.statusCode < 200 || res.statusCode >= 300) { hasError = true return cb(new Error('Unexpected HTTP status code ' + res.statusCode)) @@ -147,6 +142,51 @@ WebConn.prototype.httpRequest = function (pieceIndex, offset, length, cb) { cb(null, ret) } } + } + get.concat(opts, function (err, res, data) { + if (hasError) return + if (err) { + // Browsers allow HTTP redirects for simple cross-origin + // requests but not for requests that require preflight. + // Use a simple request to unravel any redirects and get the + // final URL. Retry the original request with the new URL if + // it's different. + // + // This test is imperfect but it's simple and good for common + // cases. It catches all cross-origin cases but matches a few + // same-origin cases too. + if (typeof window === 'undefined' || url.startsWith(window.location.origin + '/')) { + hasError = true + return cb(err) + } + + return get.head(url, function (errHead, res) { + if (hasError) return + if (errHead) { + hasError = true + return cb(errHead) + } + if (res.statusCode < 200 || res.statusCode >= 300) { + hasError = true + return cb(new Error('Unexpected HTTP status code ' + res.statusCode)) + } + if (res.url === url) { + hasError = true + return cb(err) + } + + opts.url = res.url + get.concat(opts, function (err, res, data) { + if (hasError) return + if (err) { + hasError = true + return cb(err) + } + onResponse(res, data) + }) + }) + } + onResponse(res, data) }) }) }