From fca4db80217ddc52973408da282227d23b6843d1 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Thu, 29 Apr 2021 08:32:32 -0400 Subject: [PATCH] Better handle network error when fetching sublist Reported internally: > STR -- > > Import https://cdn.statically.io/gh/uBlockOrigin/uAssets/master/filters/filters.txt > as a Custom filter list. > > Observe the filter count at 24K instead of true count > being 29K. > > Force updating is sometimes compiling 24K filters and > on subsequent updates 29K, so I narrowed it down to > this host. Findings: One of the sublists was erroring when being fetched on this particular CDN server (reason unknown). uBO was not properly handling network errors when fetching a sublist. This commit make it so that if a sublist can't be fetched, then the error is propagated as if it affected the whole list, in which case uBO will use an alternative URL if any. --- src/js/assets.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/js/assets.js b/src/js/assets.js index f5a284c57..977197c2c 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -245,6 +245,8 @@ api.fetchFilterList = async function(mainlistURL) { const sublistURLs = new Set(); // https://github.com/uBlockOrigin/uBlock-issues/issues/1113 + // Process only `!#include` directives which are not excluded by an + // `!#if` directive. const processIncludeDirectives = function(results) { const out = []; const reInclude = /^!#include +(\S+)/gm; @@ -297,10 +299,19 @@ api.fetchFilterList = async function(mainlistURL) { let allParts = [ this.fetchText(mainlistURL) ]; - for (;;) { - allParts = processIncludeDirectives(await Promise.all(allParts)); - if ( allParts.every(v => typeof v === 'string') ) { break; } - } + // Abort processing `include` directives if at least one included sublist + // can't be fetched. + do { + allParts = await Promise.all(allParts); + const part = allParts.find(part => { + return typeof part === 'object' && part.error !== undefined; + }); + if ( part !== undefined ) { + return { url: mainlistURL, content: '', error: part.error }; + } + allParts = processIncludeDirectives(allParts); + } while ( allParts.some(part => typeof part !== 'string') ); + // If we reach this point, this means all fetches were successful. return { url: mainlistURL, content: allParts.length === 1