From 489d9bf2c4f49ea96bd64c1560027b5eea2bde6b Mon Sep 17 00:00:00 2001 From: Joachim Schoder Date: Mon, 15 Jan 2024 13:26:31 +0100 Subject: [PATCH] Moved fetch call from rendering process to main process --- src/bridges/utils.ts | 4 ++ src/components/article.tsx | 7 ++- src/main/utils.ts | 12 ++++- src/scripts/utils.ts | 89 +++++++++----------------------------- 4 files changed, 38 insertions(+), 74 deletions(-) diff --git a/src/bridges/utils.ts b/src/bridges/utils.ts index d042022f..73b4b9cd 100644 --- a/src/bridges/utils.ts +++ b/src/bridges/utils.ts @@ -174,6 +174,10 @@ const utilsBridge = { initFontList: (): Promise> => { return ipcRenderer.invoke("init-font-list") }, + + fetchText: (url: string, isHtml: boolean = false) => { + return ipcRenderer.invoke("fetchText", url, isHtml) + } } declare global { diff --git a/src/components/article.tsx b/src/components/article.tsx index 18a640ab..0339779f 100644 --- a/src/components/article.tsx +++ b/src/components/article.tsx @@ -18,7 +18,7 @@ import { SourceTextDirection, } from "../scripts/models/source" import { shareSubmenu } from "./context-menu" -import { platformCtrl, decodeFetchResponse } from "../scripts/utils" +import { platformCtrl } from "../scripts/utils" const FONT_SIZE_OPTIONS = [12, 13, 14, 15, 16, 17, 18, 19, 20] @@ -330,9 +330,8 @@ class Article extends React.Component { this.setState({ fullContent: "", loaded: false, error: false }) const link = this.props.item.link try { - const result = await fetch(link) - if (!result || !result.ok) throw new Error() - const html = await decodeFetchResponse(result, true) + const html = await window.utils.fetchText(link, true) + if (!html) throw new Error() if (link === this.props.item.link) { this.setState({ fullContent: html }) } diff --git a/src/main/utils.ts b/src/main/utils.ts index 1f18ca76..5d4e5a68 100644 --- a/src/main/utils.ts +++ b/src/main/utils.ts @@ -1,4 +1,4 @@ -import { ipcMain, shell, dialog, app, session, clipboard } from "electron" +import { ipcMain, shell, dialog, app, session, clipboard, net } from "electron" import { WindowManager } from "./window" import fs = require("fs") import { ImageCallbackTypes, TouchBarTexts } from "../schema-types" @@ -215,7 +215,7 @@ export function setUtilsListeners(manager: WindowManager) { `new Promise(resolve => { const dismiss = () => { document.removeEventListener("mousedown", dismiss) - document.removeEventListener("scroll", dismiss) + document.removeEventListener("scroll", dismiss) resolve() } document.addEventListener("mousedown", dismiss) @@ -308,4 +308,12 @@ export function setUtilsListeners(manager: WindowManager) { disableQuoting: true, }) }) + + ipcMain.handle("fetchText", async (_, url, isHtml) => { + const response = await net.fetch(url) + if (response.status < 200 || response.status >= 300) { + throw new Error('Server error (' + response.status + ') ' + response.statusText) + } + return await response.text() + }) } diff --git a/src/scripts/utils.ts b/src/scripts/utils.ts index c62ac7db..86787417 100644 --- a/src/scripts/utils.ts +++ b/src/scripts/utils.ts @@ -35,61 +35,17 @@ const rssParser = new Parser({ type extractGeneric = Type extends Parser ? U : never export type MyParserItem = extractGeneric & Parser.Item -const CHARSET_RE = /charset=([^()<>@,;:\"/[\]?.=\s]*)/i -const XML_ENCODING_RE = /^<\?xml.+encoding="(.+?)".*?\?>/i -export async function decodeFetchResponse(response: Response, isHTML = false) { - const buffer = await response.arrayBuffer() - let ctype = - response.headers.has("content-type") && - response.headers.get("content-type") - let charset = - ctype && CHARSET_RE.test(ctype) ? CHARSET_RE.exec(ctype)[1] : undefined - let content = new TextDecoder(charset).decode(buffer) - if (charset === undefined) { - if (isHTML) { - const dom = domParser.parseFromString(content, "text/html") - charset = dom - .querySelector("meta[charset]") - ?.getAttribute("charset") - ?.toLowerCase() - if (!charset) { - ctype = dom - .querySelector("meta[http-equiv='Content-Type']") - ?.getAttribute("content") - charset = - ctype && - CHARSET_RE.test(ctype) && - CHARSET_RE.exec(ctype)[1].toLowerCase() - } - } else { - charset = - XML_ENCODING_RE.test(content) && - XML_ENCODING_RE.exec(content)[1].toLowerCase() - } - if (charset && charset !== "utf-8" && charset !== "utf8") { - content = new TextDecoder(charset).decode(buffer) - } - } - return content -} - export async function parseRSS(url: string) { - let result: Response + let html: string try { - result = await fetch(url, { credentials: "omit" }) - } catch { + html = await window.utils.fetchText(url) + } catch (e) { throw new Error(intl.get("log.networkError")) } - if (result && result.ok) { - try { - return await rssParser.parseString( - await decodeFetchResponse(result) - ) - } catch { - throw new Error(intl.get("log.parseError")) - } - } else { - throw new Error(result.status + " " + result.statusText) + try { + return await rssParser.parseString(html) + } catch { + throw new Error(intl.get("log.parseError")) } } @@ -98,23 +54,20 @@ export const domParser = new DOMParser() export async function fetchFavicon(url: string) { try { url = url.split("/").slice(0, 3).join("/") - let result = await fetch(url, { credentials: "omit" }) - if (result.ok) { - let html = await result.text() - let dom = domParser.parseFromString(html, "text/html") - let links = dom.getElementsByTagName("link") - for (let link of links) { - let rel = link.getAttribute("rel") - if ( - (rel === "icon" || rel === "shortcut icon") && - link.hasAttribute("href") - ) { - let href = link.getAttribute("href") - let parsedUrl = Url.parse(url) - if (href.startsWith("//")) return parsedUrl.protocol + href - else if (href.startsWith("/")) return url + href - else return href - } + const html = await window.utils.fetchText(url) + let dom = domParser.parseFromString(html, "text/html") + let links = dom.getElementsByTagName("link") + for (let link of links) { + let rel = link.getAttribute("rel") + if ( + (rel === "icon" || rel === "shortcut icon") && + link.hasAttribute("href") + ) { + let href = link.getAttribute("href") + let parsedUrl = Url.parse(url) + if (href.startsWith("//")) return parsedUrl.protocol + href + else if (href.startsWith("/")) return url + href + else return href } } url = url + "/favicon.ico"