Repository: darkreader/darkreader
Pull request #2323 (2020-04-18 16:45:45)

Fix resolving absolute paths for non-index pages
Related issue #1077

[Test-pages.zip](https://github.com/darkreader/darkreader/files/4497032/Test-pages.zip)
That's the test pages I've used.

As you know mostly if not all modern website don't have .html .htm .php after their pages as they use index.html or similar so when you request the url it was automaticly grab index.html for you etc.

But as for older websites they sometimes still use .html and .php for their sub domains sites. That can causes issues with loading images. As of like [this site](https://www.musl-libc.org/how.html) It's loads an image on ![](https://i.imgur.com/1cUELyY.png) on the .listpanel (This screenshot was been made with this fix as you can see the background image).
As in the css of this sites it's sets the background-image to `    background-image: url(puzzle-a2.svg);` An incorrect way for modern browsers and HTML5 but back than an very normal way to load images. 

So darkreader will come to the image and spit back out that it absoluteURL is at `https://www.musl-libc.org/how.html` While this will be correct if how.html wasn't a file but a folder. 

With this Patch it will check if the last pathPart(not the image ofc) ends with .html .htm .php and splice this from the array as this isn't a real path/folder but a file. And it will check if the pottential .html .htm .php isn't a backwards indicator.

As of the test pages you will need to host it on a localhost 
That can be simply with python
`python -m http.server 1337` for Python 3 on windows
`python3 -m http.server 1337` for Python 3 on Linux distro's

You will find their some files and folders. I think you can figure yourself out to test this first without the fix and than with the fix and see that nonindex.html will as asked get the good url to load the image and in SomeFolder/FolderForBackwardsTest you will find the both files have ../ in the css to show it will detect automaticcly if the potetional is a backwards indicator.

Regards,
Your new member Gusted

Gusted: Approved the unit test and the Simplifer looks good
Gusted: > I've simplified it a little bit and added some tests. Not sure if I understand how CSS files resolve paths correctly.

The current implemetation is Correct so if the test pass it should be a green light.
alexanderby: Need to find some doc how CSS resolves files paths.
Gusted: [CSS level-1](https://www.w3.org/TR/CSS1/#url)
[CSS level-2](https://www.w3.org/TR/CSS2/syndata.html#uri)
[CSS level-3](https://drafts.csswg.org/css-values-3/#urls)
[CSS level-4](https://drafts.csswg.org/css-values-4/#urls)

Patch:
diff --git a/Create language he.config b/Create language he.config
new file mode 100644
index 00000000..306f9ffb
--- /dev/null
+++ b/Create language he.config
@@ -0,0 +1,183 @@
+@extension_descript
+מצב אפל לכל אתר. תשמור על העיניים שלך, השתמש בעיצוב כהה לגלישה בלילה או אפי' ביום.
+
+@loading_please_wait
+טוען... נא המתן
+
+
+#==== Top section ====
+
+@on
+פעיל
+
+@off
+כבוי
+
+@toggle_current_site
+הוסף/הסר אתר נוכחי מהרשימה
+
+@setup_hotkey_toggle_site
+הוסף/הסר אתר נוכחי מהרשימה
+הגדר מקש קיצור
+
+@toggle_extension
+הפעל/כבה את התוסף
+
+@setup_hotkey_toggle_extension
+הפעל/כבה את התוסף
+הגדר מקש קיצור
+
+@automation
+הפעלה אוטומטית:
+
+@set_active_hours
+הגדר שעות פעילות
+
+@set_location
+הפעל לאחר השקיעה במיקום זה
+
+@longitude
+קו אורך
+
+@latitude
+קו רוחב
+
+@page_protected
+דף זה מוגן
+על ידי הדפדפן
+
+@page_in_dark_list
+אתר זה נמצא
+ברשימה אפלה גלובלית
+
+@system_dark_mode
+השתמש בסכמת הצבעים של המערכת
+
+@System_dark_mode_descript
+הפעל כאשר מצב החשכה של המערכת פועל
+
+
+#==== Filter ====
+
+@filter
+מסנן
+
+@mode
+מצב
+
+@dark
+אפל
+
+@light
+מואר
+
+@brightness
+בהירות
+
+@contrast
+ניגודיות
+
+@grayscale
+גווני אפור
+
+@sepia
+גווני חום-אדמדם
+
+@only_for
+רק עבור
+
+@only_for_descript
+החל הגדרות באתר הנוכחי בלבד
+
+
+#==== Site list ====
+
+@site_list
+רשימת אתרים
+
+@invert_listed_only
+רק מה שברשימה
+
+@not_invert_listed
+רק מה שלא ברשימה
+
+@add_site_to_list
+הוסף אתר נוכחי לרשימה
+
+@setup_add_site_hotkey
+הגדר מקש קיצור להוספת אתר
+
+
+#==== More settings ====
+
+@more
+עוד
+
+@select_font
+בחר גופן
+
+@text_stroke
+מריחת טקסט
+
+@try_experimental_theme_engines
+נסה מנועי ערכת נושא ניסיוניים:
+פילטר + שומר על רוויה בצבעים, משתמש ב- GPU
+נושא סטטי מייצר נושא מהיר פשוט
+נושא דינמי מנתח צבעים ותמונות
+
+@engine_filter
+מסנן
+
+@engine_filter_plus
+מסנן+
+
+@engine_static
+סטטי
+
+@engine_dynamic
+דינמי
+
+@theme_generation_mode
+מצב יצירת ערכת נושא
+
+@custom_browser_theme_on
+מותאם אישית
+
+@custom_browser_theme_off
+ברירת מחדל
+
+@change_browser_theme
+שנה את ערכת נושא הדפדפן
+
+
+#==== Footer ====
+
+@privacy 
+פרטיות
+
+@help 
+עזרה
+
+@donate 
+לתרום
+
+@news 
+חדשות
+
+@read_more 
+קרא עוד
+
+@open_dev_tools
+Dev tools
+
+
+#==== Store listing ====
+
+@store_listing
+תוסף טיפוח לעיניים זה מאפשר למצב לילה ליצור ערכות נושא כהות לאתרי אינטרנט גלישה. קורא כהה ממיר צבעים בהירים מה שהופך אותם לניגודיות גבוהה וקל לקריאה בלילה.
+
+ניתן להתאים את הבהירות, הניגודיות, מסנן חום-אדמדם, מצב כהה, הגדרות גופן ורשימת אתרים להתעלמות.
+
+Reader Dark אינו מציג מודעות ואינו שולח את נתוני המשתמש לשום מקום. זהו קוד פתוח לחלוטין https://github.com/darkreader/darkreader
+
+לצורך פעולה תקינה, השבת תוספים דומים. צפייה נעימה!
diff --git a/package.json b/package.json
index 9b9b5a9e..a7e0364a 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
     "debug": "node tasks/debug.js",
     "prepublishOnly": "npm test && npm run api",
     "release": "npm test && node tasks/release.js",
-    "test": "jest --config=tests/jest.config.js"
+    "test": "jest --config=tests/jest.config.js",
+    "test:inject": "jest --config=tests/inject/jest.config.js"
   },
   "main": "darkreader.js",
   "repository": {
diff --git a/src/inject/dynamic-theme/url.ts b/src/inject/dynamic-theme/url.ts
index 08691385..63c5dd52 100644
--- a/src/inject/dynamic-theme/url.ts
+++ b/src/inject/dynamic-theme/url.ts
@@ -16,7 +16,12 @@ export function getAbsoluteURL($base: string, $relative: string) {
         const u = parseURL(`${b.protocol}//${b.host}${$relative}`);
         return u.href;
     }
-    const pathParts = b.pathname.split('/').concat($relative.split('/')).filter((p) => p);
+    let pathParts = b.pathname.split('/');
+    const lastPathPart = pathParts[pathParts.length - 1];
+    if (lastPathPart.match(/\.[a-z]+$/i)) {
+        pathParts.pop();
+    }
+    pathParts = pathParts.concat(...$relative.split('/')).filter((p) => p);
     let backwardIndex: number;
     while ((backwardIndex = pathParts.indexOf('..')) > 0) {
         pathParts.splice(backwardIndex - 1, 2);


Test patch:
diff --git a/tests/inject/dynamic.tests.ts b/tests/inject/dynamic.tests.ts
new file mode 100644
index 00000000..45fcc458
--- /dev/null
+++ b/tests/inject/dynamic.tests.ts
@@ -0,0 +1,10 @@
+import {getAbsoluteURL} from '../../src/inject/dynamic-theme/url';
+
+test('Absolute URL', () => {
+    expect(getAbsoluteURL('https://www.google.com', '/image.jpg')).toBe('https://www.google.com/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path', '/image.jpg')).toBe('https://www.google.com/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path', 'image.jpg')).toBe('https://www.google.com/path/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/long/path', '../image.jpg')).toBe('https://www.google.com/long/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path/page.html', 'image.jpg')).toBe('https://www.google.com/path/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path/page.html', '../image.jpg')).toBe('https://www.google.com/image.jpg');
+});
diff --git a/tests/inject/jest.config.js b/tests/inject/jest.config.js
new file mode 100644
index 00000000..bb1ff3e4
--- /dev/null
+++ b/tests/inject/jest.config.js
@@ -0,0 +1,26 @@
+module.exports = {
+    verbose: true,
+    testEnvironment: 'jsdom',
+    transform: {
+        '^.+\\.ts(x?)$': 'ts-jest'
+    },
+    testRegex: 'tests/inject/.*\\.tests\\.ts(x?)$',
+    moduleFileExtensions: [
+        'ts',
+        'tsx',
+        'js'
+    ],
+    collectCoverage: false,
+    coverageDirectory: 'coverage',
+    collectCoverageFrom: [
+        'src/**/*.{ts,tsx}'
+    ],
+    coveragePathIgnorePatterns: [
+        '^.+\\.d\\.ts$'
+    ],
+    globals: {
+        'ts-jest': {
+            tsConfig: './tests/inject/tsconfig.json'
+        }
+    }
+};
diff --git a/tests/inject/tsconfig.json b/tests/inject/tsconfig.json
new file mode 100644
index 00000000..8b2052d4
--- /dev/null
+++ b/tests/inject/tsconfig.json
@@ -0,0 +1,10 @@
+{
+    "extends": "../../src/tsconfig",
+    "compilerOptions": {
+        "module": "commonjs",
+        "outDir": "",
+        "types": [
+            "jest"
+        ]
+    }
+}
diff --git a/tests/jest.config.js b/tests/jest.config.js
index e4f41732..5482690a 100644
--- a/tests/jest.config.js
+++ b/tests/jest.config.js
@@ -4,7 +4,7 @@ module.exports = {
     transform: {
         '^.+\\.ts(x?)$': 'ts-jest'
     },
-    testRegex: 'tests/.*\\.tests\\.ts(x?)$',
+    testRegex: 'tests/[^/]*\\.tests\\.ts(x?)$',
     moduleFileExtensions: [
         'ts',
         'tsx',