Skip to content
Permalink
Browse files

Fix: Use correct base URL in `getElementByUrl`

Close #2148
  • Loading branch information...
antross authored and molant committed Apr 2, 2019
1 parent 9ad9ad3 commit bff51557e4fdb9bf921d3dbe60a85d897fe9abde
@@ -232,7 +232,7 @@ export default class JSDOMConnector implements IConnector {
debug(`Console: ${err}`);
});

this._resourceLoader = new CustomResourceLoader(this, fetchEnd.response.body.content);
this._resourceLoader = new CustomResourceLoader(this, fetchEnd.response.body.content, this.finalHref);

const jsdom = new JSDOM(this._targetNetworkData.response.body.content, {
beforeParse: beforeParse(this.finalHref),
@@ -14,12 +14,14 @@ const debug: debug.IDebugger = d(__filename);

export default class CustomResourceLoader extends ResourceLoader {
private _connector: JSDOMConnector;
private _finalHref: string;
private _HTMLDocument: HTMLDocument;

public constructor(connector: JSDOMConnector, html: string) {
public constructor(connector: JSDOMConnector, html: string, finalHref: string) {
super();

this._connector = connector;
this._finalHref = finalHref;
this._HTMLDocument = createHTMLDocument(html);
}

@@ -38,7 +40,7 @@ export default class CustomResourceLoader extends ResourceLoader {
* To do so, we create a query from the element returned by jsdom and
* look for it in our `HTMLDocument`.
*/
const element = getElementByUrl(this._HTMLDocument, url);
const element = getElementByUrl(this._HTMLDocument, url, this._finalHref);
const urlAsUrl = new URL(url);
let resourceUrl: string = urlAsUrl.href;

@@ -95,7 +95,7 @@ export default class WebExtensionConnector implements IConnector {
const url = event.request.url;

if (this._document) {
event.element = getElementByUrl(this._document, url);
event.element = getElementByUrl(this._document, url, location.href);
}
}

@@ -23,7 +23,7 @@ const getSrcsetUrls = (srcset: string): string[] => {
return urls;
};

export default (dom: HTMLDocument, url: string): HTMLElement | null => {
export default (dom: HTMLDocument, url: string, base: string): HTMLElement | null => {
// TODO: Cache dom.querySelectorAll?.
const elements = dom.querySelectorAll('[href],[src],[poster],[srcset]').filter((element: any) => {
const elementUrl = element.getAttribute('href') || element.getAttribute('src') || element.getAttribute('poster');
@@ -35,7 +35,7 @@ export default (dom: HTMLDocument, url: string): HTMLElement | null => {

const absoluteUrls = elementUrls.map((relativeUrl) => {
// TODO: Cache the absolute URL, so we don't run new URL() for the same URL.
return new URL(relativeUrl, url).href;
return new URL(relativeUrl, base).href;
});

if (absoluteUrls.includes(url)) {
@@ -0,0 +1,86 @@
import test from 'ava';

import createHTMLDocument from '../../../../src/lib/utils/dom/create-html-document';
import getElementByUrl from '../../../../src/lib/utils/dom/get-element-by-url';

test('Find by URL match (no match)', (t) => {
const dom = createHTMLDocument(`
<img src="test1.png">
`);

const element = getElementByUrl(dom, 'http://example.com/test2.png', 'http://example.com/index.html');

t.is(element, null);
});

test('Find by URL match (no match, different origin)', (t) => {
const dom = createHTMLDocument(`
<img src="test.png">
`);

const element = getElementByUrl(dom, 'http://example2.com/test.png', 'http://example.com/index.html');

t.is(element, null);
});

test('Find by URL match (relative src)', (t) => {
const url = 'test.png';
const dom = createHTMLDocument(`
<img src="${url}">
`);

const element = getElementByUrl(dom, `http://example.com/${url}`, 'http://example.com/index.html');

t.not(element, null);
t.is(element!.getAttribute('src'), url);
});

test('Find by URL match (relative subdirectory src)', (t) => {
const url = '../images/test.png';
const dom = createHTMLDocument(`
<img src="${url}">
`);

const element = getElementByUrl(dom, 'http://example.com/images/test.png', 'http://example.com/pages/test.html');

t.not(element, null);
t.is(element!.getAttribute('src'), url);
});

test('Find by URL match (root relative subdirectory src)', (t) => {
const url = '/images/test.png';
const dom = createHTMLDocument(`
<img src="${url}">
`);

const element = getElementByUrl(dom, `http://example.com${url}`, 'http://example.com/pages/test.html');

t.not(element, null);
t.is(element!.getAttribute('src'), url);
});

test('Find by URL match (absolute src)', (t) => {
const url = 'http://example2.com/images/test.png';
const dom = createHTMLDocument(`
<img src="${url}">
`);

const element = getElementByUrl(dom, url, 'http://example.com/index.html');

t.not(element, null);
t.is(element!.getAttribute('src'), url);
});

test('Find by URL match (data-uri src)', (t) => {
// Red dot example data-uri from https://en.wikipedia.org/wiki/Data_URI_scheme
const url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const dom = createHTMLDocument(`
<img src="test.png">
<img src="${url}">
`);

const element = getElementByUrl(dom, url, 'http://example.com/index.html');

t.not(element, null);
t.is(element!.getAttribute('src'), url);
});
@@ -141,7 +141,7 @@ export class Connector implements IConnector {
* `type` can be "parser", "script", "preload", and "other": https://chromedevtools.github.io/debugger-protocol-viewer/tot/Network/#type-Initiator
*/
if (['parser', 'other'].includes(type) && requestUrl.startsWith('http')) {
return getElementByUrl(dom, requestUrl);
return getElementByUrl(dom, requestUrl, this._finalHref);
}

return null;

0 comments on commit bff5155

Please sign in to comment.
You can’t perform that action at this time.