diff --git a/preload/src/api/fetch.js b/preload/src/api/fetch.js index b9f105f6..6eced311 100644 --- a/preload/src/api/fetch.js +++ b/preload/src/api/fetch.js @@ -26,11 +26,12 @@ export function nativeFetch(url, options) { /** * @param {URL} url */ const execute = (url, options, redirectCount = 0) => { - const Module = url.protocol === "http" ? http : https; + const Module = url.protocol === "http:" ? http : https; const req = Module.request(url.href, { headers: options.headers ?? {}, - method: options.method ?? "GET" + method: options.method ?? "GET", + timeout: options.timeout ?? 3000 }, res => { if (redirectCodes.has(res.statusCode) && res.headers.location && options.redirect !== "manual") { redirectCount++; @@ -78,8 +79,18 @@ export function nativeFetch(url, options) { }); }); + req.on("timeout", () => { + const error = new Error("Request timed out"); + req.destroy(error); + }); + + req.on("error", error => { + state = "ABORTED"; + errors.forEach(e => e(error)); + }); + if (options.body) { - try {req.write(options.body)} + try {req.write(options.body);} catch (error) { state = "ABORTED"; errors.forEach(e => e(error)); @@ -100,14 +111,20 @@ export function nativeFetch(url, options) { } }; - try { - const parsed = new URL(url); - execute(parsed, options); - } - catch (error) { - state = "ABORTED"; - errors.forEach(e => e(error)); + /** + * Obviously parsing a URL may throw an error, but this is + * actually intended here. The caller should handle this + * gracefully. + * + * Reasoning: at this point the caller does not have a + * reference to the object below so they have no way of + * listening to the error through onError. + */ + const parsed = new URL(url); + if (parsed.protocol !== "http:" && parsed.protocol !== "https:") { + throw new Error(`Unsupported protocol: ${parsed.protocol}`); } + execute(parsed, options); return { onComplete(listener) { diff --git a/renderer/src/modules/api/fetch.js b/renderer/src/modules/api/fetch.js index 7138a15f..7fb23463 100644 --- a/renderer/src/modules/api/fetch.js +++ b/renderer/src/modules/api/fetch.js @@ -59,7 +59,13 @@ export default function fetch(url, options = {}) { if (typeof options.method === "string" && methods.has(options.method)) data.method = options.method; if (options.signal instanceof AbortSignal) data.signal = convertSignal(options.signal); - const ctx = Remote.nativeFetch(url, data); + let ctx; + try { + ctx = Remote.nativeFetch(url, data); + } + catch (error) { + return reject(error); + } ctx.onError(error => { reject(error); @@ -77,7 +83,8 @@ export default function fetch(url, options = {}) { }); resolve(req); - } catch (error) { + } + catch (error) { reject(error); } });