diff --git a/lib/net/http_fetch_plugin.js b/lib/net/http_fetch_plugin.js index 45a530b36b..723948a34f 100644 --- a/lib/net/http_fetch_plugin.js +++ b/lib/net/http_fetch_plugin.js @@ -34,15 +34,15 @@ goog.require('shaka.util.MapUtils'); * @export */ shaka.net.HttpFetchPlugin = function(uri, request, requestType) { - let headers = new shaka.net.HttpFetchPlugin.Headers_(); + const headers = new shaka.net.HttpFetchPlugin.Headers_(); shaka.util.MapUtils.forEach(request.headers, function(key, value) { headers.append(key, value); }); - let controller = new shaka.net.HttpFetchPlugin.AbortController_(); + const controller = new shaka.net.HttpFetchPlugin.AbortController_(); /** @type {!RequestInit} */ - let init = { + const init = { // Edge does not treat null as undefined for body; https://bit.ly/2luyE6x body: request.body || undefined, headers: headers, @@ -51,71 +51,101 @@ shaka.net.HttpFetchPlugin = function(uri, request, requestType) { credentials: request.allowCrossSiteCredentials ? 'include' : undefined, }; - let canceled = false; - let timedOut = false; + /** @type {shaka.net.HttpFetchPlugin.AbortStatus} */ + const abortStatus = { + canceled: false, + timedOut: false, + }; // The fetch API does not timeout natively, so do a timeout manually using the // AbortController. let timeout; if (request.retryParameters.timeout) { let onTimeout = function() { - timedOut = true; + abortStatus.timedOut = true; controller.abort(); }; timeout = setTimeout(onTimeout, request.retryParameters.timeout); } - let fetch = shaka.net.HttpFetchPlugin.fetch_; - let promise = fetch(uri, init).then(function(response) { - clearTimeout(timeout); - return response.arrayBuffer().then(function(arrayBuffer) { - let headers = {}; - /** @type {Headers} */ - let responseHeaders = response.headers; - responseHeaders.forEach(function(value, key) { - // Since IE/Edge incorrectly return the header with a leading new line - // character ('\n'), we trim the header here. - headers[key.trim()] = value; - }); - - return shaka.net.HttpPluginUtils.makeResponse(headers, - arrayBuffer, response.status, uri, response.url, requestType); + const promise = shaka.net.HttpFetchPlugin.request_(uri, requestType, init, + abortStatus, timeout); + + return new shaka.util.AbortableOperation( + promise, + () => { + abortStatus.canceled = true; + controller.abort(); + return Promise.resolve(); }); - }).catch(function(error) { - clearTimeout(timeout); - if (canceled) { - return Promise.reject(new shaka.util.Error( +}; + +/** + * @param {string} uri + * @param {shaka.net.NetworkingEngine.RequestType} requestType + * @param {!RequestInit} init + * @param {shaka.net.HttpFetchPlugin.AbortStatus} abortStatus + * @param {number|undefined} timeoutId + * @return {!Promise} + */ +shaka.net.HttpFetchPlugin.request_ = async function(uri, requestType, init, + abortStatus, timeoutId) { + const fetch = shaka.net.HttpFetchPlugin.fetch_; + let response; + let arrayBuffer; + + try { + response = await fetch(uri, init); + arrayBuffer = await response.arrayBuffer(); + } catch (error) { + if (abortStatus.canceled) { + throw new shaka.util.Error( shaka.util.Error.Severity.RECOVERABLE, shaka.util.Error.Category.NETWORK, shaka.util.Error.Code.OPERATION_ABORTED, - uri, requestType)); - } else if (timedOut) { - return Promise.reject(new shaka.util.Error( + uri, requestType); + } else if (abortStatus.timedOut) { + throw new shaka.util.Error( shaka.util.Error.Severity.RECOVERABLE, shaka.util.Error.Category.NETWORK, shaka.util.Error.Code.TIMEOUT, - uri, requestType)); - } else if (error.severity == undefined) { - // Replace non-shaka errors with a generic HTTP_ERROR. - return Promise.reject(new shaka.util.Error( + uri, requestType); + } else { + throw new shaka.util.Error( shaka.util.Error.Severity.RECOVERABLE, shaka.util.Error.Category.NETWORK, shaka.util.Error.Code.HTTP_ERROR, - uri, error, requestType)); - } else { - return Promise.reject(error); + uri, error, requestType); } + } finally { + clearTimeout(timeoutId); + } + + const headers = {}; + /** @type {Headers} */ + const responseHeaders = response.headers; + responseHeaders.forEach(function(value, key) { + // Since IE/Edge incorrectly return the header with a leading new line + // character ('\n'), we trim the header here. + headers[key.trim()] = value; }); - return new shaka.util.AbortableOperation( - promise, - () => { - canceled = true; - controller.abort(); - return Promise.resolve(); - }); + return shaka.net.HttpPluginUtils.makeResponse(headers, + arrayBuffer, response.status, uri, response.url, requestType); }; +/** + * @typedef {{ + * canceled: boolean, + * timedOut: boolean + * }} + * @property {boolean} canceled + * Indicates if the request was canceled. + * @property {boolean} timedOut + * Indicates if the request timed out. + */ +shaka.net.HttpFetchPlugin.AbortStatus; + /** * Determine if the Fetch API is supported in the browser. Note: this is