Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
// Tests which icon URLs UrlbarUtils.getRemoteImageUrl hands on as they are and
// which it wraps in `moz-remote-image:` so the image decodes outside the
// parent process (bug 2012436).
"use strict";
const SIZE = 16;
// The icon of a rich suggestion, as the search provider sends it.
const DATA_URL =
"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
// A controller whose view renders in a content process, which decodes what it
// displays itself.
const CONTENT_CONTROLLER = { rendersInContentProcess: true };
/**
* Asserts that an icon URL came back wrapped in `moz-remote-image:`.
*
* @param {string} iconUrl
* The URL passed to `getRemoteIconUrl`.
* @param {?string} result
* What `getRemoteIconUrl` returned.
* @return {URL}
* A `URL` object created from `result`.
*/
function assertWrapped(iconUrl, result) {
let url = URL.parse(result);
Assert.equal(url?.protocol, "moz-remote-image:", `${iconUrl} is wrapped`);
Assert.equal(
url.searchParams.get("url"),
iconUrl,
"The wrapper carries the original URL"
);
return url;
}
add_task(function trustedSchemesPassThrough() {
// These are the browser's own images, so there is nothing to re-encode.
for (let iconUrl of [
"chrome://global/skin/icons/search-glass.svg",
"about:logo",
]) {
Assert.equal(
UrlbarUtils.getRemoteImageUrl({ url: iconUrl, size: SIZE }),
iconUrl,
`${iconUrl} is used as it is`
);
}
});
add_task(function untrustedSchemesAreWrapped() {
for (let iconUrl of [
DATA_URL,
]) {
assertWrapped(
iconUrl,
UrlbarUtils.getRemoteImageUrl({ url: iconUrl, size: SIZE })
);
}
});
add_task(function unexpectedSchemesAreWrapped() {
// A provider can send anything. None of these reach an <img> unwrapped, and
// `moz-remote-image:` produces no image for them.
for (let iconUrl of [
"javascript:alert(1)",
]) {
assertWrapped(
iconUrl,
UrlbarUtils.getRemoteImageUrl({ url: iconUrl, size: SIZE })
);
}
});
add_task(function nonUrlsYieldNull() {
for (let iconUrl of [
"",
"not a url",
"example.com/favicon.ico",
"//host/x",
]) {
Assert.equal(
UrlbarUtils.getRemoteImageUrl({ url: iconUrl, size: SIZE }),
null,
`${iconUrl} is not a URL`
);
}
});
add_task(function contentProcessViewTakesTheIconAsItIs() {
for (let iconUrl of [
DATA_URL,
"chrome://global/skin/icons/search-glass.svg",
]) {
Assert.equal(
UrlbarUtils.getRemoteImageUrl({
url: iconUrl,
size: SIZE,
controller: CONTENT_CONTROLLER,
}),
iconUrl,
`${iconUrl} is used as it is`
);
}
// The scheme check the wrapper would apply doesn't apply here, but the page
// still can't load these -- http because its CSP allows only https:, data:,
// blob: and chrome: -- so the row falls back to a broken-image icon.
for (let iconUrl of [
"javascript:alert(1)",
]) {
Assert.equal(
UrlbarUtils.getRemoteImageUrl({
url: iconUrl,
size: SIZE,
controller: CONTENT_CONTROLLER,
}),
iconUrl,
`${iconUrl} is used as it is`
);
}
Assert.equal(
UrlbarUtils.getRemoteImageUrl({
url: "not a url",
size: SIZE,
controller: CONTENT_CONTROLLER,
}),
null,
"A string that isn't a URL is still rejected"
);
});
add_task(function noSize() {
let bareUrl = "https://example.com/no-size";
let wrappedUrl = UrlbarUtils.getRemoteImageUrl({ url: bareUrl });
let parsedUrl = assertWrapped(bareUrl, wrappedUrl);
Assert.ok(
!parsedUrl.searchParams.has("size"),
"The created moz-remote-image URL should not have a `size` search param"
);
});