rx-player
Version:
Canal+ HTML5 Video Player
206 lines (205 loc) • 9.01 kB
JavaScript
;
/**
* Copyright 2015 CANAL+ Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = request;
var log_1 = require("../../log");
var is_non_empty_string_1 = require("../is_non_empty_string");
var is_null_or_undefined_1 = require("../is_null_or_undefined");
var monotonic_timestamp_1 = require("../monotonic_timestamp");
var request_error_1 = require("./request_error");
var DEFAULT_RESPONSE_TYPE = "json";
function request(options) {
var requestOptions = {
url: options.url,
headers: options.headers,
responseType: (0, is_null_or_undefined_1.default)(options.responseType)
? DEFAULT_RESPONSE_TYPE
: options.responseType,
timeout: options.timeout,
connectionTimeout: options.connectionTimeout,
};
return new Promise(function (resolve, reject) {
var onProgress = options.onProgress, cancelSignal = options.cancelSignal;
var url = requestOptions.url, headers = requestOptions.headers, responseType = requestOptions.responseType, timeout = requestOptions.timeout, connectionTimeout = requestOptions.connectionTimeout;
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
var timeoutId;
if (timeout !== undefined) {
xhr.timeout = timeout;
// We've seen on some browser (mainly on some LG TVs), that `xhr.timeout`
// was either not supported or did not function properly despite the
// browser being recent enough to support it.
// That's why we also start a manual timeout. We do this a little later
// than the "native one" performed on the xhr assuming that the latter
// is more precise, it might also be more efficient.
timeoutId = setTimeout(function () {
clearCancellingProcess();
reject(new request_error_1.default(url, xhr.status, request_error_1.RequestErrorTypes.TIMEOUT));
}, timeout + 3000);
}
var connectionTimeoutId;
if (connectionTimeout !== undefined) {
connectionTimeoutId = setTimeout(function () {
clearCancellingProcess();
if (xhr.readyState !== XMLHttpRequest.DONE) {
xhr.abort();
}
reject(new request_error_1.default(url, xhr.status, request_error_1.RequestErrorTypes.TIMEOUT));
}, connectionTimeout);
}
xhr.responseType = responseType;
if (xhr.responseType === "document") {
xhr.overrideMimeType("text/xml");
}
if (!(0, is_null_or_undefined_1.default)(headers)) {
var _headers = headers;
for (var key in _headers) {
if (Object.prototype.hasOwnProperty.call(_headers, key)) {
xhr.setRequestHeader(key, _headers[key]);
}
}
}
var sendingTime = (0, monotonic_timestamp_1.default)();
// Handle request cancellation
var deregisterCancellationListener = null;
if (cancelSignal !== undefined) {
deregisterCancellationListener = cancelSignal.register(function abortRequest(err) {
clearCancellingProcess();
if (xhr.readyState !== XMLHttpRequest.DONE) {
xhr.abort();
}
reject(err);
});
if (cancelSignal.isCancelled()) {
return;
}
}
xhr.onerror = function onXHRError() {
clearCancellingProcess();
reject(new request_error_1.default(url, xhr.status, request_error_1.RequestErrorTypes.ERROR_EVENT));
};
xhr.ontimeout = function onXHRTimeout() {
clearCancellingProcess();
reject(new request_error_1.default(url, xhr.status, request_error_1.RequestErrorTypes.TIMEOUT));
};
if (connectionTimeout !== undefined) {
xhr.onreadystatechange = function clearConnectionTimeout() {
if (xhr.readyState >= XMLHttpRequest.HEADERS_RECEIVED) {
clearTimeout(connectionTimeoutId);
}
};
}
if (onProgress !== undefined) {
xhr.onprogress = function onXHRProgress(event) {
var currentTime = (0, monotonic_timestamp_1.default)();
onProgress({
url: url,
duration: currentTime - sendingTime,
sendingTime: sendingTime,
currentTime: currentTime,
size: event.loaded,
totalSize: event.total,
});
};
}
xhr.onload = function onXHRLoad(event) {
if (xhr.readyState === XMLHttpRequest.DONE) {
clearCancellingProcess();
if (xhr.status >= 200 && xhr.status < 300) {
var receivedTime = (0, monotonic_timestamp_1.default)();
var totalSize = xhr.response instanceof ArrayBuffer ? xhr.response.byteLength : event.total;
var status_1 = xhr.status;
var loadedResponseType = xhr.responseType;
var _url = (0, is_non_empty_string_1.default)(xhr.responseURL) ? xhr.responseURL : url;
var responseData = void 0;
if (loadedResponseType === "json") {
// IE bug where response is string with responseType json
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
responseData =
typeof xhr.response === "object"
? xhr.response
: toJSONForIE(xhr.responseText);
}
else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
responseData = xhr.response;
}
if ((0, is_null_or_undefined_1.default)(responseData)) {
reject(new request_error_1.default(url, xhr.status, request_error_1.RequestErrorTypes.PARSE_ERROR));
return;
}
resolve({
status: status_1,
url: _url,
responseType: loadedResponseType,
sendingTime: sendingTime,
receivedTime: receivedTime,
requestDuration: receivedTime - sendingTime,
size: totalSize,
responseData: responseData,
});
}
else {
reject(new request_error_1.default(url, xhr.status, request_error_1.RequestErrorTypes.ERROR_HTTP_CODE));
}
}
};
if (log_1.default.hasLevel("DEBUG")) {
var logLine = "XHR GET " + url;
if (options.responseType !== undefined) {
logLine += " type=" + options.responseType;
}
if (timeout !== undefined) {
logLine += " to=" + String(timeout / 1000);
}
if (connectionTimeout !== undefined) {
logLine += " cto=" + String(connectionTimeout / 1000);
}
if ((headers === null || headers === void 0 ? void 0 : headers.Range) !== undefined) {
logLine += " Range=" + (headers === null || headers === void 0 ? void 0 : headers.Range);
}
log_1.default.debug("utils", logLine);
}
xhr.send();
/**
* Clear resources and timers created to handle cancellation and timeouts.
*/
function clearCancellingProcess() {
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
if (connectionTimeoutId !== undefined) {
clearTimeout(connectionTimeoutId);
}
if (deregisterCancellationListener !== null) {
deregisterCancellationListener();
}
}
});
}
/**
* @param {string} data
* @returns {Object|null}
*/
function toJSONForIE(data) {
try {
return JSON.parse(data);
}
catch (_e) {
return null;
}
}