diff --git a/src/jsc/modules/linkedjsdomwrapper.js b/src/jsc/modules/linkedjsdomwrapper.js index 30b2cee..7199fe1 100755 --- a/src/jsc/modules/linkedjsdomwrapper.js +++ b/src/jsc/modules/linkedjsdomwrapper.js @@ -216,92 +216,146 @@ crypto.getRandomValues = getRandom; }; })(); -setTimeout.apply = function(thisArg, args) { - if (!args || args.length === 0) return setTimeout(function() {}, 0); - var callback = args[0]; - var delay = args[1]; - var callbackArgs = args.slice(2); - return setTimeout(function() { - callback.apply(null, callbackArgs); - }, delay); -}; -setTimeout.call = function(thisArg, callback, delay) { - var args = Array.prototype.slice.call(arguments, 3); - return setTimeout(function() { - callback.apply(null, args); - }, delay); -}; -setTimeout.bind = function(thisArg) { - var boundArgs = Array.prototype.slice.call(arguments, 1); - return function() { - var args = boundArgs.concat(Array.prototype.slice.call(arguments)); - return setTimeout.apply(null, args); - }; -}; +(function (global) { + 'use strict'; -clearTimeout = (function(originalClearTimeout) { - return function(id) { - if (id === null || typeof id === "undefined") { - return undefined; - } - return originalClearTimeout(id); - }; -})(clearTimeout); - -clearTimeout.apply = function(thisArg, args) { - return clearTimeout(args && args[0]); -}; -clearTimeout.call = function(thisArg, id) { - return clearTimeout(id); -}; -clearTimeout.bind = function(thisArg) { - return function(id) { return clearTimeout(id); }; -}; - -setInterval.apply = function(thisArg, args) { - if (!args || args.length === 0) return setInterval(function() {}, 0); - var callback = args[0]; - var delay = args[1]; - var callbackArgs = args.slice(2); - return setInterval(function() { - callback.apply(null, callbackArgs); - }, delay); -}; -setInterval.call = function(thisArg, callback, delay) { - var args = Array.prototype.slice.call(arguments, 3); - return setInterval(function() { - callback.apply(null, args); - }, delay); -}; -setInterval.bind = function(thisArg) { - var boundArgs = Array.prototype.slice.call(arguments, 1); - return function() { - var args = boundArgs.concat(Array.prototype.slice.call(arguments)); - return setInterval.apply(null, args); - }; -}; + var nativeSetTimeout = global.setTimeout; + var nativeClearTimeout = global.clearTimeout; + var nativeSetInterval = global.setInterval; + var nativeClearInterval = global.clearInterval; -clearInterval = (function(originalClearInterval) { - return function(id) { - if (id === null || typeof id === "undefined") { - return undefined; - } - return originalClearInterval(id); - }; -})(clearInterval); - -clearInterval.apply = function(thisArg, args) { - return clearInterval(args && args[0]); -}; -clearInterval.call = function(thisArg, id) { - return clearInterval(id); -}; -clearInterval.bind = function(thisArg) { - return function(id) { return clearInterval(id); }; -}; - -window.setInterval = setInterval; -window.clearTimeout = clearTimeout; -window.setTimeout = setTimeout; -window.clearInterval = clearInterval; + function invokeCallback(callback, args) { + callback.apply(global, args); + } + + function createTimerWrapper(nativeFn) { + + var wrapper = function (callback, delay) { + + // Match native behavior: reject invalid callbacks + if (typeof callback !== "function") { + throw new TypeError( + "setTimeout/setInterval callback must be a function" + ); + } + + var args = Array.prototype.slice.call(arguments, 2); + + return nativeFn(function () { + + try { + + invokeCallback(callback, args); + + } catch (e) { + console.error( + "Timer callback error:", + e + ); + if (e && e.stack) { + console.error(e.stack); + } + throw e; + } + + }, delay); + }; + + wrapper.apply = function (thisArg, args) { + return Function.prototype.apply.call( + wrapper, + thisArg, + args || [] + ); + }; + + wrapper.call = function (thisArg) { + return Function.prototype.apply.call( + wrapper, + thisArg, + Array.prototype.slice.call(arguments, 1) + ); + }; + + wrapper.bind = function (thisArg) { + + var boundArgs = + Array.prototype.slice.call(arguments, 1); + + return function () { + + return wrapper.apply( + null, + boundArgs.concat( + Array.prototype.slice.call(arguments) + ) + ); + }; + }; + + return wrapper; + } + + function createClearWrapper(nativeFn) { + + var wrapper = function (id) { + return nativeFn(id); + }; + + wrapper.apply = function (thisArg, args) { + return nativeFn(args && args[0]); + }; + + wrapper.call = function (thisArg, id) { + return nativeFn(id); + }; + + // Fixed bind() to preserve bound arguments + wrapper.bind = function (thisArg) { + + var boundArgs = + Array.prototype.slice.call(arguments, 1); + + return function () { + + var args = boundArgs.concat( + Array.prototype.slice.call(arguments) + ); + + return nativeFn.apply( + null, + args.length ? args : [undefined] + ); + }; + }; + + return wrapper; + } + + var wrappedSetTimeout = + createTimerWrapper(nativeSetTimeout); + + var wrappedSetInterval = + createTimerWrapper(nativeSetInterval); + + var wrappedClearTimeout = + createClearWrapper(nativeClearTimeout); + + var wrappedClearInterval = + createClearWrapper(nativeClearInterval); + + // Install on window + global.setTimeout = wrappedSetTimeout; + global.setInterval = wrappedSetInterval; + global.clearTimeout = wrappedClearTimeout; + global.clearInterval = wrappedClearInterval; + + // Install on execution global too + if (typeof globalThis !== "undefined") { + globalThis.setTimeout = wrappedSetTimeout; + globalThis.setInterval = wrappedSetInterval; + globalThis.clearTimeout = wrappedClearTimeout; + globalThis.clearInterval = wrappedClearInterval; + } +})(window); diff --git a/src/jsc/modules/node-fetch.js b/src/jsc/modules/node-fetch.js index b7657c0..123a575 100755 --- a/src/jsc/modules/node-fetch.js +++ b/src/jsc/modules/node-fetch.js @@ -1471,7 +1471,12 @@ function consumeBody() { } if (!Buffer.isBuffer(chunk)) { - chunk = Buffer.from(chunk); + try { + chunk = Buffer.from(chunk); + } catch (e) { + reject(new FetchError(`Invalid response body while trying to fetch ${_this4.url}: unable to convert chunk to Buffer`,'system',e)); + return; + } } if (_this4.size && accumBytes + chunk.length > _this4.size) { @@ -2577,21 +2582,33 @@ function fetch(url, opts) { clearTimeout(reqTimeout); } - if (request.timeout) { - reqTimeout = setTimeout(function () { - reject(new FetchError(`network timeout at: ${request.url}`, 'request-timeout')); - finalize(); - }, request.timeout); - } + if (request.timeout) { + const startTimeout = function () { + if (reqTimeout) { + return; + } + reqTimeout = setTimeout(function () { + reject(new FetchError(`network timeout at: ${request.url}`,'request-timeout')); + finalize(); + }, request.timeout); + }; + + if (typeof req.once === 'function') { + req.once('socket', startTimeout); + + // fallback for runtimes that never emit socket + setTimeout(startTimeout, 0); + } else { + startTimeout(); + } + } req.on('error', function (err) { - reject(new FetchError(`request to ${request.url} failed, reason: ${getErrorReason(err)}`, 'system', err)); - - if (response && response.body) { - destroyStream(response.body, err); - } - - finalize(); + reject(new FetchError(`request to ${request.url} failed, reason: ${getErrorReason(err)}`,'system',err)); + if (response && response.body) { + destroyStream(response.body, err); + } + finalize(); }); fixResponseChunkedTransferBadEnding(req, function (err) {