From 4aeb2fafb255c647d0b7785f7c976b6fdcf8c99d Mon Sep 17 00:00:00 2001 From: pedr Date: Sun, 19 Nov 2023 07:44:27 -0300 Subject: [PATCH] Clipper: add options to make fetchBlob exit faster, if needed (#9252) Co-authored-by: Laurent Cozic --- packages/lib/services/rest/routes/notes.ts | 17 +++++++++++------ packages/lib/shim-init-node.js | 11 +++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/lib/services/rest/routes/notes.ts b/packages/lib/services/rest/routes/notes.ts index 769973650..353468905 100644 --- a/packages/lib/services/rest/routes/notes.ts +++ b/packages/lib/services/rest/routes/notes.ts @@ -63,6 +63,11 @@ type RequestNote = { stylesheets: any; }; +type FetchOptions = { + timeout?: number; + maxRedirects?: number; +}; + async function requestNoteToNote(requestNote: RequestNote): Promise { const output: any = { title: requestNote.title ? requestNote.title : '', @@ -184,7 +189,7 @@ async function tryToGuessExtFromMimeType(response: any, mediaPath: string) { return newMediaPath; } -export async function downloadMediaFile(url: string /* , allowFileProtocolImages */) { +export async function downloadMediaFile(url: string, fetchOptions?: FetchOptions) { logger.info('Downloading media file', url); const tempDir = Setting.value('tempDir'); @@ -225,7 +230,7 @@ export async function downloadMediaFile(url: string /* , allowFileProtocolImages const localPath = fileUriToPath(url); await shim.fsDriver().copy(localPath, mediaPath); } else { - const response = await shim.fetchBlob(url, { path: mediaPath, maxRetry: 1 }); + const response = await shim.fetchBlob(url, { path: mediaPath, maxRetry: 1, ...fetchOptions }); // If we could not find the file extension from the URL, try to get it // now based on the Content-Type header. @@ -238,13 +243,13 @@ export async function downloadMediaFile(url: string /* , allowFileProtocolImages } } -async function downloadMediaFiles(urls: string[] /* , allowFileProtocolImages:boolean */) { +async function downloadMediaFiles(urls: string[], fetchOptions?: FetchOptions) { const PromisePool = require('es6-promise-pool'); const output: any = {}; const downloadOne = async (url: string) => { - const mediaPath = await downloadMediaFile(url); // , allowFileProtocolImages); + const mediaPath = await downloadMediaFile(url, fetchOptions); // , allowFileProtocolImages); if (mediaPath) output[url] = { path: mediaPath, originalUrl: url }; }; @@ -369,14 +374,14 @@ async function attachImageFromDataUrl(note: any, imageDataUrl: string, cropRect: return await shim.attachFileToNote(note, tempFilePath); } -export const extractNoteFromHTML = async (requestNote: RequestNote, requestId: number, imageSizes: any) => { +export const extractNoteFromHTML = async (requestNote: RequestNote, requestId: number, imageSizes: any, fetchOptions?: FetchOptions) => { const note = await requestNoteToNote(requestNote); const mediaUrls = extractMediaUrls(note.markup_language, note.body); logger.info(`Request (${requestId}): Downloading media files: ${mediaUrls.length}`); - const mediaFiles = await downloadMediaFiles(mediaUrls); // , allowFileProtocolImages); + const mediaFiles = await downloadMediaFiles(mediaUrls, fetchOptions); // , allowFileProtocolImages); logger.info(`Request (${requestId}): Creating resources from paths: ${Object.getOwnPropertyNames(mediaFiles).length}`); diff --git a/packages/lib/shim-init-node.js b/packages/lib/shim-init-node.js index ca74dd67d..c737f8baf 100644 --- a/packages/lib/shim-init-node.js +++ b/packages/lib/shim-init-node.js @@ -460,6 +460,11 @@ function shimInit(options = null) { if (!options.method) options.method = 'GET'; // if (!('maxRetry' in options)) options.maxRetry = 5; + // 21 maxRedirects is the default amount from follow-redirects library + // 20 seems to be the max amount that most popular browsers will allow + if (!options.maxRedirects) options.maxRedirects = 21; + if (!options.timeout) options.timeout = undefined; + const urlParse = require('url').parse; url = urlParse(url.trim()); @@ -490,6 +495,8 @@ function shimInit(options = null) { method: method, path: url.pathname + (url.query ? `?${url.query}` : ''), headers: headers, + timeout: options.timeout, + maxRedirects: options.maxRedirects, }; const resolvedProxyUrl = resolveProxyUrl(proxySettings.proxyUrl); @@ -551,6 +558,10 @@ function shimInit(options = null) { }); }); + request.on('timeout', () => { + request.destroy(new Error(`Request timed out. Timeout value: ${requestOptions.timeout}ms.`)); + }); + request.on('error', (error) => { cleanUpOnError(error); });