зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central a=merge
This commit is contained in:
Коммит
da3293e62c
|
@ -60,7 +60,7 @@ rev = "3224e2dee65c0726c448484d4c3c43956b9330ec"
|
|||
[source."https://github.com/bytecodealliance/wasmtime"]
|
||||
git = "https://github.com/bytecodealliance/wasmtime"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
rev = "fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
|
||||
[source."https://github.com/badboy/failure"]
|
||||
git = "https://github.com/badboy/failure"
|
||||
|
|
10
.cron.yml
10
.cron.yml
|
@ -316,6 +316,16 @@ jobs:
|
|||
when:
|
||||
- {hour: 4, minute: 00}
|
||||
|
||||
- name: perftest-on-autoland
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: perftest-auto
|
||||
target-tasks-method: perftest-on-autoland
|
||||
run-on-projects:
|
||||
- autoland
|
||||
when:
|
||||
- {hour: 4, minute: 00}
|
||||
|
||||
- name: scriptworker-canary
|
||||
job:
|
||||
type: trigger-action
|
||||
|
|
|
@ -753,7 +753,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
dependencies = [
|
||||
"cranelift-entity 0.66.0",
|
||||
]
|
||||
|
@ -761,7 +761,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cranelift-bforest",
|
||||
|
@ -778,7 +778,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-entity 0.66.0",
|
||||
|
@ -787,7 +787,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
|
@ -797,12 +797,12 @@ source = "git+https://github.com/PLSysSec/lucet_sandbox_compiler?rev=6594bb9dfab
|
|||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
|
@ -813,7 +813,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.66.0"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"cranelift-entity 0.66.0",
|
||||
|
|
|
@ -75,8 +75,8 @@ failure_derive = { git = "https://github.com/badboy/failure", rev = "64af847bc5f
|
|||
|
||||
[patch.crates-io.cranelift-codegen]
|
||||
git = "https://github.com/bytecodealliance/wasmtime"
|
||||
rev = "25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
rev = "fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
|
||||
[patch.crates-io.cranelift-wasm]
|
||||
git = "https://github.com/bytecodealliance/wasmtime"
|
||||
rev = "25e31739a63b7a33a4a34c961b88606c76670e46"
|
||||
rev = "fc88898e9ad7766feadfa0954c4594fcccd86b92"
|
||||
|
|
|
@ -67,6 +67,7 @@ const MONITOR_RESPONSE_PROPS = [
|
|||
|
||||
let gTestOverride = null;
|
||||
let monitorResponse = null;
|
||||
let entrypoint = "direct";
|
||||
|
||||
class AboutProtectionsParent extends JSWindowActorParent {
|
||||
constructor() {
|
||||
|
@ -379,6 +380,13 @@ class AboutProtectionsParent extends JSWindowActorParent {
|
|||
case "GetShowProxyCard":
|
||||
let card = await this.shouldShowProxyCard();
|
||||
return card;
|
||||
|
||||
case "RecordEntryPoint":
|
||||
entrypoint = aMessage.data.entrypoint;
|
||||
break;
|
||||
|
||||
case "FetchEntryPoint":
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
|
|
@ -62,8 +62,6 @@ support-files =
|
|||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_beforeunload_duplicate_dialogs.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_blob-channelname.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug321000.js]
|
||||
skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
function test() {
|
||||
var file = new File(
|
||||
[new Blob(["test"], { type: "text/plain" })],
|
||||
"test-name"
|
||||
);
|
||||
var url = URL.createObjectURL(file);
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: url,
|
||||
loadUsingSystemPrincipal: true,
|
||||
});
|
||||
|
||||
is(channel.contentDispositionFilename, "test-name", "filename matches");
|
||||
}
|
|
@ -201,7 +201,7 @@ let JSWINDOWACTORS = {
|
|||
},
|
||||
},
|
||||
|
||||
matches: ["about:protections"],
|
||||
matches: ["about:protections", "about:protections?*"],
|
||||
},
|
||||
|
||||
AboutReader: {
|
||||
|
|
|
@ -527,6 +527,19 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
|
|||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "text"
|
||||
})))))))) : null;
|
||||
|
||||
case "video":
|
||||
return this.props.content.tiles.source ? react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: `tiles-media-section ${this.props.content.tiles.media_type}`
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "fade"
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("video", {
|
||||
className: "media",
|
||||
autoPlay: "true",
|
||||
loop: "true",
|
||||
muted: "true",
|
||||
src: _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__["AboutWelcomeUtils"].hasDarkMode() ? this.props.content.tiles.source.dark : this.props.content.tiles.source.default
|
||||
})) : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -771,6 +784,10 @@ const AboutWelcomeUtils = {
|
|||
bubbles: true,
|
||||
detail
|
||||
}));
|
||||
},
|
||||
|
||||
hasDarkMode() {
|
||||
return document.body.hasAttribute("lwt-newtab-brighttext");
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -100,6 +100,7 @@ body {
|
|||
--welcome-button-text-color: #FFF;
|
||||
--welcome-button-background-hover-color: #003EAA;
|
||||
--welcome-button-background-active-color: #002275;
|
||||
--about-welcome-media-fade: linear-gradient(transparent, transparent 40%, #F9F9FA);
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
|
@ -122,7 +123,8 @@ body {
|
|||
--welcome-card-button-background-color: rgba(12, 12, 13, 0.3);
|
||||
--welcome-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
|
||||
--welcome-card-button-background-active-color: rgba(12, 12, 13, 0.7);
|
||||
--welcome-button-box-shadow-color: rgba(249, 249, 250, 0.2); }
|
||||
--welcome-button-box-shadow-color: rgba(249, 249, 250, 0.2);
|
||||
--about-welcome-media-fade: linear-gradient(transparent, transparent 35%, #1D1133, #1D1133); }
|
||||
|
||||
.welcomeCardGrid {
|
||||
margin: 0;
|
||||
|
@ -316,7 +318,9 @@ body {
|
|||
font-weight: normal;
|
||||
margin: 0 6px;
|
||||
color: var(--grey-subtitle-1);
|
||||
line-height: 28px; }
|
||||
line-height: 28px;
|
||||
max-width: 750px;
|
||||
letter-spacing: -0.01em; }
|
||||
.multistageContainer .tiles-theme-container {
|
||||
margin: 10px auto;
|
||||
border: 0; }
|
||||
|
@ -423,6 +427,30 @@ body {
|
|||
background-color: #E25920; }
|
||||
.multistageContainer .tiles-topsites-section .site:nth-child(5) .icon {
|
||||
background-color: #0250BB; }
|
||||
.multistageContainer .tiles-media-section {
|
||||
align-self: center;
|
||||
position: relative;
|
||||
margin-top: -12px;
|
||||
height: 400px;
|
||||
margin-bottom: -155px; }
|
||||
.multistageContainer .tiles-media-section .fade {
|
||||
height: 390px;
|
||||
width: 800px;
|
||||
position: absolute;
|
||||
background-image: var(--about-welcome-media-fade); }
|
||||
.multistageContainer .tiles-media-section .media {
|
||||
height: 390px;
|
||||
width: 800px; }
|
||||
@media (prefers-reduced-motion) {
|
||||
.multistageContainer .tiles-media-section {
|
||||
height: 200px;
|
||||
width: 800px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 12px; }
|
||||
.multistageContainer .tiles-media-section.privacy {
|
||||
background: top no-repeat url("../data/content/assets/firefox-protections.svg"); }
|
||||
.multistageContainer .tiles-media-section .media {
|
||||
opacity: 0; } }
|
||||
.multistageContainer button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
|
@ -435,7 +463,9 @@ body {
|
|||
white-space: nowrap;
|
||||
background-color: var(--newtab-button-primary-color);
|
||||
color: var(--welcome-button-text-color);
|
||||
border-radius: 4px; }
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
z-index: 1; }
|
||||
.multistageContainer button.primary:focus {
|
||||
background: var(--welcome-button-background-hover-color);
|
||||
box-shadow: 0 0 0 1px var(--welcome-button-box-shadow-inset-color) inset, 0 0 0 1px var(--welcome-button-box-shadow-inset-color), 0 0 0 4px var(--welcome-button-box-shadow-color); }
|
||||
|
@ -474,7 +504,8 @@ body {
|
|||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin-top: auto;
|
||||
padding: 32px 0 66px; }
|
||||
padding: 32px 0 66px;
|
||||
z-index: 1; }
|
||||
.multistageContainer .steps.has-disclaimer {
|
||||
padding-bottom: 0; }
|
||||
.multistageContainer .steps .indicator {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src resource: chrome:;">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; media-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src resource: chrome:;">
|
||||
<title data-l10n-id="onboarding-welcome-header"></title>
|
||||
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png">
|
||||
<link rel="stylesheet" href="resource://activity-stream/aboutwelcome/aboutwelcome.css">
|
||||
|
|
|
@ -36,6 +36,7 @@ body {
|
|||
--welcome-button-text-color: #FFF;
|
||||
--welcome-button-background-hover-color: #003EAA;
|
||||
--welcome-button-background-active-color: #002275;
|
||||
--about-welcome-media-fade: linear-gradient(transparent, transparent 40%, #F9F9FA);
|
||||
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu',
|
||||
'Helvetica Neue', sans-serif;
|
||||
|
@ -62,6 +63,7 @@ body {
|
|||
--welcome-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
|
||||
--welcome-card-button-background-active-color: rgba(12, 12, 13, 0.7);
|
||||
--welcome-button-box-shadow-color: rgba(249, 249, 250, 0.2);
|
||||
--about-welcome-media-fade: linear-gradient(transparent, transparent 35%, #1D1133, #1D1133);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,6 +320,8 @@ body {
|
|||
margin: 0 6px;
|
||||
color: var(--grey-subtitle-1);
|
||||
line-height: 28px;
|
||||
max-width: 750px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,6 +492,41 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.tiles-media-section {
|
||||
align-self: center;
|
||||
position: relative;
|
||||
margin-top: -12px;
|
||||
height: 400px;
|
||||
margin-bottom: -155px;
|
||||
|
||||
.fade {
|
||||
height: 390px;
|
||||
width: 800px;
|
||||
position: absolute;
|
||||
background-image: var(--about-welcome-media-fade);
|
||||
}
|
||||
|
||||
.media {
|
||||
height: 390px;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
height: 200px;
|
||||
width: 800px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&.privacy {
|
||||
background: top no-repeat url('../data/content/assets/firefox-protections.svg');
|
||||
}
|
||||
|
||||
.media {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
|
@ -502,6 +541,8 @@ body {
|
|||
background-color: var(--newtab-button-primary-color);
|
||||
color: var(--welcome-button-text-color);
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&:focus {
|
||||
background: var(--welcome-button-background-hover-color);
|
||||
|
@ -565,6 +606,7 @@ body {
|
|||
justify-content: center;
|
||||
margin-top: auto;
|
||||
padding: 32px 0 66px;
|
||||
z-index: 1;
|
||||
|
||||
&.has-disclaimer {
|
||||
padding-bottom: 0;
|
||||
|
|
|
@ -281,6 +281,25 @@ export class WelcomeScreen extends React.PureComponent {
|
|||
</div>
|
||||
</div>
|
||||
) : null;
|
||||
case "video":
|
||||
return this.props.content.tiles.source ? (
|
||||
<div
|
||||
className={`tiles-media-section ${this.props.content.tiles.media_type}`}
|
||||
>
|
||||
<div className="fade" />
|
||||
<video
|
||||
className="media"
|
||||
autoPlay="true"
|
||||
loop="true"
|
||||
muted="true"
|
||||
src={
|
||||
AboutWelcomeUtils.hasDarkMode()
|
||||
? this.props.content.tiles.source.dark
|
||||
: this.props.content.tiles.source.default
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ export const AboutWelcomeUtils = {
|
|||
})
|
||||
);
|
||||
},
|
||||
hasDarkMode() {
|
||||
return document.body.hasAttribute("lwt-newtab-brighttext");
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_WELCOME_CONTENT = {
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
После Ширина: | Высота: | Размер: 5.7 KiB |
Двоичные данные
browser/components/newtab/data/content/assets/privacy-onboarding-dark.webm
Normal file
Двоичные данные
browser/components/newtab/data/content/assets/privacy-onboarding-dark.webm
Normal file
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -8,18 +8,21 @@ const BASE_URI =
|
|||
"privatebrowsing/test/browser/empty_file.html";
|
||||
|
||||
add_task(async function test() {
|
||||
info("Creating a normal window...");
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
let tab = win.gBrowser.selectedBrowser;
|
||||
BrowserTestUtils.loadURI(tab, BASE_URI);
|
||||
await BrowserTestUtils.browserLoaded(tab);
|
||||
const loaded = BrowserTestUtils.browserLoaded(
|
||||
gBrowser.selectedBrowser,
|
||||
false,
|
||||
BASE_URI
|
||||
);
|
||||
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, BASE_URI);
|
||||
await loaded;
|
||||
|
||||
let blobURL;
|
||||
|
||||
info("Creating a blob URL...");
|
||||
await SpecialPowers.spawn(tab, [], function() {
|
||||
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
|
||||
return Promise.resolve(
|
||||
content.window.URL.createObjectURL(new content.window.Blob([123]))
|
||||
content.window.URL.createObjectURL(
|
||||
new Blob([123], { type: "text/plain" })
|
||||
)
|
||||
);
|
||||
}).then(newURL => {
|
||||
blobURL = newURL;
|
||||
|
@ -28,12 +31,19 @@ add_task(async function test() {
|
|||
info("Blob URL: " + blobURL);
|
||||
|
||||
info("Creating a private window...");
|
||||
|
||||
let privateWin = await BrowserTestUtils.openNewBrowserWindow({
|
||||
private: true,
|
||||
});
|
||||
let privateTab = privateWin.gBrowser.selectedBrowser;
|
||||
BrowserTestUtils.loadURI(privateTab, BASE_URI);
|
||||
await BrowserTestUtils.browserLoaded(privateTab);
|
||||
|
||||
const privateTabLoaded = BrowserTestUtils.browserLoaded(
|
||||
privateTab,
|
||||
false,
|
||||
BASE_URI
|
||||
);
|
||||
await BrowserTestUtils.loadURI(privateTab, BASE_URI);
|
||||
await privateTabLoaded;
|
||||
|
||||
await SpecialPowers.spawn(privateTab, [blobURL], function(url) {
|
||||
return new Promise(resolve => {
|
||||
|
@ -55,6 +65,5 @@ add_task(async function test() {
|
|||
);
|
||||
});
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
await BrowserTestUtils.closeWindow(privateWin);
|
||||
});
|
||||
|
|
|
@ -8,12 +8,49 @@ import LockwiseCard from "./lockwise-card.js";
|
|||
import MonitorCard from "./monitor-card.js";
|
||||
import ProxyCard from "./proxy-card.js";
|
||||
|
||||
// We need to send the close telemetry before unload while we still have a connection to RPM.
|
||||
window.addEventListener("beforeunload", () => {
|
||||
document.sendTelemetryEvent("close", "protection_report");
|
||||
});
|
||||
let cbCategory = RPMGetStringPref("browser.contentblocking.category");
|
||||
document.sendTelemetryEvent = (action, object, value = "") => {
|
||||
// eslint-disable-next-line no-undef
|
||||
RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
|
||||
category: cbCategory,
|
||||
});
|
||||
};
|
||||
|
||||
let { protocol, pathname, searchParams } = new URL(document.location);
|
||||
|
||||
let searchParamsChanged = false;
|
||||
if (searchParams.has("entrypoint")) {
|
||||
RPMSendAsyncMessage("RecordEntryPoint", {
|
||||
entrypoint: searchParams.get("entrypoint"),
|
||||
});
|
||||
// Remove this parameter from the URL (after recording above) to make it
|
||||
// cleaner for bookmarking and switch-to-tab and so that bookmarked values
|
||||
// don't skew telemetry.
|
||||
searchParams.delete("entrypoint");
|
||||
searchParamsChanged = true;
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", e => {
|
||||
if (searchParamsChanged) {
|
||||
let newURL = protocol + pathname;
|
||||
let params = searchParams.toString();
|
||||
if (params) {
|
||||
newURL += "?" + params;
|
||||
}
|
||||
window.location.replace(newURL);
|
||||
return;
|
||||
}
|
||||
|
||||
RPMSendQuery("FetchEntryPoint", {}).then(entrypoint => {
|
||||
// Send telemetry on arriving on this page
|
||||
document.sendTelemetryEvent("show", "protection_report", entrypoint);
|
||||
});
|
||||
|
||||
// We need to send the close telemetry before unload while we still have a connection to RPM.
|
||||
window.addEventListener("beforeunload", () => {
|
||||
document.sendTelemetryEvent("close", "protection_report");
|
||||
});
|
||||
|
||||
let todayInMs = Date.now();
|
||||
let weekAgoInMs = todayInMs - 6 * 24 * 60 * 60 * 1000;
|
||||
|
||||
|
@ -53,22 +90,10 @@ document.addEventListener("DOMContentLoaded", e => {
|
|||
manageProtections.addEventListener("click", protectionSettingsEvtHandler);
|
||||
manageProtections.addEventListener("keypress", protectionSettingsEvtHandler);
|
||||
|
||||
let cbCategory = RPMGetStringPref("browser.contentblocking.category");
|
||||
|
||||
let legend = document.getElementById("legend");
|
||||
legend.style.gridTemplateAreas =
|
||||
"'social cookie tracker fingerprinter cryptominer'";
|
||||
|
||||
document.sendTelemetryEvent = (action, object, value = "") => {
|
||||
// eslint-disable-next-line no-undef
|
||||
RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
|
||||
category: cbCategory,
|
||||
});
|
||||
};
|
||||
|
||||
// Send telemetry on arriving and closing this page
|
||||
document.sendTelemetryEvent("show", "protection_report");
|
||||
|
||||
let createGraph = data => {
|
||||
let graph = document.getElementById("graph");
|
||||
let summary = document.getElementById("graph-total-summary");
|
||||
|
|
|
@ -820,3 +820,90 @@ add_task(async function test_save_telemetry() {
|
|||
// Use the TrackingDBService API to delete the data.
|
||||
await TrackingDBService.clearAll();
|
||||
});
|
||||
|
||||
// Test that telemetry is sent if entrypoint param is included,
|
||||
// and test that it is recorded as default if entrypoint param is not properly included
|
||||
add_task(async function checkTelemetryLoadEventForEntrypoint() {
|
||||
// There's an arbitrary interval of 2 seconds in which the content
|
||||
// processes sync their event data with the parent process, we wait
|
||||
// this out to ensure that we clear everything that is left over from
|
||||
// previous tests and don't receive random events in the middle of our tests.
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(c => setTimeout(c, 2000));
|
||||
|
||||
// Clear everything.
|
||||
Services.telemetry.clearEvents();
|
||||
await TestUtils.waitForCondition(() => {
|
||||
let events = Services.telemetry.snapshotEvents(
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
|
||||
true
|
||||
).content;
|
||||
return !events || !events.length;
|
||||
});
|
||||
|
||||
Services.telemetry.setEventRecordingEnabled("security.ui.protections", true);
|
||||
|
||||
info("Typo in 'entrypoint' should not be recorded");
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
url: "about:protections?entryPoint=newPage",
|
||||
gBrowser,
|
||||
});
|
||||
|
||||
let loadEvents = await TestUtils.waitForCondition(() => {
|
||||
let events = Services.telemetry.snapshotEvents(
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
|
||||
true
|
||||
).content;
|
||||
if (events && events.length) {
|
||||
events = events.filter(
|
||||
e =>
|
||||
e[1] == "security.ui.protections" &&
|
||||
e[2] == "show" &&
|
||||
e[4] == "direct"
|
||||
);
|
||||
if (events.length == 1) {
|
||||
return events;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, "recorded telemetry for showing the report contains default 'direct' entrypoint");
|
||||
|
||||
is(
|
||||
loadEvents.length,
|
||||
1,
|
||||
`recorded telemetry for showing the report contains default 'direct' entrypoint`
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
|
||||
tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
url: "about:protections?entrypoint=page",
|
||||
gBrowser,
|
||||
});
|
||||
|
||||
loadEvents = await TestUtils.waitForCondition(() => {
|
||||
let events = Services.telemetry.snapshotEvents(
|
||||
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
|
||||
true
|
||||
).content;
|
||||
if (events && events.length) {
|
||||
events = events.filter(
|
||||
e =>
|
||||
e[1] == "security.ui.protections" && e[2] == "show" && e[4] == "page"
|
||||
);
|
||||
if (events.length == 1) {
|
||||
return events;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, "recorded telemetry for showing the report contains correct entrypoint");
|
||||
|
||||
is(
|
||||
loadEvents.length,
|
||||
1,
|
||||
"recorded telemetry for showing the report contains correct entrypoint"
|
||||
);
|
||||
|
||||
// Clean up.
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -323,11 +323,26 @@ async function openPopupAndGetEngineButton(
|
|||
);
|
||||
} else {
|
||||
let aliases = UrlbarSearchUtils.aliasesForEngine(oneOffButton.engine);
|
||||
Assert.equal(
|
||||
oneOffButton.getAttribute("tooltiptext"),
|
||||
engineName + (aliases.length ? ` (${aliases[0]})` : ""),
|
||||
"One-off should have the tooltip set to the engine name"
|
||||
);
|
||||
if (!aliases.length) {
|
||||
Assert.equal(
|
||||
oneOffButton.getAttribute("tooltiptext"),
|
||||
engineName,
|
||||
"One-off without alias should have the tooltip set to the engine name"
|
||||
);
|
||||
} else {
|
||||
let l10n = {
|
||||
id: "search-one-offs-engine-with-alias",
|
||||
args: {
|
||||
engineName,
|
||||
alias: aliases[0],
|
||||
},
|
||||
};
|
||||
Assert.deepEqual(
|
||||
win.document.l10n.getAttributes(oneOffButton),
|
||||
l10n,
|
||||
"One-off with alias has expected tooltip l10n values"
|
||||
);
|
||||
}
|
||||
}
|
||||
Assert.equal(
|
||||
oneOffButton.id,
|
||||
|
|
|
@ -1206,6 +1206,11 @@ class UrlbarInput {
|
|||
|
||||
if (this.searchMode) {
|
||||
this.toggleAttribute("searchmode", true);
|
||||
// Search mode should only be active when pageproxystate is invalid.
|
||||
if (this.getAttribute("pageproxystate") == "valid") {
|
||||
this.value = "";
|
||||
this.setPageProxyState("invalid", true);
|
||||
}
|
||||
} else {
|
||||
this.removeAttribute("searchmode");
|
||||
}
|
||||
|
|
|
@ -233,7 +233,16 @@ class Preferences {
|
|||
*/
|
||||
constructor() {
|
||||
this._map = new Map();
|
||||
this._observer = new UrlbarPrefsObserver(pref => this._onPrefChanged(pref));
|
||||
this.QueryInterface = ChromeUtils.generateQI([
|
||||
"nsIObserver",
|
||||
"nsISupportsWeakReference",
|
||||
]);
|
||||
Services.prefs.addObserver(PREF_URLBAR_BRANCH, this, true);
|
||||
for (let pref of PREF_OTHER_DEFAULTS.keys()) {
|
||||
Services.prefs.addObserver(pref, this, true);
|
||||
}
|
||||
this._observerWeakRefs = [];
|
||||
this.addObserver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,6 +280,44 @@ class Preferences {
|
|||
setter(pref, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a preference observer. Observers are held weakly.
|
||||
*
|
||||
* @param {object} observer
|
||||
* An object that must have a method named `onPrefChanged`, which will
|
||||
* be called when a urlbar preference changes. It will be passed the
|
||||
* pref name. For prefs in the `browser.urlbar.` branch, the name will
|
||||
* be relative to the branch. For other prefs, the name will be the
|
||||
* full name.
|
||||
*/
|
||||
addObserver(observer) {
|
||||
this._observerWeakRefs.push(Cu.getWeakReference(observer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes preference changes.
|
||||
*
|
||||
* @param {nsISupports} subject
|
||||
* @param {string} topic
|
||||
* @param {string} data
|
||||
*/
|
||||
observe(subject, topic, data) {
|
||||
let pref = data.replace(PREF_URLBAR_BRANCH, "");
|
||||
if (!PREF_URLBAR_DEFAULTS.has(pref) && !PREF_OTHER_DEFAULTS.has(pref)) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < this._observerWeakRefs.length; ) {
|
||||
let observer = this._observerWeakRefs[i].get();
|
||||
if (!observer) {
|
||||
// The observer has been GC'ed, so remove it from our list.
|
||||
this._observerWeakRefs.splice(i, 1);
|
||||
} else {
|
||||
observer.onPrefChanged(pref);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a pref tracked by UrlbarPrefs changes.
|
||||
*
|
||||
|
@ -278,7 +325,7 @@ class Preferences {
|
|||
* The name of the pref, relative to `browser.urlbar.` if the pref is
|
||||
* in that branch.
|
||||
*/
|
||||
_onPrefChanged(pref) {
|
||||
onPrefChanged(pref) {
|
||||
this._map.delete(pref);
|
||||
// Some prefs may influence others.
|
||||
if (pref == "matchBuckets") {
|
||||
|
@ -403,45 +450,4 @@ class Preferences {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A weak preferences observer. You must hold on to instances of this class
|
||||
* because otherwise they will be garbage collected.
|
||||
*/
|
||||
class UrlbarPrefsObserver {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param {function} callback
|
||||
* Called when a urlbar preference changes. It will be passed the pref
|
||||
* name. For prefs in the `browser.urlbar.` branch, the name will be
|
||||
* relative to the branch. For other prefs, the name will be the full name.
|
||||
*/
|
||||
constructor(callback) {
|
||||
this._callback = callback;
|
||||
this.QueryInterface = ChromeUtils.generateQI([
|
||||
"nsIObserver",
|
||||
"nsISupportsWeakReference",
|
||||
]);
|
||||
Services.prefs.addObserver(PREF_URLBAR_BRANCH, this, true);
|
||||
for (let pref of PREF_OTHER_DEFAULTS.keys()) {
|
||||
Services.prefs.addObserver(pref, this, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes preference changes.
|
||||
*
|
||||
* @param {nsISupports} subject
|
||||
* @param {string} topic
|
||||
* @param {string} data
|
||||
*/
|
||||
observe(subject, topic, data) {
|
||||
let pref = data.replace(PREF_URLBAR_BRANCH, "");
|
||||
if (!PREF_URLBAR_DEFAULTS.has(pref) && !PREF_OTHER_DEFAULTS.has(pref)) {
|
||||
return;
|
||||
}
|
||||
this._callback(pref);
|
||||
}
|
||||
}
|
||||
|
||||
var UrlbarPrefs = new Preferences();
|
||||
|
|
|
@ -12,7 +12,6 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
SearchOneOffs: "resource:///modules/SearchOneOffs.jsm",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
||||
UrlbarPrefsObserver: "resource:///modules/UrlbarPrefs.jsm",
|
||||
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm",
|
||||
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
|
||||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
|
@ -57,9 +56,7 @@ class UrlbarSearchOneOffs extends SearchOneOffs {
|
|||
super(view.panel.querySelector(".search-one-offs"));
|
||||
this.view = view;
|
||||
this.input = view.input;
|
||||
this._prefObserver = new UrlbarPrefsObserver(pref =>
|
||||
this._onPrefChanged(pref)
|
||||
);
|
||||
UrlbarPrefs.addObserver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,6 +191,23 @@ class UrlbarSearchOneOffs extends SearchOneOffs {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a pref tracked by UrlbarPrefs changes.
|
||||
*
|
||||
* @param {string} changedPref
|
||||
* The name of the pref, relative to `browser.urlbar.` if the pref is in
|
||||
* that branch.
|
||||
*/
|
||||
onPrefChanged(changedPref) {
|
||||
// Null out this._engines when the local-one-offs-related prefs change so
|
||||
// that they rebuild themselves the next time the view opens.
|
||||
let prefs = [...LOCAL_MODES.values()].map(({ pref }) => pref);
|
||||
prefs.push("update2", "update2.localOneOffs", "update2.oneOffsRefresh");
|
||||
if (prefs.includes(changedPref)) {
|
||||
this._engines = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides _rebuildEngineList to add the local one-offs.
|
||||
*
|
||||
|
@ -251,21 +265,4 @@ class UrlbarSearchOneOffs extends SearchOneOffs {
|
|||
|
||||
this.handleSearchCommand(event, engineOrSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a pref tracked by UrlbarPrefs changes.
|
||||
*
|
||||
* @param {string} changedPref
|
||||
* The name of the pref, relative to `browser.urlbar.` if the pref is in
|
||||
* that branch.
|
||||
*/
|
||||
_onPrefChanged(changedPref) {
|
||||
// Null out this._engines when the local-one-offs-related prefs change so
|
||||
// that they rebuild themselves the next time the view opens.
|
||||
let prefs = [...LOCAL_MODES.values()].map(({ pref }) => pref);
|
||||
prefs.push("update2", "update2.localOneOffs", "update2.oneOffsRefresh");
|
||||
if (prefs.includes(changedPref)) {
|
||||
this._engines = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,3 +261,27 @@ add_task(async function click_close() {
|
|||
gURLBar.setSearchMode(null);
|
||||
}
|
||||
});
|
||||
|
||||
// Tests that entering search mode invalidates pageproxystate and exits search
|
||||
// mode.
|
||||
add_task(async function invalidate_pageproxystate() {
|
||||
await BrowserTestUtils.withNewTab("about:robots", async function(browser) {
|
||||
await UrlbarTestUtils.promisePopupOpen(window, () => {
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
|
||||
});
|
||||
Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid");
|
||||
await enterSearchMode(window);
|
||||
Assert.equal(
|
||||
gURLBar.getAttribute("pageproxystate"),
|
||||
"invalid",
|
||||
"Entering search mode should clear pageproxystate."
|
||||
);
|
||||
Assert.equal(gURLBar.value, "", "Urlbar value should be cleared.");
|
||||
await exitSearchMode(window, { clickClose: true });
|
||||
Assert.equal(
|
||||
gURLBar.getAttribute("pageproxystate"),
|
||||
"invalid",
|
||||
"Pageproxystate should still be invalid after exiting search mode."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ support-files =
|
|||
!/browser/components/search/test/browser/testEngine.xml
|
||||
!/browser/components/search/test/browser/testEngine_diacritics.xml
|
||||
testEngine_chromeicon.xml
|
||||
skip-if = (debug && os == "linux" && bits == 64 && os_version == "18.04") # Bug 1649755
|
||||
[browser_EveryWindow.js]
|
||||
[browser_LiveBookmarkMigrator.js]
|
||||
[browser_PageActions.js]
|
||||
|
|
|
@ -217,14 +217,11 @@ def old_configure_options(*options):
|
|||
'--enable-extensions',
|
||||
'--enable-libproxy',
|
||||
'--enable-logrefcnt',
|
||||
'--enable-mobile-optimize',
|
||||
'--enable-necko-wifi',
|
||||
'--enable-negotiateauth',
|
||||
'--enable-official-branding',
|
||||
'--enable-parental-controls',
|
||||
'--enable-pref-extensions',
|
||||
'--enable-sandbox',
|
||||
'--enable-startupcache',
|
||||
'--enable-system-cairo',
|
||||
'--enable-system-extension-dirs',
|
||||
'--enable-system-pixman',
|
||||
|
|
|
@ -9,13 +9,15 @@ import { setupEvents, clientEvents } from "./firefox/events";
|
|||
import { features, prefs } from "../utils/prefs";
|
||||
|
||||
let actions;
|
||||
let targetList;
|
||||
|
||||
export async function onConnect(
|
||||
connection: any,
|
||||
_actions: Object
|
||||
): Promise<void> {
|
||||
const { devToolsClient, targetList } = connection;
|
||||
const { devToolsClient, targetList: _targetList } = connection;
|
||||
actions = _actions;
|
||||
targetList = _targetList;
|
||||
|
||||
setupCommands({ devToolsClient, targetList });
|
||||
setupEvents({ actions, devToolsClient });
|
||||
|
@ -40,6 +42,19 @@ async function onTargetAvailable({
|
|||
targetFront,
|
||||
isTargetSwitching,
|
||||
}): Promise<void> {
|
||||
const isBrowserToolbox = targetList.targetFront.isParentProcess;
|
||||
const isNonTopLevelFrameTarget =
|
||||
!targetFront.isTopLevel &&
|
||||
targetFront.targetType === targetList.TYPES.FRAME;
|
||||
|
||||
if (isBrowserToolbox && isNonTopLevelFrameTarget) {
|
||||
// In the BrowserToolbox, non-top-level frame targets are already
|
||||
// debugged via content-process targets.
|
||||
// Do not attach the thread here, as it was already done by the
|
||||
// corresponding content-process target.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetFront.isTopLevel) {
|
||||
await actions.addTarget(targetFront);
|
||||
return;
|
||||
|
|
|
@ -738,7 +738,8 @@ Toolbox.prototype = {
|
|||
|
||||
const isBrowserToolbox = this.targetList.targetFront.isParentProcess;
|
||||
const isNonTopLevelFrameTarget =
|
||||
!targetFront.isTopLevel && targetFront.type === TargetList.TYPES.FRAME;
|
||||
!targetFront.isTopLevel &&
|
||||
targetFront.targetType === TargetList.TYPES.FRAME;
|
||||
|
||||
if (isBrowserToolbox && isNonTopLevelFrameTarget) {
|
||||
// In the BrowserToolbox, non-top-level frame targets are already
|
||||
|
@ -766,7 +767,7 @@ Toolbox.prototype = {
|
|||
_attachAndResumeThread: async function(target) {
|
||||
if (target.threadFront) {
|
||||
// if threadFront already exists, the thread is already attached.
|
||||
if (target.type !== TargetList.TYPES.SERVICE_WORKER) {
|
||||
if (target.targetType === TargetList.TYPES.SERVICE_WORKER) {
|
||||
// This can legitimately happen for service workers. See Bug 1655439.
|
||||
console.warn(
|
||||
"Attaching to an already attached thread for a service worker target"
|
||||
|
@ -778,7 +779,7 @@ Toolbox.prototype = {
|
|||
|
||||
// This should not happen for non-server-worker targets, throw otherwise.
|
||||
throw new Error(
|
||||
`Attaching to an already attached thread for a target of type "${target.type}"`
|
||||
`Attaching to an already attached thread for a target of type "${target.targetType}"`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -476,9 +476,9 @@ NetworkObserver.prototype = {
|
|||
const fromServiceWorker = this.interceptedChannels.has(channel);
|
||||
this.interceptedChannels.delete(channel);
|
||||
|
||||
// If this is a cached response, there never was a request event
|
||||
// so we need to construct one here so the frontend gets all the
|
||||
// expected events.
|
||||
// If this is a cached response (which are also emitted by service worker requests),
|
||||
// there never was a request event so we need to construct one here
|
||||
// so the frontend gets all the expected events.
|
||||
let httpActivity = this.createOrGetActivityObject(channel);
|
||||
if (!httpActivity.owner) {
|
||||
httpActivity = this._createNetworkEvent(channel, {
|
||||
|
@ -486,6 +486,12 @@ NetworkObserver.prototype = {
|
|||
fromServiceWorker: fromServiceWorker,
|
||||
});
|
||||
}
|
||||
|
||||
// We need to send the request body to the frontend for
|
||||
// the faked (cached/service worker request) event.
|
||||
this._onRequestBodySent(httpActivity);
|
||||
this._sendRequestBody(httpActivity);
|
||||
|
||||
httpActivity.owner.addResponseStart(
|
||||
{
|
||||
httpVersion: response.httpVersion,
|
||||
|
@ -569,20 +575,7 @@ NetworkObserver.prototype = {
|
|||
switch (activitySubtype) {
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT:
|
||||
this._onRequestBodySent(httpActivity);
|
||||
if (httpActivity.sentBody !== null) {
|
||||
const limit = Services.prefs.getIntPref(
|
||||
"devtools.netmonitor.requestBodyLimit"
|
||||
);
|
||||
const size = httpActivity.sentBody.length;
|
||||
if (size > limit && limit > 0) {
|
||||
httpActivity.sentBody = httpActivity.sentBody.substr(0, limit);
|
||||
}
|
||||
httpActivity.owner.addRequestPostData({
|
||||
text: httpActivity.sentBody,
|
||||
size: size,
|
||||
});
|
||||
httpActivity.sentBody = null;
|
||||
}
|
||||
this._sendRequestBody(httpActivity);
|
||||
break;
|
||||
case gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER:
|
||||
this._onResponseHeader(httpActivity, extraStringData);
|
||||
|
@ -1517,6 +1510,23 @@ NetworkObserver.prototype = {
|
|||
};
|
||||
},
|
||||
|
||||
_sendRequestBody: function(httpActivity) {
|
||||
if (httpActivity.sentBody !== null) {
|
||||
const limit = Services.prefs.getIntPref(
|
||||
"devtools.netmonitor.requestBodyLimit"
|
||||
);
|
||||
const size = httpActivity.sentBody.length;
|
||||
if (size > limit && limit > 0) {
|
||||
httpActivity.sentBody = httpActivity.sentBody.substr(0, limit);
|
||||
}
|
||||
httpActivity.owner.addRequestPostData({
|
||||
text: httpActivity.sentBody,
|
||||
size: size,
|
||||
});
|
||||
httpActivity.sentBody = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Suspend observer activity. This is called when the Network monitor actor stops
|
||||
* listening.
|
||||
|
|
|
@ -3581,14 +3581,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
|
||||
// If the HTTPS-Only Mode upgraded this request and the upgrade might have
|
||||
// caused this error, we replace the error-page with about:httpsonlyerror
|
||||
if (aFailedChannel && nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aError)) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aFailedChannel->LoadInfo();
|
||||
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
|
||||
if ((httpsOnlyStatus &
|
||||
nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED) &&
|
||||
!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT)) {
|
||||
errorPage.AssignLiteral("httpsonlyerror");
|
||||
}
|
||||
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aFailedChannel, aError)) {
|
||||
errorPage.AssignLiteral("httpsonlyerror");
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsILoadURIDelegate> loadURIDelegate = GetLoadURIDelegate()) {
|
||||
|
|
|
@ -10246,6 +10246,37 @@ void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) {
|
|||
}
|
||||
}
|
||||
|
||||
void Document::ProcessMETATag(HTMLMetaElement* aMetaElement) {
|
||||
// set any HTTP-EQUIV data into document's header data as well as url
|
||||
nsAutoString header;
|
||||
aMetaElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
|
||||
if (!header.IsEmpty()) {
|
||||
// Ignore META REFRESH when document is sandboxed from automatic features.
|
||||
nsContentUtils::ASCIIToLower(header);
|
||||
if (nsGkAtoms::refresh->Equals(header) &&
|
||||
(GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString result;
|
||||
aMetaElement->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
|
||||
if (!result.IsEmpty()) {
|
||||
RefPtr<nsAtom> fieldAtom(NS_Atomize(header));
|
||||
SetHeaderData(fieldAtom, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (aMetaElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||
nsGkAtoms::handheldFriendly, eIgnoreCase)) {
|
||||
nsAutoString result;
|
||||
aMetaElement->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
|
||||
if (!result.IsEmpty()) {
|
||||
nsContentUtils::ASCIIToLower(result);
|
||||
SetHeaderData(nsGkAtoms::handheldFriendly, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Element> Document::CreateElem(const nsAString& aName,
|
||||
nsAtom* aPrefix,
|
||||
int32_t aNamespaceID,
|
||||
|
|
|
@ -2161,6 +2161,7 @@ class Document : public nsINode,
|
|||
mIsContentDocument = aIsContentDocument;
|
||||
}
|
||||
|
||||
void ProcessMETATag(HTMLMetaElement* aMetaElement);
|
||||
/**
|
||||
* Create an element with the specified name, prefix and namespace ID.
|
||||
* Returns null if element name parsing failed.
|
||||
|
|
|
@ -249,17 +249,6 @@ nsresult nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsContentSink::ProcessHeaderData(nsAtom* aHeader,
|
||||
const nsAString& aValue,
|
||||
nsIContent* aContent) {
|
||||
nsresult rv = NS_OK;
|
||||
// necko doesn't process headers coming in from the parser
|
||||
|
||||
mDocument->SetHeaderData(aHeader, aValue);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsContentSink::DoProcessLinkHeader() {
|
||||
nsAutoString value;
|
||||
mDocument->GetHeaderData(nsGkAtoms::link, value);
|
||||
|
@ -733,47 +722,6 @@ nsresult nsContentSink::ProcessStyleLinkFromHeader(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsContentSink::ProcessMETATag(nsIContent* aContent) {
|
||||
NS_ASSERTION(aContent, "missing meta-element");
|
||||
MOZ_ASSERT(aContent->IsElement());
|
||||
|
||||
Element* element = aContent->AsElement();
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// set any HTTP-EQUIV data into document's header data as well as url
|
||||
nsAutoString header;
|
||||
element->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
|
||||
if (!header.IsEmpty()) {
|
||||
// Ignore META REFRESH when document is sandboxed from automatic features.
|
||||
nsContentUtils::ASCIIToLower(header);
|
||||
if (nsGkAtoms::refresh->Equals(header) &&
|
||||
(mDocument->GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString result;
|
||||
element->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
|
||||
if (!result.IsEmpty()) {
|
||||
RefPtr<nsAtom> fieldAtom(NS_Atomize(header));
|
||||
rv = ProcessHeaderData(fieldAtom, result, element);
|
||||
}
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||
nsGkAtoms::handheldFriendly, eIgnoreCase)) {
|
||||
nsAutoString result;
|
||||
element->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
|
||||
if (!result.IsEmpty()) {
|
||||
nsContentUtils::ASCIIToLower(result);
|
||||
mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsContentSink::PrefetchHref(const nsAString& aHref, const nsAString& aAs,
|
||||
const nsAString& aType,
|
||||
const nsAString& aMedia) {
|
||||
|
|
|
@ -93,8 +93,6 @@ class nsContentSink : public nsICSSLoaderObserver,
|
|||
NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasDeferred,
|
||||
nsresult aStatus) override;
|
||||
|
||||
virtual nsresult ProcessMETATag(nsIContent* aContent);
|
||||
|
||||
// nsIContentSink implementation helpers
|
||||
nsresult WillParseImpl(void);
|
||||
nsresult WillInterruptImpl(void);
|
||||
|
@ -147,8 +145,6 @@ class nsContentSink : public nsICSSLoaderObserver,
|
|||
nsIChannel* aChannel);
|
||||
|
||||
nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
|
||||
nsresult ProcessHeaderData(nsAtom* aHeader, const nsAString& aValue,
|
||||
nsIContent* aContent = nullptr);
|
||||
nsresult ProcessLinkHeader(const nsAString& aLinkData);
|
||||
nsresult ProcessLinkFromHeader(
|
||||
const nsAString& aAnchor, const nsAString& aHref, const nsAString& aRel,
|
||||
|
|
|
@ -760,7 +760,7 @@ ClientWebGLContext::SetContextOptions(JSContext* cx,
|
|||
newOpts.xrCompatible = attributes.mXrCompatible;
|
||||
newOpts.powerPreference = attributes.mPowerPreference;
|
||||
newOpts.enableDebugRendererInfo =
|
||||
Preferences::GetBool("webgl.enable-debug-renderer-info", false);
|
||||
StaticPrefs::webgl_enable_debug_renderer_info();
|
||||
MOZ_ASSERT(mCanvasElement || mOffscreenCanvas);
|
||||
newOpts.shouldResistFingerprinting =
|
||||
mCanvasElement ?
|
||||
|
@ -5099,7 +5099,7 @@ static bool IsExtensionForbiddenForCaller(const WebGLExtensionID ext,
|
|||
|
||||
case WebGLExtensionID::WEBGL_debug_renderer_info:
|
||||
return resistFingerprinting ||
|
||||
!Preferences::GetBool("webgl.enable-debug-renderer-info", false);
|
||||
!StaticPrefs::webgl_enable_debug_renderer_info();
|
||||
|
||||
case WebGLExtensionID::WEBGL_debug_shaders:
|
||||
return resistFingerprinting;
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
|
||||
#include "BlobURLChannel.h"
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
#include "mozilla/dom/BlobURL.h"
|
||||
#include "mozilla/dom/BlobURLInputStream.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
BlobURLChannel::BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
: mInitialized(false) {
|
||||
: mContentStreamOpened(false) {
|
||||
SetURI(aURI);
|
||||
SetOriginalURI(aURI);
|
||||
SetLoadInfo(aLoadInfo);
|
||||
|
@ -24,59 +27,49 @@ BlobURLChannel::BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
|||
|
||||
BlobURLChannel::~BlobURLChannel() = default;
|
||||
|
||||
void BlobURLChannel::InitFailed() {
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
MOZ_ASSERT(!mInputStream);
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
void BlobURLChannel::Initialize(BlobImpl* aBlobImpl) {
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
|
||||
nsAutoString contentType;
|
||||
aBlobImpl->GetType(contentType);
|
||||
SetContentType(NS_ConvertUTF16toUTF8(contentType));
|
||||
|
||||
if (aBlobImpl->IsFile()) {
|
||||
nsString filename;
|
||||
aBlobImpl->GetName(filename);
|
||||
SetContentDispositionFilename(filename);
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
uint64_t size = aBlobImpl->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
InitFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
SetContentLength(size);
|
||||
|
||||
aBlobImpl->CreateInputStream(getter_AddRefs(mInputStream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
InitFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mInputStream);
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
nsresult BlobURLChannel::OpenContentStream(bool aAsync,
|
||||
nsIInputStream** aResult,
|
||||
nsIChannel** aChannel) {
|
||||
MOZ_ASSERT(mInitialized);
|
||||
if (mContentStreamOpened) {
|
||||
return NS_ERROR_ALREADY_OPENED;
|
||||
}
|
||||
|
||||
if (!mInputStream) {
|
||||
mContentStreamOpened = true;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
|
||||
|
||||
RefPtr<BlobURL> blobURL;
|
||||
rv = uri->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(blobURL));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!blobURL)) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
if (blobURL->Revoked()) {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
// if the channel was not triggered by the system principal,
|
||||
// then we return here because the URL had been revoked
|
||||
if (loadInfo && !loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
#else
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream =
|
||||
BlobURLInputStream::Create(this, blobURL);
|
||||
if (NS_WARN_IF(!inputStream)) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
EnableSynthesizedProgressEvents(true);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = mInputStream;
|
||||
stream.forget(aResult);
|
||||
inputStream.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void BlobURLChannel::OnChannelDone() { mInputStream = nullptr; }
|
||||
}
|
|
@ -22,28 +22,13 @@ class BlobURLChannel final : public nsBaseChannel {
|
|||
public:
|
||||
BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo);
|
||||
|
||||
// This method is called when there is not a valid BlobImpl for this channel.
|
||||
// This method will make ::OpenContentStream to return NS_ERROR_MALFORMED_URI.
|
||||
void InitFailed();
|
||||
|
||||
// There is a valid BlobImpl for the channel. The blob's inputStream will be
|
||||
// used when ::OpenContentStream is called.
|
||||
void Initialize(BlobImpl* aBlobImpl);
|
||||
|
||||
private:
|
||||
~BlobURLChannel();
|
||||
|
||||
nsresult OpenContentStream(bool aAsync, nsIInputStream** aResult,
|
||||
nsIChannel** aChannel) override;
|
||||
|
||||
void OnChannelDone() override;
|
||||
|
||||
// If Initialize() is called, this will contain the blob's inputStream.
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
|
||||
// This boolean is used to check that InitFailed() or Initialize() are called
|
||||
// just once.
|
||||
bool mInitialized;
|
||||
bool mContentStreamOpened;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -0,0 +1,573 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BlobURLInputStream.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ADDREF(BlobURLInputStream);
|
||||
NS_IMPL_RELEASE(BlobURLInputStream);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(BlobURLInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStreamLength)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStreamLength)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAsyncInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
/* static */
|
||||
already_AddRefed<nsIInputStream> BlobURLInputStream::Create(
|
||||
BlobURLChannel* const aChannel, BlobURL* const aBlobURL) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_WARN_IF(!aChannel) || NS_WARN_IF(!aBlobURL)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
|
||||
nsresult rv = aBlobURL->GetSpec(spec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MakeAndAddRef<BlobURLInputStream>(aChannel, spec);
|
||||
}
|
||||
|
||||
// from nsIInputStream interface
|
||||
NS_IMETHODIMP BlobURLInputStream::Close() {
|
||||
return CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BlobURLInputStream::Available(uint64_t* aLength) {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
|
||||
if (mState == State::ERROR) {
|
||||
MOZ_ASSERT(NS_FAILED(mError));
|
||||
return mError;
|
||||
}
|
||||
|
||||
if (mState == State::CLOSED) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
if (mState == State::READY) {
|
||||
MOZ_ASSERT(mAsyncInputStream);
|
||||
return mAsyncInputStream->Available(aLength);
|
||||
}
|
||||
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BlobURLInputStream::Read(char* aBuffer, uint32_t aCount,
|
||||
uint32_t* aReadCount) {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
if (mState == State::ERROR) {
|
||||
MOZ_ASSERT(NS_FAILED(mError));
|
||||
return mError;
|
||||
}
|
||||
|
||||
// Read() should not return NS_BASE_STREAM_CLOSED if stream is closed.
|
||||
// A read count of 0 should indicate closed or consumed stream.
|
||||
// See:
|
||||
// https://searchfox.org/mozilla-central/rev/559b25eb41c1cbffcb90a34e008b8288312fcd25/xpcom/io/nsIInputStream.idl#104
|
||||
if (mState == State::CLOSED) {
|
||||
*aReadCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mState == State::READY) {
|
||||
MOZ_ASSERT(mAsyncInputStream);
|
||||
nsresult rv = mAsyncInputStream->Read(aBuffer, aCount, aReadCount);
|
||||
if (NS_SUCCEEDED(rv) && aReadCount && !*aReadCount) {
|
||||
mState = State::CLOSED;
|
||||
ReleaseUnderlyingStream(lock);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BlobURLInputStream::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void* aClosure, uint32_t aCount,
|
||||
uint32_t* aResult) {
|
||||
// This means the caller will have to wrap the stream in an
|
||||
// nsBufferedInputStream in order to use ReadSegments
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BlobURLInputStream::IsNonBlocking(bool* aNonBlocking) {
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// from nsIAsyncInputStream interface
|
||||
NS_IMETHODIMP BlobURLInputStream::CloseWithStatus(nsresult aStatus) {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
if (mState == State::READY) {
|
||||
MOZ_ASSERT(mAsyncInputStream);
|
||||
mAsyncInputStream->CloseWithStatus(aStatus);
|
||||
}
|
||||
|
||||
mState = State::CLOSED;
|
||||
ReleaseUnderlyingStream(lock);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP BlobURLInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
uint32_t aFlags,
|
||||
uint32_t aRequestedCount,
|
||||
nsIEventTarget* aEventTarget) {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
|
||||
if (mState == State::ERROR) {
|
||||
MOZ_ASSERT(NS_FAILED(mError));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Pre-empting a valid callback with another is not allowed.
|
||||
if (NS_WARN_IF(mAsyncWaitCallback && aCallback)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mAsyncWaitTarget = aEventTarget;
|
||||
mAsyncWaitRequestedCount = aRequestedCount;
|
||||
mAsyncWaitFlags = aFlags;
|
||||
mAsyncWaitCallback = aCallback;
|
||||
|
||||
if (mState == State::INITIAL) {
|
||||
mState = State::WAITING;
|
||||
// RetrieveBlobData will execute NotifyWWaitTarget() when retrieve succeeds
|
||||
// or fails
|
||||
if (NS_IsMainThread()) {
|
||||
RetrieveBlobData(lock);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(
|
||||
"BlobURLInputStream::CallRetrieveBlobData", this,
|
||||
&BlobURLInputStream::CallRetrieveBlobData);
|
||||
NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mState == State::WAITING) {
|
||||
// RetrieveBlobData is already in progress and will execute
|
||||
// NotifyWaitTargets when retrieve succeeds or fails
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mState == State::READY) {
|
||||
// Ask the blob's input stream if reading is possible or not
|
||||
return mAsyncInputStream->AsyncWait(
|
||||
mAsyncWaitCallback ? this : nullptr, mAsyncWaitFlags,
|
||||
mAsyncWaitRequestedCount, mAsyncWaitTarget);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == State::CLOSED);
|
||||
NotifyWaitTargets(lock);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// from nsIInputStreamLength interface
|
||||
NS_IMETHODIMP BlobURLInputStream::Length(int64_t* aLength) {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
|
||||
if (mState == State::CLOSED) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
if (mState == State::ERROR) {
|
||||
MOZ_ASSERT(NS_FAILED(mError));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mState == State::READY) {
|
||||
*aLength = mBlobSize;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
// from nsIAsyncInputStreamLength interface
|
||||
NS_IMETHODIMP BlobURLInputStream::AsyncLengthWait(
|
||||
nsIInputStreamLengthCallback* aCallback, nsIEventTarget* aEventTarget) {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
|
||||
if (mState == State::ERROR) {
|
||||
MOZ_ASSERT(NS_FAILED(mError));
|
||||
return mError;
|
||||
}
|
||||
|
||||
// Pre-empting a valid callback with another is not allowed.
|
||||
if (mAsyncLengthWaitCallback && aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mAsyncLengthWaitTarget = aEventTarget;
|
||||
mAsyncLengthWaitCallback = aCallback;
|
||||
|
||||
if (mState == State::INITIAL) {
|
||||
mState = State::WAITING;
|
||||
// RetrieveBlobData will execute NotifyWWaitTarget() when retrieve succeeds
|
||||
// or fails
|
||||
if (NS_IsMainThread()) {
|
||||
RetrieveBlobData(lock);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(
|
||||
"BlobURLInputStream::CallRetrieveBlobData", this,
|
||||
&BlobURLInputStream::CallRetrieveBlobData);
|
||||
NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mState == State::WAITING) {
|
||||
// RetrieveBlobData is already in progress and will execute
|
||||
// NotifyWaitTargets when retrieve succeeds or fails
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Since here the state must be READY (in which case the size of the blob is
|
||||
// already known) or CLOSED, callback can be called immediately
|
||||
NotifyWaitTargets(lock);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// from nsIInputStreamCallback interface
|
||||
NS_IMETHODIMP BlobURLInputStream::OnInputStreamReady(
|
||||
nsIAsyncInputStream* aStream) {
|
||||
nsCOMPtr<nsIInputStreamCallback> callback;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
MOZ_ASSERT_IF(mAsyncInputStream, aStream == mAsyncInputStream);
|
||||
|
||||
// aborted in the meantime
|
||||
if (!mAsyncWaitCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mAsyncWaitCallback.swap(callback);
|
||||
mAsyncWaitTarget = nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(callback);
|
||||
return callback->OnInputStreamReady(this);
|
||||
}
|
||||
|
||||
// from nsIInputStreamLengthCallback interface
|
||||
NS_IMETHODIMP BlobURLInputStream::OnInputStreamLengthReady(
|
||||
nsIAsyncInputStreamLength* aStream, int64_t aLength) {
|
||||
nsCOMPtr<nsIInputStreamLengthCallback> callback;
|
||||
{
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
|
||||
// aborted in the meantime
|
||||
if (!mAsyncLengthWaitCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mAsyncLengthWaitCallback.swap(callback);
|
||||
mAsyncLengthWaitCallback = nullptr;
|
||||
}
|
||||
|
||||
return callback->OnInputStreamLengthReady(this, aLength);
|
||||
}
|
||||
|
||||
// private:
|
||||
BlobURLInputStream::~BlobURLInputStream() {
|
||||
if (mChannel) {
|
||||
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel", mChannel.forget());
|
||||
}
|
||||
}
|
||||
|
||||
BlobURLInputStream::BlobURLInputStream(BlobURLChannel* const aChannel,
|
||||
nsACString& aBlobURLSpec)
|
||||
: mChannel(aChannel),
|
||||
mBlobURLSpec(std::move(aBlobURLSpec)),
|
||||
mStateMachineMutex("BlobURLInputStream::mStateMachineMutex"),
|
||||
mState(State::INITIAL),
|
||||
mError(NS_OK),
|
||||
mBlobSize(-1),
|
||||
mAsyncWaitFlags(),
|
||||
mAsyncWaitRequestedCount() {}
|
||||
|
||||
void BlobURLInputStream::WaitOnUnderlyingStream(
|
||||
const MutexAutoLock& aProofOfLock) {
|
||||
if (mAsyncWaitCallback || mAsyncWaitTarget) {
|
||||
// AsyncWait should be called on the underlying stream
|
||||
mAsyncInputStream->AsyncWait(mAsyncWaitCallback ? this : nullptr,
|
||||
mAsyncWaitFlags, mAsyncWaitRequestedCount,
|
||||
mAsyncWaitTarget);
|
||||
}
|
||||
|
||||
if (mAsyncLengthWaitCallback || mAsyncLengthWaitTarget) {
|
||||
// AsyncLengthWait should be called on the underlying stream
|
||||
nsCOMPtr<nsIAsyncInputStreamLength> asyncStreamLength =
|
||||
do_QueryInterface(mAsyncInputStream);
|
||||
if (asyncStreamLength) {
|
||||
asyncStreamLength->AsyncLengthWait(
|
||||
mAsyncLengthWaitCallback ? this : nullptr, mAsyncLengthWaitTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlobURLInputStream::CallRetrieveBlobData() {
|
||||
MutexAutoLock lock(mStateMachineMutex);
|
||||
RetrieveBlobData(lock);
|
||||
}
|
||||
|
||||
void BlobURLInputStream::RetrieveBlobData(const MutexAutoLock& aProofOfLock) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
||||
|
||||
MOZ_ASSERT(mState == State::WAITING);
|
||||
|
||||
auto cleanupOnEarlyExit = MakeScopeExit([&] {
|
||||
mState = State::ERROR;
|
||||
mError = NS_ERROR_FAILURE;
|
||||
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel", mChannel.forget());
|
||||
NotifyWaitTargets(aProofOfLock);
|
||||
});
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
if (NS_WARN_IF(NS_FAILED(mChannel->GetLoadInfo(getter_AddRefs(loadInfo))))) {
|
||||
NS_WARNING("Failed to get owning channel's loadinfo");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> loadingPrincipal;
|
||||
if (NS_WARN_IF(NS_FAILED(loadInfo->GetTriggeringPrincipal(
|
||||
getter_AddRefs(triggeringPrincipal)))) ||
|
||||
NS_WARN_IF(!triggeringPrincipal)) {
|
||||
NS_WARNING("Failed to get owning channel's triggering principal");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal))))) {
|
||||
NS_WARNING("Failed to get owning channel's loading principal");
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess() || !BlobURLSchemeIsHTTPOrHTTPS(mBlobURLSpec)) {
|
||||
nsIPrincipal* const dataEntryPrincipal =
|
||||
BlobURLProtocolHandler::GetDataEntryPrincipal(mBlobURLSpec,
|
||||
true /* AlsoIfRevoked */);
|
||||
|
||||
// Since revoked blobs are also retrieved, it is possible that the blob no
|
||||
// longer exists (due to the 5 second timeout) when execution reaches here
|
||||
if (!dataEntryPrincipal) {
|
||||
NS_WARNING("Failed to get data entry principal. URL revoked?");
|
||||
return;
|
||||
}
|
||||
|
||||
// We want to be sure that we stop the creation of the channel if the blob
|
||||
// URL is copy-and-pasted on a different context (ex. private browsing or
|
||||
// containers).
|
||||
//
|
||||
// We also allow the system principal to create the channel regardless of
|
||||
// the OriginAttributes. This is primarily for the benefit of mechanisms
|
||||
// like the Download API that explicitly create a channel with the system
|
||||
// principal and which is never mutated to have a non-zero
|
||||
// mPrivateBrowsingId or container.
|
||||
if (NS_WARN_IF(!loadingPrincipal ||
|
||||
!loadingPrincipal->IsSystemPrincipal()) &&
|
||||
NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
|
||||
loadInfo->GetOriginAttributes(),
|
||||
BasePrincipal::Cast(dataEntryPrincipal)->OriginAttributesRef()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!triggeringPrincipal->Subsumes(dataEntryPrincipal))) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl;
|
||||
nsresult rv = NS_GetBlobForBlobURISpec(
|
||||
mBlobURLSpec, getter_AddRefs(blobImpl), true /* AlsoIfRevoked */);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || (NS_WARN_IF(!blobImpl))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(
|
||||
NS_FAILED(StoreBlobImplStream(blobImpl.forget(), aProofOfLock)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
mState = State::READY;
|
||||
|
||||
// By design, execution can only reach here when a caller has called
|
||||
// AsyncWait or AsyncLengthWait on this stream. The underlying stream is
|
||||
// valid, but the caller should not be informed until that stream has data
|
||||
// to read or it is closed.
|
||||
WaitOnUnderlyingStream(aProofOfLock);
|
||||
|
||||
cleanupOnEarlyExit.release();
|
||||
return;
|
||||
}
|
||||
|
||||
ContentChild* contentChild{ContentChild::GetSingleton()};
|
||||
MOZ_ASSERT(contentChild);
|
||||
|
||||
const RefPtr<BlobURLInputStream> self = this;
|
||||
|
||||
cleanupOnEarlyExit.release();
|
||||
|
||||
contentChild
|
||||
->SendBlobURLDataRequest(mBlobURLSpec, triggeringPrincipal,
|
||||
loadingPrincipal,
|
||||
loadInfo->GetOriginAttributes())
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[self](const BlobURLDataRequestResult& aResult) {
|
||||
MutexAutoLock lock(self->mStateMachineMutex);
|
||||
if (aResult.type() == BlobURLDataRequestResult::TIPCBlob) {
|
||||
if (self->mState == State::WAITING) {
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
IPCBlobUtils::Deserialize(aResult.get_IPCBlob());
|
||||
if (blobImpl && self->StoreBlobImplStream(blobImpl.forget(),
|
||||
lock) == NS_OK) {
|
||||
self->mState = State::READY;
|
||||
// By design, execution can only reach here when a caller has
|
||||
// called AsyncWait or AsyncLengthWait on this stream. The
|
||||
// underlying stream is valid, but the caller should not be
|
||||
// informed until that stream has data to read or it is
|
||||
// closed.
|
||||
self->WaitOnUnderlyingStream(lock);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(self->mState == State::CLOSED);
|
||||
// Callback can be called immediately
|
||||
self->NotifyWaitTargets(lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_WARNING("Blob data was not retrieved!");
|
||||
self->mState = State::ERROR;
|
||||
self->mError = aResult.type() == BlobURLDataRequestResult::Tnsresult
|
||||
? aResult.get_nsresult()
|
||||
: NS_ERROR_FAILURE;
|
||||
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel",
|
||||
self->mChannel.forget());
|
||||
self->NotifyWaitTargets(lock);
|
||||
},
|
||||
[self](mozilla::ipc::ResponseRejectReason aReason) {
|
||||
MutexAutoLock lock(self->mStateMachineMutex);
|
||||
NS_WARNING("IPC call to SendBlobURLDataRequest failed!");
|
||||
self->mState = State::ERROR;
|
||||
self->mError = NS_ERROR_FAILURE;
|
||||
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel",
|
||||
self->mChannel.forget());
|
||||
self->NotifyWaitTargets(lock);
|
||||
});
|
||||
}
|
||||
|
||||
nsresult BlobURLInputStream::StoreBlobImplStream(
|
||||
already_AddRefed<BlobImpl> aBlobImpl, const MutexAutoLock& aProofOfLock) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
||||
const RefPtr<BlobImpl> blobImpl = aBlobImpl;
|
||||
nsAutoString contentType;
|
||||
blobImpl->GetType(contentType);
|
||||
mChannel->SetContentType(NS_ConvertUTF16toUTF8(contentType));
|
||||
|
||||
auto cleanupOnExit = MakeScopeExit([&] { mChannel = nullptr; });
|
||||
|
||||
if (blobImpl->IsFile()) {
|
||||
nsAutoString filename;
|
||||
blobImpl->GetName(filename);
|
||||
if (!filename.IsEmpty()) {
|
||||
mChannel->SetContentDispositionFilename(filename);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ErrorResult errorResult;
|
||||
|
||||
mBlobSize = blobImpl->GetSize(errorResult);
|
||||
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return errorResult.StealNSResult();
|
||||
}
|
||||
|
||||
mChannel->SetContentLength(mBlobSize);
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
blobImpl->CreateInputStream(getter_AddRefs(inputStream), errorResult);
|
||||
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return errorResult.StealNSResult();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!inputStream)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult rv = NS_MakeAsyncNonBlockingInputStream(
|
||||
inputStream.forget(), getter_AddRefs(mAsyncInputStream));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mAsyncInputStream)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void BlobURLInputStream::NotifyWaitTargets(const MutexAutoLock& aProofOfLock) {
|
||||
if (mAsyncWaitCallback) {
|
||||
auto callback = mAsyncWaitTarget
|
||||
? NS_NewInputStreamReadyEvent(
|
||||
"BlobURLInputStream::OnInputStreamReady",
|
||||
mAsyncWaitCallback, mAsyncWaitTarget)
|
||||
: mAsyncWaitCallback;
|
||||
|
||||
mAsyncWaitCallback = nullptr;
|
||||
mAsyncWaitTarget = nullptr;
|
||||
callback->OnInputStreamReady(this);
|
||||
}
|
||||
|
||||
if (mAsyncLengthWaitCallback) {
|
||||
const RefPtr<BlobURLInputStream> self = this;
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
|
||||
"BlobURLInputStream::OnInputStreamLengthReady", [self] {
|
||||
self->mAsyncLengthWaitCallback->OnInputStreamLengthReady(
|
||||
self, self->mBlobSize);
|
||||
});
|
||||
|
||||
mAsyncLengthWaitCallback = nullptr;
|
||||
|
||||
if (mAsyncLengthWaitTarget) {
|
||||
mAsyncLengthWaitTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
mAsyncLengthWaitTarget = nullptr;
|
||||
} else {
|
||||
runnable->Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlobURLInputStream::ReleaseUnderlyingStream(
|
||||
const MutexAutoLock& aProofOfLock) {
|
||||
mAsyncInputStream = nullptr;
|
||||
mBlobSize = -1;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_BlobURLInputStream_h
|
||||
#define mozilla_dom_BlobURLInputStream_h
|
||||
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIInputStreamLength.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BlobURL;
|
||||
class BlobURLChannel;
|
||||
class BlobURLInputStream final : public nsIAsyncInputStream,
|
||||
public nsIInputStreamLength,
|
||||
public nsIAsyncInputStreamLength,
|
||||
public nsIInputStreamCallback,
|
||||
public nsIInputStreamLengthCallback {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
NS_DECL_NSIINPUTSTREAMLENGTH
|
||||
NS_DECL_NSIASYNCINPUTSTREAMLENGTH
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
NS_DECL_NSIINPUTSTREAMLENGTHCALLBACK
|
||||
|
||||
static already_AddRefed<nsIInputStream> Create(BlobURLChannel* const aChannel,
|
||||
BlobURL* const aBlobURL);
|
||||
|
||||
BlobURLInputStream(BlobURLChannel* const aChannel, nsACString& aBlobURLSpec);
|
||||
|
||||
private:
|
||||
enum class State { INITIAL, READY, WAITING, CLOSED, ERROR };
|
||||
|
||||
~BlobURLInputStream();
|
||||
|
||||
void WaitOnUnderlyingStream(const MutexAutoLock& aProofOfLock);
|
||||
|
||||
// This method should only be used to call RetrieveBlobData in a different
|
||||
// thread
|
||||
void CallRetrieveBlobData();
|
||||
|
||||
void RetrieveBlobData(const MutexAutoLock& aProofOfLock);
|
||||
|
||||
nsresult StoreBlobImplStream(already_AddRefed<BlobImpl> aBlobImpl,
|
||||
const MutexAutoLock& aProofOfLock);
|
||||
void NotifyWaitTargets(const MutexAutoLock& aProofOfLock);
|
||||
void ReleaseUnderlyingStream(const MutexAutoLock& aProofOfLock);
|
||||
|
||||
RefPtr<BlobURLChannel> mChannel;
|
||||
const nsCString mBlobURLSpec;
|
||||
|
||||
// Non-recursive mutex introduced in order to guard access to mState, mError
|
||||
// and mAsyncInputStream
|
||||
Mutex mStateMachineMutex;
|
||||
State mState;
|
||||
// Stores the error code if stream is in error state
|
||||
nsresult mError;
|
||||
|
||||
int64_t mBlobSize;
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;
|
||||
nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
|
||||
nsCOMPtr<nsIEventTarget> mAsyncWaitTarget;
|
||||
uint32_t mAsyncWaitFlags;
|
||||
uint32_t mAsyncWaitRequestedCount;
|
||||
|
||||
nsCOMPtr<nsIInputStreamLengthCallback> mAsyncLengthWaitCallback;
|
||||
nsCOMPtr<nsIEventTarget> mAsyncLengthWaitTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_BlobURLInputStream_h */
|
|
@ -30,6 +30,7 @@
|
|||
#include "nsIPrincipal.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
#define RELEASING_TIMER 5000
|
||||
|
||||
|
@ -688,14 +689,14 @@ nsresult BlobURLProtocolHandler::GenerateURIString(nsIPrincipal* aPrincipal,
|
|||
|
||||
/* static */
|
||||
nsIPrincipal* BlobURLProtocolHandler::GetDataEntryPrincipal(
|
||||
const nsACString& aUri) {
|
||||
const nsACString& aUri, bool aAlsoIfRevoked) {
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"without locking gDataTable is main-thread only");
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res = GetDataInfo(aUri);
|
||||
DataInfo* res = GetDataInfo(aUri, aAlsoIfRevoked);
|
||||
|
||||
if (!res) {
|
||||
return nullptr;
|
||||
|
@ -779,60 +780,10 @@ BlobURLProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aResult) {
|
|||
NS_IMETHODIMP
|
||||
BlobURLProtocolHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** aResult) {
|
||||
RefPtr<BlobURLChannel> channel = new BlobURLChannel(aURI, aLoadInfo);
|
||||
|
||||
auto raii = MakeScopeExit([&] {
|
||||
channel->InitFailed();
|
||||
channel.forget(aResult);
|
||||
});
|
||||
|
||||
RefPtr<BlobURL> blobURL;
|
||||
nsresult rv =
|
||||
aURI->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(blobURL));
|
||||
if (NS_FAILED(rv) || !blobURL) {
|
||||
return NS_OK;
|
||||
auto channel = MakeRefPtr<BlobURLChannel>(aURI, aLoadInfo);
|
||||
if (!channel) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"without locking gDataTable is main-thread only");
|
||||
DataInfo* info = GetDataInfoFromURI(aURI, true /*aAlsoIfRevoked */);
|
||||
if (!info || info->mObjectType != DataInfo::eBlobImpl || !info->mBlobImpl) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (blobURL->Revoked()) {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// if the channel was not triggered by the system principal,
|
||||
// then we return here because the URL had been revoked
|
||||
if (aLoadInfo && !aLoadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
|
||||
return NS_OK;
|
||||
}
|
||||
#else
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
// We want to be sure that we stop the creation of the channel if the blob URL
|
||||
// is copy-and-pasted on a different context (ex. private browsing or
|
||||
// containers).
|
||||
//
|
||||
// We also allow the system principal to create the channel regardless of the
|
||||
// OriginAttributes. This is primarily for the benefit of mechanisms like
|
||||
// the Download API that explicitly create a channel with the system
|
||||
// principal and which is never mutated to have a non-zero mPrivateBrowsingId
|
||||
// or container.
|
||||
if (aLoadInfo &&
|
||||
(!aLoadInfo->GetLoadingPrincipal() ||
|
||||
!aLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()) &&
|
||||
!ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
|
||||
aLoadInfo->GetOriginAttributes(),
|
||||
BasePrincipal::Cast(info->mPrincipal)->OriginAttributesRef())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
raii.release();
|
||||
|
||||
channel->Initialize(info->mBlobImpl);
|
||||
channel.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -901,13 +852,14 @@ nsresult NS_GetBlobForBlobURI(nsIURI* aURI, BlobImpl** aBlob) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, BlobImpl** aBlob) {
|
||||
nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, BlobImpl** aBlob,
|
||||
bool aAlsoIfRevoked) {
|
||||
*aBlob = nullptr;
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"without locking gDataTable is main-thread only");
|
||||
|
||||
DataInfo* info = GetDataInfo(aSpec);
|
||||
if (!info || info->mObjectType != DataInfo::eBlobImpl) {
|
||||
DataInfo* info = GetDataInfo(aSpec, aAlsoIfRevoked);
|
||||
if (!info || info->mObjectType != DataInfo::eBlobImpl || !info->mBlobImpl) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
|
@ -947,6 +899,11 @@ bool IsType(nsIURI* aUri, DataInfo::ObjectType aType) {
|
|||
|
||||
bool IsBlobURI(nsIURI* aUri) { return IsType(aUri, DataInfo::eBlobImpl); }
|
||||
|
||||
bool BlobURLSchemeIsHTTPOrHTTPS(const nsACString& aUri) {
|
||||
return (StringBeginsWith(aUri, "blob:http://"_ns) ||
|
||||
StringBeginsWith(aUri, "blob:https://"_ns));
|
||||
}
|
||||
|
||||
bool IsMediaSourceURI(nsIURI* aUri) {
|
||||
return IsType(aUri, DataInfo::eMediaSource);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler,
|
|||
|
||||
static bool HasDataEntry(const nsACString& aUri);
|
||||
|
||||
static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri);
|
||||
static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri,
|
||||
bool aAlsoIfRevoked = false);
|
||||
static void Traverse(const nsACString& aUri,
|
||||
nsCycleCollectionTraversalCallback& aCallback);
|
||||
|
||||
|
@ -98,6 +99,9 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler,
|
|||
bool IsBlobURI(nsIURI* aUri);
|
||||
bool IsMediaSourceURI(nsIURI* aUri);
|
||||
|
||||
// Return true if inner scheme of blobURL is http or https, false otherwise.
|
||||
bool BlobURLSchemeIsHTTPOrHTTPS(const nsACString& aUri);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -105,7 +109,8 @@ extern nsresult NS_GetBlobForBlobURI(nsIURI* aURI,
|
|||
mozilla::dom::BlobImpl** aBlob);
|
||||
|
||||
extern nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec,
|
||||
mozilla::dom::BlobImpl** aBlob);
|
||||
mozilla::dom::BlobImpl** aBlob,
|
||||
bool aAlsoIfRevoked = false);
|
||||
|
||||
extern nsresult NS_GetSourceForMediaSourceURI(
|
||||
nsIURI* aURI, mozilla::dom::MediaSource** aSource);
|
||||
|
|
|
@ -9,6 +9,7 @@ with Files("**"):
|
|||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'BlobURL.h',
|
||||
'BlobURLInputStream.h',
|
||||
'BlobURLProtocolHandler.h',
|
||||
'FontTableURIProtocolHandler.h',
|
||||
]
|
||||
|
@ -16,6 +17,7 @@ EXPORTS.mozilla.dom += [
|
|||
UNIFIED_SOURCES += [
|
||||
'BlobURL.cpp',
|
||||
'BlobURLChannel.cpp',
|
||||
'BlobURLInputStream.cpp',
|
||||
'BlobURLProtocolHandler.cpp',
|
||||
'FontTableURIProtocolHandler.cpp',
|
||||
]
|
||||
|
|
|
@ -413,6 +413,10 @@ void nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition) {
|
|||
Shutdown();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->NotifyObservers(wrapped, "geolocation-position-events",
|
||||
u"location-updated");
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
if (mCallback.HasWebIDLCallback()) {
|
||||
RefPtr<PositionCallback> callback = mCallback.GetWebIDLCallback();
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/StaticPrefs_security.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIXMLContentSink.h"
|
||||
|
||||
static mozilla::LazyLogModule gMetaElementLog("nsMetaElement");
|
||||
#define LOG(msg) MOZ_LOG(gMetaElementLog, mozilla::LogLevel::Debug, msg)
|
||||
|
@ -86,6 +88,24 @@ nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
|
|||
return rv;
|
||||
}
|
||||
Document& doc = aContext.OwnerDoc();
|
||||
|
||||
bool shouldProcessMeta = true;
|
||||
// We don't want to call ProcessMETATag when we are pretty print
|
||||
// the document
|
||||
if (doc.IsXMLDocument()) {
|
||||
if (nsCOMPtr<nsIXMLContentSink> xmlSink =
|
||||
do_QueryInterface(doc.GetCurrentContentSink())) {
|
||||
if (xmlSink->IsPrettyPrintXML() &&
|
||||
xmlSink->IsPrettyPrintHasSpecialRoot()) {
|
||||
shouldProcessMeta = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldProcessMeta) {
|
||||
doc.ProcessMETATag(this);
|
||||
}
|
||||
|
||||
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport,
|
||||
eIgnoreCase)) {
|
||||
ProcessViewportContent(&doc);
|
||||
|
|
|
@ -6825,6 +6825,71 @@ PFileDescriptorSetParent* ContentParent::SendPFileDescriptorSetConstructor(
|
|||
return PContentParent::SendPFileDescriptorSetConstructor(aFD);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
|
||||
const nsCString& aBlobURL, nsIPrincipal* pTriggeringPrincipal,
|
||||
nsIPrincipal* pLoadingPrincipal, const OriginAttributes& aOriginAttributes,
|
||||
BlobURLDataRequestResolver&& aResolver) {
|
||||
RefPtr<BlobImpl> blobImpl;
|
||||
nsresult rv = NS_GetBlobForBlobURISpec(aBlobURL, getter_AddRefs(blobImpl),
|
||||
true /* AlsoIfRevoked */);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResolver(rv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!blobImpl)) {
|
||||
aResolver(NS_ERROR_DOM_BAD_URI);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// Since revoked blobs are also retrieved, it is possible that the blob no
|
||||
// longer exists (due to the 5 second timeout) when execution reaches here
|
||||
nsIPrincipal* const dataEntryPrincipal =
|
||||
BlobURLProtocolHandler::GetDataEntryPrincipal(aBlobURL,
|
||||
true /* AlsoIfRevoked */);
|
||||
|
||||
if (!dataEntryPrincipal) {
|
||||
aResolver(NS_ERROR_DOM_BAD_URI);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// We want to be sure that we stop the creation of the channel if the blob
|
||||
// URL is copy-and-pasted on a different context (ex. private browsing or
|
||||
// containers).
|
||||
//
|
||||
// We also allow the system principal to create the channel regardless of
|
||||
// the OriginAttributes. This is primarily for the benefit of mechanisms
|
||||
// like the Download API that explicitly create a channel with the system
|
||||
// principal and which is never mutated to have a non-zero
|
||||
// mPrivateBrowsingId or container.
|
||||
|
||||
if (NS_WARN_IF(!pLoadingPrincipal ||
|
||||
!pLoadingPrincipal->IsSystemPrincipal()) &&
|
||||
NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
|
||||
aOriginAttributes,
|
||||
BasePrincipal::Cast(dataEntryPrincipal)->OriginAttributesRef()))) {
|
||||
aResolver(NS_ERROR_DOM_BAD_URI);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (!pTriggeringPrincipal->Subsumes(dataEntryPrincipal)) {
|
||||
aResolver(NS_ERROR_DOM_BAD_URI);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCBlob ipcBlob;
|
||||
rv = IPCBlobUtils::Serialize(blobImpl, this, ipcBlob);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResolver(rv);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
aResolver(ipcBlob);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
|
||||
uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
|
|
|
@ -697,6 +697,12 @@ class ContentParent final
|
|||
PFileDescriptorSetParent* SendPFileDescriptorSetConstructor(
|
||||
const FileDescriptor& aFD) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvBlobURLDataRequest(
|
||||
const nsCString& aBlobURL, nsIPrincipal* pTriggeringPrincipal,
|
||||
nsIPrincipal* pLoadingPrincipal,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
BlobURLDataRequestResolver&& aResolver);
|
||||
|
||||
protected:
|
||||
bool CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
|
||||
const char* aOperation) const;
|
||||
|
|
|
@ -381,6 +381,12 @@ union SyncedContextInitializer
|
|||
WindowContextInitializer;
|
||||
};
|
||||
|
||||
union BlobURLDataRequestResult
|
||||
{
|
||||
IPCBlob;
|
||||
nsresult;
|
||||
};
|
||||
|
||||
/**
|
||||
* The PContent protocol is a top-level protocol between the UI process
|
||||
* and a content process. There is exactly one PContentParent/PContentChild pair
|
||||
|
@ -1658,6 +1664,8 @@ parent:
|
|||
async HistoryGo(MaybeDiscardedBrowsingContext aContext,
|
||||
int32_t aOffset) returns(int32_t requestedIndex);
|
||||
|
||||
async BlobURLDataRequest(nsCString aBlobURL, nsIPrincipal aTriggeringPrincipal, nsIPrincipal aLoadingPrincipal, OriginAttributes aOriginAttributes) returns (BlobURLDataRequestResult aResult);
|
||||
|
||||
both:
|
||||
async ScriptError(nsString message, nsString sourceName, nsString sourceLine,
|
||||
uint32_t lineNumber, uint32_t colNumber, uint32_t flags,
|
||||
|
|
|
@ -850,12 +850,26 @@ void MediaTrackGraphImpl::NotifyInputData(const AudioDataValue* aBuffer,
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
mInputData = aBuffer;
|
||||
mInputFrames = aFrames;
|
||||
mInputChannelCount = aChannels;
|
||||
}
|
||||
|
||||
void MediaTrackGraphImpl::ProcessInputData() {
|
||||
if (!mInputData) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<AudioDataListener>>* listeners =
|
||||
mInputDeviceUsers.GetValue(mInputDeviceID);
|
||||
MOZ_ASSERT(listeners);
|
||||
for (auto& listener : *listeners) {
|
||||
listener->NotifyInputData(this, aBuffer, aFrames, aRate, aChannels);
|
||||
listener->NotifyInputData(this, mInputData, mInputFrames, GraphRate(), mInputChannelCount);
|
||||
}
|
||||
|
||||
mInputData = nullptr;
|
||||
mInputFrames = 0;
|
||||
mInputChannelCount = 0;
|
||||
}
|
||||
|
||||
void MediaTrackGraphImpl::DeviceChangedImpl() {
|
||||
|
@ -1381,6 +1395,8 @@ auto MediaTrackGraphImpl::OneIterationImpl(GraphTime aStateEnd,
|
|||
DemoteThreadFromRealTime();
|
||||
}
|
||||
|
||||
ProcessInputData();
|
||||
|
||||
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
|
||||
// thread, and so the monitor need not be held to check mLifecycleState.
|
||||
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
|
||||
|
@ -3013,6 +3029,9 @@ MediaTrackGraphImpl::MediaTrackGraphImpl(
|
|||
mPortCount(0),
|
||||
mInputDeviceID(nullptr),
|
||||
mOutputDeviceID(aOutputDeviceID),
|
||||
mInputData(nullptr),
|
||||
mInputChannelCount(0),
|
||||
mInputFrames(0),
|
||||
mMonitor("MediaTrackGraphImpl"),
|
||||
mLifecycleState(LIFECYCLE_THREAD_NOT_STARTED),
|
||||
mPostedRunInStableStateEvent(false),
|
||||
|
|
|
@ -427,10 +427,14 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
|
|||
/* Called on the graph thread before the first Notify*Data after an
|
||||
* AudioCallbackDriver starts. */
|
||||
void NotifyStarted() override;
|
||||
/* Called on the graph thread when there is new input data for listeners. This
|
||||
* is the raw audio input for this MediaTrackGraph. */
|
||||
/* Called on the audio callback thread when there is new input data for
|
||||
* listeners. This is the raw audio input for this MediaTrackGraph. Actual
|
||||
* processing happens in ProcessInputData */
|
||||
void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames,
|
||||
TrackRate aRate, uint32_t aChannels) override;
|
||||
/* Called on the graph thread to process the input data delivered in each
|
||||
* iteration by NotifyInputData. */
|
||||
void ProcessInputData();
|
||||
/* Called every time there are changes to input/output audio devices like
|
||||
* plug/unplug etc. This can be called on any thread, and posts a message to
|
||||
* the main thread so that it can post a message to the graph thread. */
|
||||
|
@ -776,6 +780,11 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
|
|||
nsDataHashtable<nsVoidPtrHashKey, nsTArray<RefPtr<AudioDataListener>>>
|
||||
mInputDeviceUsers;
|
||||
|
||||
// Only valid for the current iteration: if non nullptr, there is input data.
|
||||
const AudioDataValue* mInputData;
|
||||
uint32_t mInputChannelCount;
|
||||
uint32_t mInputFrames;
|
||||
|
||||
/**
|
||||
* List of resume operations waiting for a switch to an AudioCallbackDriver.
|
||||
*/
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
include protocol PGMPContent;
|
||||
include GMPTypes;
|
||||
|
||||
include "GMPMessageUtils.h";
|
||||
|
||||
using cdm::HdcpVersion from "content_decryption_module.h";
|
||||
|
||||
include "GMPMessageUtils.h";
|
||||
|
@ -64,7 +66,7 @@ child:
|
|||
async GiveBuffer(Shmem aShmem);
|
||||
|
||||
async PurgeShmems();
|
||||
|
||||
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#define BUFFER_SIZE 65536
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class CopierCallbacks final : public nsIRequestObserver {
|
||||
public:
|
||||
|
@ -548,3 +548,6 @@ PresentationTCPSessionTransport::OnDataAvailable(nsIRequest* aRequest,
|
|||
// Pass the incoming data to the listener.
|
||||
return mCallback->NotifyData(data, false);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -27,6 +27,7 @@ support-files =
|
|||
file_presentation_mixed_security_contexts.html
|
||||
|
||||
[test_presentation_dc_sender.html]
|
||||
skip-if = e10s # Bug 1656033
|
||||
[test_presentation_dc_receiver.html]
|
||||
skip-if = e10s # Bug 1129785
|
||||
[test_presentation_dc_receiver_oop.html]
|
||||
|
|
|
@ -41,8 +41,8 @@ nsHTTPSOnlyStreamListener::OnStartRequest(nsIRequest* request) {
|
|||
NS_IMETHODIMP
|
||||
nsHTTPSOnlyStreamListener::OnStopRequest(nsIRequest* request,
|
||||
nsresult aStatus) {
|
||||
// DNS errors are unrelated to the HTTPS-Only mode, so they can be ignored.
|
||||
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aStatus)) {
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
||||
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(channel, aStatus)) {
|
||||
RecordUpgradeTelemetry(request, aStatus);
|
||||
LogUpgradeFailure(request, aStatus);
|
||||
}
|
||||
|
|
|
@ -125,9 +125,34 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeWebSocket(nsIURI* aURI,
|
|||
}
|
||||
|
||||
/* static */
|
||||
bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsresult aError) {
|
||||
// This list of error codes is largely drawn from
|
||||
// nsDocShell::DisplayLoadError()
|
||||
bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
|
||||
nsresult aError) {
|
||||
// If there is no failed channel, then there is nothing to do here.
|
||||
if (!aChannel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If HTTPS-Only Mode is not enabled, then there is nothing to do here.
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the listener is not registerd, then there is nothing to do here.
|
||||
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
|
||||
if (!(httpsOnlyStatus &
|
||||
nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the load is exempt, then there is nothing to do here.
|
||||
if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it's one of those errors, then most likely it's not a HTTPS-Only error
|
||||
// (This list of errors is largely drawn from nsDocShell::DisplayLoadError())
|
||||
return !(NS_ERROR_UNKNOWN_PROTOCOL == aError ||
|
||||
NS_ERROR_FILE_NOT_FOUND == aError ||
|
||||
NS_ERROR_FILE_ACCESS_DENIED == aError ||
|
||||
|
@ -213,8 +238,8 @@ bool nsHTTPSOnlyUtils::LoopbackOrLocalException(nsIURI* aURI) {
|
|||
nsresult rv = aURI->GetAsciiHost(asciiHost);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// Let's make a quick check if the host matches these loopback strings before
|
||||
// we do anything else
|
||||
// Let's make a quick check if the host matches these loopback strings
|
||||
// before we do anything else
|
||||
if (asciiHost.EqualsLiteral("localhost") || asciiHost.EqualsLiteral("::1")) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -44,10 +44,11 @@ class nsHTTPSOnlyUtils {
|
|||
/**
|
||||
* Checks if the error code is on a block-list of codes that are probably not
|
||||
* related to a HTTPS-Only Mode upgrade.
|
||||
* @param aChannel The failed Channel.
|
||||
* @param aError Error Code from Request
|
||||
* @return false if error is not related to upgrade
|
||||
*/
|
||||
static bool CouldBeHttpsOnlyError(nsresult aError);
|
||||
static bool CouldBeHttpsOnlyError(nsIChannel* aChannel, nsresult aError);
|
||||
|
||||
/**
|
||||
* Logs localized message to either content console or browser console
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let geolocation = null;
|
||||
let numRequests = 0;
|
||||
let locations = [
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
];
|
||||
|
||||
function geoHandler(metadata, response) {
|
||||
numRequests++;
|
||||
let [lat, lng] = locations.shift();
|
||||
response.setStatusLine("1.0", 200, "OK");
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
response.setHeader("Content-Type", "application/x-javascript", false);
|
||||
response.write(
|
||||
JSON.stringify({
|
||||
status: "OK",
|
||||
location: { lat, lng },
|
||||
accuracy: 42,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function toJSON(pos) {
|
||||
return { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||
}
|
||||
|
||||
function getPosition() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
geolocation.getCurrentPosition(resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
function watchPosition() {
|
||||
let seen = 0;
|
||||
return new Promise(function(resolve, reject) {
|
||||
let id = geolocation.watchPosition(position => {
|
||||
seen++;
|
||||
if (seen === 1) {
|
||||
Assert.deepEqual(toJSON(position), { lat: 3, lng: 4 });
|
||||
Assert.deepEqual(observer._lastData, { lat: 3, lng: 4 });
|
||||
Assert.equal(observer._countEvents, 2);
|
||||
} else if (seen === 2) {
|
||||
Assert.deepEqual(toJSON(position), { lat: 5, lng: 6 });
|
||||
Assert.deepEqual(observer._lastData, { lat: 5, lng: 6 });
|
||||
Assert.equal(observer._countEvents, 3);
|
||||
geolocation.clearWatch(id);
|
||||
resolve();
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
let observer = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
||||
|
||||
observe(subject, topic, data) {
|
||||
Assert.equal(topic, "geolocation-position-events");
|
||||
observer._countEvents++;
|
||||
observer._lastData = toJSON(subject);
|
||||
},
|
||||
|
||||
_lastData: null,
|
||||
_countEvents: 0,
|
||||
};
|
||||
|
||||
add_task(async function test_resetClient() {
|
||||
do_get_profile();
|
||||
geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports);
|
||||
|
||||
let server = new HttpServer();
|
||||
server.registerPathHandler("/geo", geoHandler);
|
||||
server.start(-1);
|
||||
|
||||
Services.prefs.setCharPref(
|
||||
"geo.provider.network.url",
|
||||
"http://localhost:" + server.identity.primaryPort + "/geo"
|
||||
);
|
||||
Services.prefs.setBoolPref(
|
||||
"geo.provider.network.debug.requestCache.enabled",
|
||||
false
|
||||
);
|
||||
Services.prefs.setBoolPref("geo.provider.network.scan", false);
|
||||
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].getService();
|
||||
obs = obs.QueryInterface(Ci.nsIObserverService);
|
||||
obs.addObserver(observer, "geolocation-position-events");
|
||||
|
||||
let position = await getPosition();
|
||||
Assert.deepEqual(toJSON(position), { lat: 1, lng: 2 });
|
||||
Assert.equal(observer._countEvents, 1);
|
||||
Assert.deepEqual(observer._lastData, { lat: 1, lng: 2 });
|
||||
|
||||
await watchPosition();
|
||||
|
||||
await new Promise(resolve => server.stop(resolve));
|
||||
});
|
|
@ -5,6 +5,7 @@ head =
|
|||
[test_bug465752.js]
|
||||
[test_Fetch.js]
|
||||
[test_geolocation_provider.js]
|
||||
[test_geolocation_monitor.js]
|
||||
[test_geolocation_timeout.js]
|
||||
[test_geolocation_timeout_wrap.js]
|
||||
skip-if = os == "mac" || os == "android"
|
||||
|
|
|
@ -50,6 +50,8 @@ class Document;
|
|||
class nsIXMLContentSink : public nsIContentSink {
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXMLCONTENT_SINK_IID)
|
||||
virtual bool IsPrettyPrintXML() const { return false; }
|
||||
virtual bool IsPrettyPrintHasSpecialRoot() const { return false; }
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIXMLContentSink, NS_IXMLCONTENT_SINK_IID)
|
||||
|
|
|
@ -565,14 +565,9 @@ nsresult nsXMLContentSink::CloseElement(nsIContent* aContent) {
|
|||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
|
||||
// Need to check here to make sure this meta tag does not set
|
||||
// mPrettyPrintXML to false when we have a special root!
|
||||
(!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
|
||||
rv = ProcessMETATag(aContent);
|
||||
} else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
|
||||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
|
||||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
|
||||
if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
|
||||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
|
||||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
|
||||
if (auto* linkStyle = LinkStyle::FromNode(*aContent)) {
|
||||
linkStyle->SetEnableUpdates(true);
|
||||
auto updateOrError =
|
||||
|
|
|
@ -73,6 +73,10 @@ class nsXMLContentSink : public nsContentSink,
|
|||
virtual nsISupports* GetTarget() override;
|
||||
virtual bool IsScriptExecuting() override;
|
||||
virtual void ContinueInterruptedParsingAsync() override;
|
||||
bool IsPrettyPrintXML() const override { return mPrettyPrintXML; }
|
||||
bool IsPrettyPrintHasSpecialRoot() const override {
|
||||
return mPrettyPrintHasSpecialRoot;
|
||||
}
|
||||
|
||||
// nsITransformObserver
|
||||
NS_IMETHOD OnDocumentCreated(
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<style>
|
||||
body {
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
div {
|
||||
height: 100px;
|
||||
background-color: rgba(0, 255, 0, 0.1);;
|
||||
transform: translateX(1px);
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "1px";
|
||||
for (var i = 2; i < 1000; i++) {
|
||||
var container = document.createElement('div');
|
||||
container.style.width = i + "px";
|
||||
container.appendChild(div);
|
||||
div = container;
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
</script>
|
||||
</body>
|
|
@ -195,3 +195,4 @@ load 1647862.html
|
|||
load 1647940.html
|
||||
load 1650989-very-large-mask.html
|
||||
load 1650990.html
|
||||
skip-if(!webrender||AddressSanitizer) load 1652750-deep-scene-stack.html
|
|
@ -2463,17 +2463,19 @@ bool js::array_pop(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return SetLengthProperty(cx, obj, index);
|
||||
}
|
||||
|
||||
void js::ArrayShiftMoveElements(NativeObject* obj) {
|
||||
void js::ArrayShiftMoveElements(ArrayObject* arr) {
|
||||
AutoUnsafeCallWithABI unsafe;
|
||||
MOZ_ASSERT(obj->isExtensible());
|
||||
MOZ_ASSERT_IF(obj->is<ArrayObject>(),
|
||||
obj->as<ArrayObject>().lengthIsWritable());
|
||||
MOZ_ASSERT(arr->isExtensible());
|
||||
MOZ_ASSERT(arr->lengthIsWritable());
|
||||
MOZ_ASSERT_IF(jit::JitOptions.warpBuilder, IsPackedArray(arr));
|
||||
MOZ_ASSERT(!arr->denseElementsAreCopyOnWrite());
|
||||
MOZ_ASSERT(!arr->denseElementsHaveMaybeInIterationFlag());
|
||||
|
||||
size_t initlen = obj->getDenseInitializedLength();
|
||||
size_t initlen = arr->getDenseInitializedLength();
|
||||
MOZ_ASSERT(initlen > 0);
|
||||
|
||||
if (!obj->tryShiftDenseElements(1)) {
|
||||
obj->moveDenseElementsNoPreBarrier(0, 1, initlen - 1);
|
||||
if (!arr->tryShiftDenseElements(1)) {
|
||||
arr->moveDenseElements(0, 1, initlen - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ extern bool array_pop(JSContext* cx, unsigned argc, js::Value* vp);
|
|||
|
||||
extern bool array_join(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
|
||||
extern void ArrayShiftMoveElements(NativeObject* obj);
|
||||
extern void ArrayShiftMoveElements(ArrayObject* arr);
|
||||
|
||||
extern bool array_shift(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
|
||||
|
|
|
@ -110,7 +110,8 @@
|
|||
#include "wasm/WasmTypes.h" // for WasmInstanceObjectVector
|
||||
|
||||
#include "debugger/DebugAPI-inl.h"
|
||||
#include "debugger/Frame-inl.h" // for DebuggerFrame::hasGeneratorInfo
|
||||
#include "debugger/Environment-inl.h" // for DebuggerEnvironment::owner
|
||||
#include "debugger/Frame-inl.h" // for DebuggerFrame::hasGeneratorInfo
|
||||
#include "debugger/Object-inl.h" // for DebuggerObject::owner and isInstance.
|
||||
#include "debugger/Script-inl.h" // for DebuggerScript::getReferent
|
||||
#include "gc/GC-inl.h" // for ZoneCellIter
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// |jit-test| skip-if: wasmCompilersPresent().match("cranelift")
|
||||
// (Reason: the Cranelift backend does not support shared memory yet.)
|
||||
|
||||
// |jit-test| skip-if: wasmCompilersPresent().match("cranelift") && !getBuildConfiguration()['arm64']
|
||||
//
|
||||
// (Reason: the Cranelift backend does not support shared memory on non-AArch64
|
||||
// hosts yet.)
|
||||
//
|
||||
// Tests of limits of memory and table types
|
||||
|
||||
const PageSize = 65536;
|
||||
|
|
|
@ -2030,6 +2030,7 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfoArg) {
|
|||
case BailoutKind::ProtoGuard:
|
||||
case BailoutKind::NotProxyGuard:
|
||||
case BailoutKind::NotArrayBufferMaybeSharedGuard:
|
||||
case BailoutKind::ArrayPopShift:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
|
|
|
@ -5099,6 +5099,59 @@ AttachDecision CallIRGenerator::tryAttachArrayPush(HandleFunction callee) {
|
|||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachArrayPopShift(HandleFunction callee,
|
||||
InlinableNative native) {
|
||||
// Expecting no arguments.
|
||||
if (argc_ != 0) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Only optimize if |this| is a packed array.
|
||||
if (!thisval_.isObject() || !IsPackedArray(&thisval_.toObject())) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Other conditions:
|
||||
//
|
||||
// * The array length needs to be writable because we're changing it.
|
||||
// * The elements must not be copy-on-write because we're deleting an element.
|
||||
// * The array must be extensible. Non-extensible arrays require preserving
|
||||
// the |initializedLength == capacity| invariant on ObjectElements.
|
||||
// See NativeObject::shrinkCapacityToInitializedLength.
|
||||
// This also ensures the elements aren't sealed/frozen.
|
||||
// * There must not be a for-in iterator for the elements because the IC stub
|
||||
// does not suppress deleted properties.
|
||||
ArrayObject* arr = &thisval_.toObject().as<ArrayObject>();
|
||||
if (!arr->lengthIsWritable() || arr->denseElementsAreCopyOnWrite() ||
|
||||
!arr->isExtensible() || arr->denseElementsHaveMaybeInIterationFlag()) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Initialize the input operand.
|
||||
Int32OperandId argcId(writer.setInputOperandId(0));
|
||||
|
||||
// Guard callee is the 'pop' or 'shift' native function.
|
||||
emitNativeCalleeGuard(callee);
|
||||
|
||||
ValOperandId thisValId =
|
||||
writer.loadArgumentFixedSlot(ArgumentKind::This, argc_);
|
||||
ObjOperandId objId = writer.guardToObject(thisValId);
|
||||
writer.guardClass(objId, GuardClassKind::Array);
|
||||
|
||||
if (native == InlinableNative::ArrayPop) {
|
||||
writer.packedArrayPopResult(objId);
|
||||
} else {
|
||||
MOZ_ASSERT(native == InlinableNative::ArrayShift);
|
||||
writer.packedArrayShiftResult(objId);
|
||||
}
|
||||
|
||||
writer.typeMonitorResult();
|
||||
cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored;
|
||||
|
||||
trackAttached("ArrayPopShift");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachArrayJoin(HandleFunction callee) {
|
||||
// Only handle argc <= 1.
|
||||
if (argc_ > 1) {
|
||||
|
@ -7432,6 +7485,9 @@ AttachDecision CallIRGenerator::tryAttachInlinableNative(
|
|||
return tryAttachArrayConstructor(callee);
|
||||
case InlinableNative::ArrayPush:
|
||||
return tryAttachArrayPush(callee);
|
||||
case InlinableNative::ArrayPop:
|
||||
case InlinableNative::ArrayShift:
|
||||
return tryAttachArrayPopShift(callee, native);
|
||||
case InlinableNative::ArrayJoin:
|
||||
return tryAttachArrayJoin(callee);
|
||||
case InlinableNative::ArrayIsArray:
|
||||
|
|
|
@ -1612,6 +1612,8 @@ class MOZ_RAII CallIRGenerator : public IRGenerator {
|
|||
void emitNativeCalleeGuard(HandleFunction callee);
|
||||
|
||||
AttachDecision tryAttachArrayPush(HandleFunction callee);
|
||||
AttachDecision tryAttachArrayPopShift(HandleFunction callee,
|
||||
InlinableNative native);
|
||||
AttachDecision tryAttachArrayJoin(HandleFunction callee);
|
||||
AttachDecision tryAttachArrayIsArray(HandleFunction callee);
|
||||
AttachDecision tryAttachDataViewGet(HandleFunction callee, Scalar::Type type);
|
||||
|
|
|
@ -3860,6 +3860,44 @@ bool CacheIRCompiler::emitArrayJoinResult(ObjOperandId objId) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitPackedArrayPopResult(ObjOperandId arrayId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
AutoOutputRegister output(*this);
|
||||
Register array = allocator.useRegister(masm, arrayId);
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
masm.packedArrayPop(array, output.valueReg(), scratch1, scratch2,
|
||||
failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitPackedArrayShiftResult(ObjOperandId arrayId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
AutoOutputRegister output(*this);
|
||||
Register array = allocator.useRegister(masm, arrayId);
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
AutoScratchRegister scratch2(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(),
|
||||
liveVolatileFloatRegs());
|
||||
masm.packedArrayShift(array, output.valueReg(), scratch1, scratch2,
|
||||
volatileRegs, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitIsObjectResult(ValOperandId inputId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
|
|
|
@ -18,16 +18,27 @@ bool CacheIRHealth::spewStubHealth(AutoStructuredSpewer& spew, ICStub* stub) {
|
|||
const CacheIRStubInfo* stubInfo = stub->cacheIRStubInfo();
|
||||
CacheIRReader stubReader(stubInfo);
|
||||
uint32_t totalStubHealth = 0;
|
||||
|
||||
spew->beginListProperty("cacheIROps");
|
||||
while (stubReader.more()) {
|
||||
CacheOp op = stubReader.readOp();
|
||||
uint32_t opHealth = CacheIROpHealth[size_t(op)];
|
||||
uint32_t argLength = CacheIROpArgLengths[size_t(op)];
|
||||
const char* opName = CacheIROpNames[size_t(op)];
|
||||
|
||||
spew->beginObject();
|
||||
if (opHealth == UINT32_MAX) {
|
||||
const char* opName = CacheIROpNames[size_t(op)];
|
||||
spew->property("unscoredOp", opName);
|
||||
} else {
|
||||
spew->property("cacheIROp", opName);
|
||||
spew->property("opHealth", opHealth);
|
||||
totalStubHealth += opHealth;
|
||||
}
|
||||
spew->endObject();
|
||||
|
||||
stubReader.skip(argLength);
|
||||
}
|
||||
spew->endList(); // cacheIROps
|
||||
|
||||
spew->property("stubHealth", totalStubHealth);
|
||||
return true;
|
||||
|
|
|
@ -890,6 +890,20 @@
|
|||
args:
|
||||
obj: ObjId
|
||||
|
||||
- name: PackedArrayPopResult
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 2
|
||||
args:
|
||||
array: ObjId
|
||||
|
||||
- name: PackedArrayShiftResult
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 4
|
||||
args:
|
||||
array: ObjId
|
||||
|
||||
- name: IsArrayResult
|
||||
shared: false
|
||||
transpile: true
|
||||
|
|
|
@ -10303,10 +10303,24 @@ void CodeGenerator::emitArrayPopShift(LInstruction* lir,
|
|||
|
||||
void CodeGenerator::visitArrayPopShiftV(LArrayPopShiftV* lir) {
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register elements = ToRegister(lir->temp0());
|
||||
Register length = ToRegister(lir->temp1());
|
||||
Register temp1 = ToRegister(lir->temp0());
|
||||
Register temp2 = ToRegister(lir->temp1());
|
||||
TypedOrValueRegister out(ToOutValue(lir));
|
||||
emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
|
||||
|
||||
if (JitOptions.warpBuilder) {
|
||||
Label bail;
|
||||
if (lir->mir()->mode() == MArrayPopShift::Pop) {
|
||||
masm.packedArrayPop(obj, out.valueReg(), temp1, temp2, &bail);
|
||||
} else {
|
||||
MOZ_ASSERT(lir->mir()->mode() == MArrayPopShift::Shift);
|
||||
LiveRegisterSet volatileRegs = liveVolatileRegs(lir);
|
||||
masm.packedArrayShift(obj, out.valueReg(), temp1, temp2, volatileRegs,
|
||||
&bail);
|
||||
}
|
||||
bailoutFrom(&bail, lir->snapshot());
|
||||
} else {
|
||||
emitArrayPopShift(lir, lir->mir(), obj, temp1, temp2, out);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir) {
|
||||
|
@ -10314,6 +10328,8 @@ void CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir) {
|
|||
Register elements = ToRegister(lir->temp0());
|
||||
Register length = ToRegister(lir->temp1());
|
||||
TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
|
||||
|
||||
MOZ_ASSERT(!JitOptions.warpBuilder);
|
||||
emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
|
||||
}
|
||||
|
||||
|
|
|
@ -176,6 +176,9 @@ enum class BailoutKind : uint8_t {
|
|||
// Bailout triggered by MGuardIsNotArrayBufferMaybeShared.
|
||||
NotArrayBufferMaybeSharedGuard,
|
||||
|
||||
// Bailout triggered by MArrayPopShift.
|
||||
ArrayPopShift,
|
||||
|
||||
// Bailout triggered by MGuardValue.
|
||||
ValueGuard,
|
||||
|
||||
|
@ -266,6 +269,8 @@ inline const char* BailoutKindString(BailoutKind kind) {
|
|||
return "BailoutKind::NotProxyGuard";
|
||||
case BailoutKind::NotArrayBufferMaybeSharedGuard:
|
||||
return "BailoutKind::NotArrayBufferMaybeSharedGuard";
|
||||
case BailoutKind::ArrayPopShift:
|
||||
return "BailoutKind::ArrayPopShift";
|
||||
case BailoutKind::ValueGuard:
|
||||
return "BailoutKind::ValueGuard";
|
||||
case BailoutKind::NullOrUndefinedGuard:
|
||||
|
|
|
@ -3466,8 +3466,13 @@ void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
|
|||
case MIRType::Value: {
|
||||
LArrayPopShiftV* lir =
|
||||
new (alloc()) LArrayPopShiftV(object, temp(), temp());
|
||||
if (JitOptions.warpBuilder) {
|
||||
assignSnapshot(lir, BailoutKind::ArrayPopShift);
|
||||
}
|
||||
defineBox(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
if (!JitOptions.warpBuilder || ins->mode() == MArrayPopShift::Shift) {
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MIRType::Undefined:
|
||||
|
|
|
@ -7892,7 +7892,9 @@ class MArrayPopShift : public MUnaryInstruction,
|
|||
: MUnaryInstruction(classOpcode, object),
|
||||
mode_(mode),
|
||||
needsHoleCheck_(needsHoleCheck),
|
||||
maybeUndefined_(maybeUndefined) {}
|
||||
maybeUndefined_(maybeUndefined) {
|
||||
setResultType(MIRType::Value);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ArrayPopShift)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "jit/Lowering.h"
|
||||
#include "jit/MIR.h"
|
||||
#include "jit/MoveEmitter.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
#include "jit/Simulator.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/Printf.h"
|
||||
|
@ -3894,6 +3895,122 @@ void MacroAssembler::setIsPackedArray(Register obj, Register output,
|
|||
bind(&done);
|
||||
}
|
||||
|
||||
void MacroAssembler::packedArrayPop(Register array, ValueOperand output,
|
||||
Register temp1, Register temp2,
|
||||
Label* fail) {
|
||||
// Load obj->elements in temp1.
|
||||
loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
|
||||
|
||||
// Check flags.
|
||||
static constexpr uint32_t UnhandledFlags =
|
||||
ObjectElements::Flags::NON_PACKED | ObjectElements::Flags::COPY_ON_WRITE |
|
||||
ObjectElements::Flags::NONWRITABLE_ARRAY_LENGTH |
|
||||
ObjectElements::Flags::NOT_EXTENSIBLE |
|
||||
ObjectElements::Flags::MAYBE_IN_ITERATION;
|
||||
Address flags(temp1, ObjectElements::offsetOfFlags());
|
||||
branchTest32(Assembler::NonZero, flags, Imm32(UnhandledFlags), fail);
|
||||
|
||||
// Load length in temp2. Ensure length == initializedLength.
|
||||
Address lengthAddr(temp1, ObjectElements::offsetOfLength());
|
||||
Address initLengthAddr(temp1, ObjectElements::offsetOfInitializedLength());
|
||||
load32(lengthAddr, temp2);
|
||||
branch32(Assembler::NotEqual, initLengthAddr, temp2, fail);
|
||||
|
||||
// Result is |undefined| if length == 0.
|
||||
Label notEmpty, done;
|
||||
branchTest32(Assembler::NonZero, temp2, temp2, ¬Empty);
|
||||
{
|
||||
moveValue(UndefinedValue(), output);
|
||||
jump(&done);
|
||||
}
|
||||
|
||||
bind(¬Empty);
|
||||
|
||||
// Load the last element.
|
||||
sub32(Imm32(1), temp2);
|
||||
BaseObjectElementIndex elementAddr(temp1, temp2);
|
||||
loadValue(elementAddr, output);
|
||||
|
||||
// Pre-barrier the element because we're removing it from the array.
|
||||
EmitPreBarrier(*this, elementAddr, MIRType::Value);
|
||||
|
||||
// Update length and initializedLength.
|
||||
store32(temp2, lengthAddr);
|
||||
store32(temp2, initLengthAddr);
|
||||
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
void MacroAssembler::packedArrayShift(Register array, ValueOperand output,
|
||||
Register temp1, Register temp2,
|
||||
LiveRegisterSet volatileRegs,
|
||||
Label* fail) {
|
||||
// Load obj->elements in temp1.
|
||||
loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
|
||||
|
||||
// Check flags.
|
||||
static constexpr uint32_t UnhandledFlags =
|
||||
ObjectElements::Flags::NON_PACKED | ObjectElements::Flags::COPY_ON_WRITE |
|
||||
ObjectElements::Flags::NONWRITABLE_ARRAY_LENGTH |
|
||||
ObjectElements::Flags::NOT_EXTENSIBLE |
|
||||
ObjectElements::Flags::MAYBE_IN_ITERATION;
|
||||
Address flags(temp1, ObjectElements::offsetOfFlags());
|
||||
branchTest32(Assembler::NonZero, flags, Imm32(UnhandledFlags), fail);
|
||||
|
||||
// Load length in temp2. Ensure length == initializedLength.
|
||||
Address lengthAddr(temp1, ObjectElements::offsetOfLength());
|
||||
Address initLengthAddr(temp1, ObjectElements::offsetOfInitializedLength());
|
||||
load32(lengthAddr, temp2);
|
||||
branch32(Assembler::NotEqual, initLengthAddr, temp2, fail);
|
||||
|
||||
// Result is |undefined| if length == 0.
|
||||
Label notEmpty, done;
|
||||
branchTest32(Assembler::NonZero, temp2, temp2, ¬Empty);
|
||||
{
|
||||
moveValue(UndefinedValue(), output);
|
||||
jump(&done);
|
||||
}
|
||||
|
||||
bind(¬Empty);
|
||||
|
||||
// Load the first element.
|
||||
Address elementAddr(temp1, 0);
|
||||
loadValue(elementAddr, output);
|
||||
|
||||
// Pre-barrier the element because we're removing it from the array.
|
||||
EmitPreBarrier(*this, elementAddr, MIRType::Value);
|
||||
|
||||
// Move the other elements.
|
||||
{
|
||||
// Ensure output and temp2 are in volatileRegs. Don't preserve temp1.
|
||||
volatileRegs.takeUnchecked(temp1);
|
||||
if (output.hasVolatileReg()) {
|
||||
volatileRegs.addUnchecked(output);
|
||||
}
|
||||
if (temp2.volatile_()) {
|
||||
volatileRegs.addUnchecked(temp2);
|
||||
}
|
||||
|
||||
PushRegsInMask(volatileRegs);
|
||||
|
||||
setupUnalignedABICall(temp1);
|
||||
passABIArg(array);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArrayShiftMoveElements));
|
||||
|
||||
PopRegsInMask(volatileRegs);
|
||||
|
||||
// Reload the elements. The call may have updated it.
|
||||
loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
|
||||
}
|
||||
|
||||
// Update length and initializedLength.
|
||||
sub32(Imm32(1), temp2);
|
||||
store32(temp2, lengthAddr);
|
||||
store32(temp2, initLengthAddr);
|
||||
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
static constexpr bool ValidateShiftRange(Scalar::Type from, Scalar::Type to) {
|
||||
for (Scalar::Type type = from; type < to; type = Scalar::Type(type + 1)) {
|
||||
if (TypedArrayShift(type) != TypedArrayShift(from)) {
|
||||
|
|
|
@ -3561,6 +3561,12 @@ class MacroAssembler : public MacroAssemblerSpecific {
|
|||
|
||||
void setIsPackedArray(Register obj, Register output, Register temp);
|
||||
|
||||
void packedArrayPop(Register array, ValueOperand output, Register temp1,
|
||||
Register temp2, Label* fail);
|
||||
void packedArrayShift(Register array, ValueOperand output, Register temp1,
|
||||
Register temp2, LiveRegisterSet volatileRegs,
|
||||
Label* fail);
|
||||
|
||||
void typedArrayElementShift(Register obj, Register output);
|
||||
void branchIfClassIsNotTypedArray(Register clasp, Label* notTypedArray);
|
||||
|
||||
|
|
|
@ -130,6 +130,9 @@ class ValueOperand {
|
|||
return type_ == reg || payload_ == reg;
|
||||
}
|
||||
constexpr Register payloadOrValueReg() const { return payloadReg(); }
|
||||
bool hasVolatileReg() const {
|
||||
return type_.volatile_() || payload_.volatile_();
|
||||
}
|
||||
constexpr bool operator==(const ValueOperand& o) const {
|
||||
return type_ == o.type_ && payload_ == o.payload_;
|
||||
}
|
||||
|
@ -147,6 +150,7 @@ class ValueOperand {
|
|||
constexpr Register64 toRegister64() const { return Register64(valueReg()); }
|
||||
constexpr bool aliases(Register reg) const { return value_ == reg; }
|
||||
constexpr Register payloadOrValueReg() const { return valueReg(); }
|
||||
bool hasVolatileReg() const { return value_.volatile_(); }
|
||||
constexpr bool operator==(const ValueOperand& o) const {
|
||||
return value_ == o.value_;
|
||||
}
|
||||
|
|
|
@ -1773,6 +1773,36 @@ bool WarpCacheIRTranspiler::emitArrayPush(ObjOperandId objId,
|
|||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitPackedArrayPopResult(ObjOperandId arrayId) {
|
||||
MDefinition* array = getOperand(arrayId);
|
||||
|
||||
// TODO(Warp): these flags only make sense for the Ion implementation. Remove
|
||||
// them when IonBuilder is gone.
|
||||
bool needsHoleCheck = true;
|
||||
bool maybeUndefined = true;
|
||||
auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Pop,
|
||||
needsHoleCheck, maybeUndefined);
|
||||
addEffectful(ins);
|
||||
|
||||
pushResult(ins);
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitPackedArrayShiftResult(ObjOperandId arrayId) {
|
||||
MDefinition* array = getOperand(arrayId);
|
||||
|
||||
// TODO(Warp): these flags only make sense for the Ion implementation. Remove
|
||||
// them when IonBuilder is gone.
|
||||
bool needsHoleCheck = true;
|
||||
bool maybeUndefined = true;
|
||||
auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Shift,
|
||||
needsHoleCheck, maybeUndefined);
|
||||
addEffectful(ins);
|
||||
|
||||
pushResult(ins);
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitHasClassResult(ObjOperandId objId,
|
||||
uint32_t claspOffset) {
|
||||
MDefinition* obj = getOperand(objId);
|
||||
|
|
|
@ -473,7 +473,6 @@ case "$target" in
|
|||
;;
|
||||
|
||||
*-android*|*-linuxandroid*)
|
||||
MOZ_GFX_OPTIMIZE_MOBILE=1
|
||||
MOZ_OPTIMIZE_FLAGS="-O3"
|
||||
if test -z "$CLANG_CC"; then
|
||||
MOZ_OPTIMIZE_FLAGS="-freorder-blocks -fno-reorder-functions $MOZ_OPTIMIZE_FLAGS"
|
||||
|
|
|
@ -2661,30 +2661,35 @@ bool js::PreventExtensions(JSContext* cx, HandleObject obj,
|
|||
// If the following assertion fails, there's somewhere else a missing
|
||||
// call to shrinkCapacityToInitializedLength() which needs to be found
|
||||
// and fixed.
|
||||
MOZ_ASSERT_IF(obj->isNative(),
|
||||
MOZ_ASSERT_IF(obj->is<NativeObject>(),
|
||||
obj->as<NativeObject>().getDenseInitializedLength() ==
|
||||
obj->as<NativeObject>().getDenseCapacity());
|
||||
|
||||
return result.succeed();
|
||||
}
|
||||
|
||||
if (obj->isNative()) {
|
||||
if (obj->is<NativeObject>()) {
|
||||
// Force lazy properties to be resolved.
|
||||
if (!ResolveLazyProperties(cx, obj.as<NativeObject>())) {
|
||||
HandleNativeObject nobj = obj.as<NativeObject>();
|
||||
if (!ResolveLazyProperties(cx, nobj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare the elements. We have to do this before we mark the object
|
||||
// non-extensible; that's fine because these changes are not observable.
|
||||
if (!ObjectElements::PreventExtensions(cx, &obj->as<NativeObject>())) {
|
||||
if (!ObjectElements::PrepareForPreventExtensions(cx, nobj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, set the NOT_EXTENSIBLE flag on the BaseShape and ObjectElements.
|
||||
if (!JSObject::setFlags(cx, obj, BaseShape::NOT_EXTENSIBLE,
|
||||
JSObject::GENERATE_SHAPE)) {
|
||||
return false;
|
||||
}
|
||||
if (obj->is<NativeObject>()) {
|
||||
ObjectElements::PreventExtensions(&obj->as<NativeObject>());
|
||||
}
|
||||
|
||||
return result.succeed();
|
||||
}
|
||||
|
@ -3553,10 +3558,13 @@ void JSObject::dump(js::GenericPrinter& out) const {
|
|||
if (!nobj->denseElementsArePacked()) {
|
||||
out.put(" non_packed_elements");
|
||||
}
|
||||
if (nobj->denseElementsAreSealed()) {
|
||||
if (nobj->getElementsHeader()->isNotExtensible()) {
|
||||
out.put(" not_extensible");
|
||||
}
|
||||
if (nobj->getElementsHeader()->isSealed()) {
|
||||
out.put(" sealed_elements");
|
||||
}
|
||||
if (nobj->denseElementsAreFrozen()) {
|
||||
if (nobj->getElementsHeader()->isFrozen()) {
|
||||
out.put(" frozen_elements");
|
||||
}
|
||||
if (nobj->getElementsHeader()->maybeInIteration()) {
|
||||
|
|
|
@ -294,20 +294,6 @@ inline void NativeObject::moveDenseElements(uint32_t dstStart,
|
|||
}
|
||||
}
|
||||
|
||||
inline void NativeObject::moveDenseElementsNoPreBarrier(uint32_t dstStart,
|
||||
uint32_t srcStart,
|
||||
uint32_t count) {
|
||||
MOZ_ASSERT(!zone()->needsIncrementalBarrier());
|
||||
|
||||
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
|
||||
MOZ_ASSERT(srcStart + count <= getDenseCapacity());
|
||||
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
|
||||
MOZ_ASSERT(isExtensible());
|
||||
|
||||
memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot));
|
||||
elementsRangeWriteBarrierPost(dstStart, count);
|
||||
}
|
||||
|
||||
inline void NativeObject::reverseDenseElementsNoPreBarrier(uint32_t length) {
|
||||
MOZ_ASSERT(!zone()->needsIncrementalBarrier());
|
||||
|
||||
|
@ -615,11 +601,18 @@ inline js::gc::AllocKind NativeObject::allocKindForTenure() const {
|
|||
|
||||
inline js::GlobalObject& NativeObject::global() const { return nonCCWGlobal(); }
|
||||
|
||||
inline bool NativeObject::denseElementsMaybeInIteration() {
|
||||
inline bool NativeObject::denseElementsHaveMaybeInIterationFlag() {
|
||||
if (!getElementsHeader()->maybeInIteration()) {
|
||||
AssertDenseElementsNotIterated(this);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool NativeObject::denseElementsMaybeInIteration() {
|
||||
if (!denseElementsHaveMaybeInIterationFlag()) {
|
||||
return false;
|
||||
}
|
||||
return ObjectRealm::get(this).objectMaybeInIteration(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,8 @@ bool ObjectElements::MakeElementsCopyOnWrite(JSContext* cx, NativeObject* obj) {
|
|||
}
|
||||
|
||||
/* static */
|
||||
bool ObjectElements::PreventExtensions(JSContext* cx, NativeObject* obj) {
|
||||
bool ObjectElements::PrepareForPreventExtensions(JSContext* cx,
|
||||
NativeObject* obj) {
|
||||
if (!obj->maybeCopyElementsForWrite(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -145,6 +146,18 @@ bool ObjectElements::PreventExtensions(JSContext* cx, NativeObject* obj) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void ObjectElements::PreventExtensions(NativeObject* obj) {
|
||||
MOZ_ASSERT(!obj->denseElementsAreCopyOnWrite());
|
||||
MOZ_ASSERT(!obj->isExtensible());
|
||||
MOZ_ASSERT(obj->getElementsHeader()->numShiftedElements() == 0);
|
||||
MOZ_ASSERT(obj->getDenseInitializedLength() == obj->getDenseCapacity());
|
||||
|
||||
if (!obj->hasEmptyElements()) {
|
||||
obj->getElementsHeader()->setNotExtensible();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ObjectElements::FreezeOrSeal(JSContext* cx, HandleNativeObject obj,
|
||||
IntegrityLevel level) {
|
||||
|
|
|
@ -200,9 +200,14 @@ class ObjectElements {
|
|||
// is created and never changed.
|
||||
SHARED_MEMORY = 0x8,
|
||||
|
||||
// These elements are set to integrity level "sealed". This flag should
|
||||
// only be set on non-extensible objects.
|
||||
SEALED = 0x10,
|
||||
// These elements are not extensible. If this flag is set, the object's
|
||||
// BaseShape must also have the NOT_EXTENSIBLE flag. This exists on
|
||||
// ObjectElements in addition to BaseShape to simplify JIT code.
|
||||
NOT_EXTENSIBLE = 0x10,
|
||||
|
||||
// These elements are set to integrity level "sealed". If this flag is
|
||||
// set, the NOT_EXTENSIBLE flag must be set as well.
|
||||
SEALED = 0x20,
|
||||
|
||||
// These elements are set to integrity level "frozen". If this flag is
|
||||
// set, the SEALED flag must be set as well.
|
||||
|
@ -211,17 +216,17 @@ class ObjectElements {
|
|||
// The BaseShape flag ensures a shape guard can be used to guard against
|
||||
// frozen elements. The ObjectElements flag is convenient for JIT code and
|
||||
// ObjectElements assertions.
|
||||
FROZEN = 0x20,
|
||||
FROZEN = 0x40,
|
||||
|
||||
// If this flag is not set, the elements are guaranteed to contain no hole
|
||||
// values (the JS_ELEMENTS_HOLE MagicValue) in [0, initializedLength).
|
||||
NON_PACKED = 0x40,
|
||||
NON_PACKED = 0x80,
|
||||
|
||||
// If this flag is not set, there's definitely no for-in iterator that
|
||||
// covers these dense elements so elements can be deleted without calling
|
||||
// SuppressDeletedProperty. This is used by fast paths for various Array
|
||||
// builtins. See also NativeObject::denseElementsMaybeInIteration.
|
||||
MAYBE_IN_ITERATION = 0x80,
|
||||
MAYBE_IN_ITERATION = 0x100,
|
||||
};
|
||||
|
||||
// The flags word stores both the flags and the number of shifted elements.
|
||||
|
@ -295,8 +300,8 @@ class ObjectElements {
|
|||
void addShiftedElements(uint32_t count) {
|
||||
MOZ_ASSERT(count < capacity);
|
||||
MOZ_ASSERT(count < initializedLength);
|
||||
MOZ_ASSERT(!(flags &
|
||||
(NONWRITABLE_ARRAY_LENGTH | SEALED | FROZEN | COPY_ON_WRITE)));
|
||||
MOZ_ASSERT(!(flags & (NONWRITABLE_ARRAY_LENGTH | NOT_EXTENSIBLE | SEALED |
|
||||
FROZEN | COPY_ON_WRITE)));
|
||||
uint32_t numShifted = numShiftedElements() + count;
|
||||
MOZ_ASSERT(numShifted <= MaxShiftedElements);
|
||||
flags = (numShifted << NumShiftedElementsShift) | (flags & FlagsMask);
|
||||
|
@ -305,8 +310,8 @@ class ObjectElements {
|
|||
}
|
||||
void unshiftShiftedElements(uint32_t count) {
|
||||
MOZ_ASSERT(count > 0);
|
||||
MOZ_ASSERT(!(flags &
|
||||
(NONWRITABLE_ARRAY_LENGTH | SEALED | FROZEN | COPY_ON_WRITE)));
|
||||
MOZ_ASSERT(!(flags & (NONWRITABLE_ARRAY_LENGTH | NOT_EXTENSIBLE | SEALED |
|
||||
FROZEN | COPY_ON_WRITE)));
|
||||
uint32_t numShifted = numShiftedElements();
|
||||
MOZ_ASSERT(count <= numShifted);
|
||||
numShifted -= count;
|
||||
|
@ -324,13 +329,21 @@ class ObjectElements {
|
|||
void markMaybeInIteration() { flags |= MAYBE_IN_ITERATION; }
|
||||
bool maybeInIteration() { return flags & MAYBE_IN_ITERATION; }
|
||||
|
||||
void setNotExtensible() {
|
||||
MOZ_ASSERT(!isNotExtensible());
|
||||
flags |= NOT_EXTENSIBLE;
|
||||
}
|
||||
bool isNotExtensible() { return flags & NOT_EXTENSIBLE; }
|
||||
|
||||
void seal() {
|
||||
MOZ_ASSERT(isNotExtensible());
|
||||
MOZ_ASSERT(!isSealed());
|
||||
MOZ_ASSERT(!isFrozen());
|
||||
MOZ_ASSERT(!isCopyOnWrite());
|
||||
flags |= SEALED;
|
||||
}
|
||||
void freeze() {
|
||||
MOZ_ASSERT(isNotExtensible());
|
||||
MOZ_ASSERT(isSealed());
|
||||
MOZ_ASSERT(!isFrozen());
|
||||
MOZ_ASSERT(!isCopyOnWrite());
|
||||
|
@ -390,7 +403,9 @@ class ObjectElements {
|
|||
static void ConvertElementsToDoubles(JSContext* cx, uintptr_t elements);
|
||||
static bool MakeElementsCopyOnWrite(JSContext* cx, NativeObject* obj);
|
||||
|
||||
static MOZ_MUST_USE bool PreventExtensions(JSContext* cx, NativeObject* obj);
|
||||
static MOZ_MUST_USE bool PrepareForPreventExtensions(JSContext* cx,
|
||||
NativeObject* obj);
|
||||
static void PreventExtensions(NativeObject* obj);
|
||||
static MOZ_MUST_USE bool FreezeOrSeal(JSContext* cx, HandleNativeObject obj,
|
||||
IntegrityLevel level);
|
||||
|
||||
|
@ -410,8 +425,9 @@ class ObjectElements {
|
|||
|
||||
uint32_t numShiftedElements() const {
|
||||
uint32_t numShifted = flags >> NumShiftedElementsShift;
|
||||
MOZ_ASSERT_IF(numShifted > 0, !(flags & (NONWRITABLE_ARRAY_LENGTH | SEALED |
|
||||
FROZEN | COPY_ON_WRITE)));
|
||||
MOZ_ASSERT_IF(numShifted > 0,
|
||||
!(flags & (NONWRITABLE_ARRAY_LENGTH | NOT_EXTENSIBLE |
|
||||
SEALED | FROZEN | COPY_ON_WRITE)));
|
||||
return numShifted;
|
||||
}
|
||||
|
||||
|
@ -1314,8 +1330,6 @@ class NativeObject : public JSObject {
|
|||
uint32_t srcStart, uint32_t count);
|
||||
inline void moveDenseElements(uint32_t dstStart, uint32_t srcStart,
|
||||
uint32_t count);
|
||||
inline void moveDenseElementsNoPreBarrier(uint32_t dstStart,
|
||||
uint32_t srcStart, uint32_t count);
|
||||
inline void reverseDenseElementsNoPreBarrier(uint32_t length);
|
||||
|
||||
inline DenseElementResult setOrExtendDenseElements(
|
||||
|
@ -1360,6 +1374,7 @@ class NativeObject : public JSObject {
|
|||
// Note that it's fine to return false if this object is on the prototype of
|
||||
// another object: SuppressDeletedProperty only suppresses properties deleted
|
||||
// from the iterated object itself.
|
||||
inline bool denseElementsHaveMaybeInIterationFlag();
|
||||
inline bool denseElementsMaybeInIteration();
|
||||
|
||||
// Ensures that the object can hold at least index + extra elements. This
|
||||
|
|
|
@ -281,7 +281,7 @@ bool mozJSSubScriptLoader::ReadScript(JS::MutableHandle<JSScript*> script,
|
|||
int64_t len = -1;
|
||||
|
||||
rv = chan->GetContentLength(&len);
|
||||
if (NS_FAILED(rv) || len == -1) {
|
||||
if (NS_FAILED(rv)) {
|
||||
ReportError(cx, LOAD_ERROR_NOCONTENT, uri);
|
||||
return false;
|
||||
}
|
||||
|
@ -295,6 +295,21 @@ bool mozJSSubScriptLoader::ReadScript(JS::MutableHandle<JSScript*> script,
|
|||
rv = NS_ReadInputStreamToString(instream, buf, len);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
if (len < 0) {
|
||||
len = buf.Length();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int64_t currentLength = -1;
|
||||
// if getting content length succeeded above, it should not fail now
|
||||
MOZ_ASSERT(chan->GetContentLength(¤tLength) == NS_OK);
|
||||
// if content length was not known when GetContentLength() was called before,
|
||||
// 'len' would be set to -1 until NS_ReadInputStreamToString() set its correct
|
||||
// value. Every subsequent call to GetContentLength() should return the same
|
||||
// length as that value.
|
||||
MOZ_ASSERT(currentLength == len);
|
||||
#endif
|
||||
|
||||
Maybe<JSAutoRealm> ar;
|
||||
|
||||
// Note that when using the ScriptPreloader cache with loadSubScript, there
|
||||
|
|
|
@ -2556,12 +2556,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
|
|||
auto inlineAxisAlignment =
|
||||
isOrthogonal ? stylePos->UsedAlignSelf(GetParent()->Style())._0
|
||||
: stylePos->UsedJustifySelf(GetParent()->Style())._0;
|
||||
// Note: 'normal' means 'start' for elements with an intrinsic size
|
||||
// or ratio in the relevant dimension, otherwise 'stretch'.
|
||||
// https://drafts.csswg.org/css-grid/#grid-item-sizing
|
||||
if ((inlineAxisAlignment == StyleAlignFlags::NORMAL &&
|
||||
!hasIntrinsicISize && !logicalRatio) ||
|
||||
inlineAxisAlignment == StyleAlignFlags::STRETCH) {
|
||||
if (inlineAxisAlignment == StyleAlignFlags::STRETCH) {
|
||||
stretchI = eStretch;
|
||||
}
|
||||
}
|
||||
|
@ -2624,12 +2619,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
|
|||
auto blockAxisAlignment =
|
||||
!isOrthogonal ? stylePos->UsedAlignSelf(GetParent()->Style())._0
|
||||
: stylePos->UsedJustifySelf(GetParent()->Style())._0;
|
||||
// Note: 'normal' means 'start' for elements with an intrinsic size
|
||||
// or ratio in the relevant dimension, otherwise 'stretch'.
|
||||
// https://drafts.csswg.org/css-grid/#grid-item-sizing
|
||||
if ((blockAxisAlignment == StyleAlignFlags::NORMAL &&
|
||||
!hasIntrinsicBSize && !logicalRatio) ||
|
||||
blockAxisAlignment == StyleAlignFlags::STRETCH) {
|
||||
if (blockAxisAlignment == StyleAlignFlags::STRETCH) {
|
||||
stretchB = eStretch;
|
||||
}
|
||||
}
|
||||
|
@ -2717,33 +2707,31 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
|
|||
stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
|
||||
}
|
||||
|
||||
if (logicalRatio) {
|
||||
if (stretchI == eStretch) {
|
||||
tentISize = iSize; // * / 'stretch'
|
||||
if (stretchB == eStretch) {
|
||||
tentBSize = bSize; // 'stretch' / 'stretch'
|
||||
} else if (stretchB == eStretchPreservingRatio) {
|
||||
// 'normal' / 'stretch'
|
||||
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
|
||||
}
|
||||
} else if (stretchB == eStretch) {
|
||||
tentBSize = bSize; // 'stretch' / * (except 'stretch')
|
||||
if (stretchI == eStretchPreservingRatio) {
|
||||
// 'stretch' / 'normal'
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
}
|
||||
} else if (stretchI == eStretchPreservingRatio) {
|
||||
tentISize = iSize; // * (except 'stretch') / 'normal'
|
||||
if (stretchI == eStretch) {
|
||||
tentISize = iSize; // * / 'stretch'
|
||||
if (stretchB == eStretch) {
|
||||
tentBSize = bSize; // 'stretch' / 'stretch'
|
||||
} else if (stretchB == eStretchPreservingRatio && logicalRatio) {
|
||||
// 'normal' / 'stretch'
|
||||
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
|
||||
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
|
||||
// Stretch within the CB size with preserved intrinsic ratio.
|
||||
tentBSize = bSize; // 'normal' / 'normal'
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
}
|
||||
} else if (stretchB == eStretchPreservingRatio) {
|
||||
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
|
||||
}
|
||||
} else if (stretchB == eStretch) {
|
||||
tentBSize = bSize; // 'stretch' / * (except 'stretch')
|
||||
if (stretchI == eStretchPreservingRatio && logicalRatio) {
|
||||
// 'stretch' / 'normal'
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
}
|
||||
} else if (stretchI == eStretchPreservingRatio && logicalRatio) {
|
||||
tentISize = iSize; // * (except 'stretch') / 'normal'
|
||||
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
|
||||
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
|
||||
// Stretch within the CB size with preserved intrinsic ratio.
|
||||
tentBSize = bSize; // 'normal' / 'normal'
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
}
|
||||
} else if (stretchB == eStretchPreservingRatio && logicalRatio) {
|
||||
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
|
||||
tentISize = logicalRatio.ApplyTo(bSize);
|
||||
}
|
||||
|
||||
// ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when
|
||||
|
|
|
@ -206,6 +206,21 @@ nsresult nsPrintObject::InitAsRootObject(nsIDocShell* aDocShell, Document* aDoc,
|
|||
mozilla::Unused << nsDocShell::Cast(mDocShell)->GetDocument();
|
||||
}
|
||||
|
||||
// If we are cloning from a document in a different BrowsingContext, we need
|
||||
// to make sure to copy over our opener policy information from that
|
||||
// BrowsingContext.
|
||||
BrowsingContext* targetBC = mDocShell->GetBrowsingContext();
|
||||
BrowsingContext* sourceBC = aDoc->GetBrowsingContext();
|
||||
NS_ENSURE_STATE(sourceBC);
|
||||
if (targetBC != sourceBC) {
|
||||
MOZ_ASSERT(targetBC->IsTopContent());
|
||||
// In the case where the source is an iframe, this information needs to be
|
||||
// copied from the toplevel source BrowsingContext, as we may be making a
|
||||
// static clone of a single subframe.
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
targetBC->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()));
|
||||
}
|
||||
|
||||
mDocument = aDoc->CreateStaticClone(mDocShell);
|
||||
NS_ENSURE_STATE(mDocument);
|
||||
mHasSelection = CachePrintSelectionRanges(*aDoc, *mDocument);
|
||||
|
|
|
@ -88,7 +88,8 @@ if CONFIG['CPU_ARCH'] in ('x86', 'x86_64'):
|
|||
'../../../third_party/dav1d/src/x86/itx.asm',
|
||||
'../../../third_party/dav1d/src/x86/loopfilter.asm',
|
||||
'../../../third_party/dav1d/src/x86/looprestoration.asm',
|
||||
'../../../third_party/dav1d/src/x86/mc.asm',
|
||||
'../../../third_party/dav1d/src/x86/mc_avx2.asm',
|
||||
'../../../third_party/dav1d/src/x86/mc_avx512.asm',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
|
|
@ -20,11 +20,11 @@ origin:
|
|||
|
||||
# Human-readable identifier for this version/release
|
||||
# Generally "version NNN", "tag SSS", "bookmark SSS"
|
||||
release: commit be1fe18e2f2e6802bf696bc5cbddfd24fb2bc748 (2020-06-25T02:34:01.000+02:00).
|
||||
release: commit 6cf58c8e7deb54e287afeee6710b2a3774eded9c (2020-07-20T15:40:01.000+02:00).
|
||||
|
||||
# Revision to pull in
|
||||
# Must be a long or short commit SHA (long preferred)
|
||||
revision: be1fe18e2f2e6802bf696bc5cbddfd24fb2bc748
|
||||
revision: 6cf58c8e7deb54e287afeee6710b2a3774eded9c
|
||||
|
||||
# The package's license, where possible using the mnemonic from
|
||||
# https://spdx.org/licenses/
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
/* auto-generated, do not edit */
|
||||
#define DAV1D_VERSION "0.7.1-9-gbe1fe18"
|
||||
#define DAV1D_VERSION "0.7.1-36-g6cf58c8"
|
||||
|
|
|
@ -555,6 +555,12 @@ WebrtcTCPSocket::OnTransportAvailable(nsISocketTransport* aTransport,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebrtcTCPSocket::OnWebSocketConnectionAvailable(
|
||||
nsIWebSocketConnection* aConnection) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void WebrtcTCPSocket::FinishOpen() {
|
||||
MOZ_ASSERT(OnSocketThread());
|
||||
// mTransport, mSocketIn, and mSocketOut are all set. We may have set them in
|
||||
|
|
|
@ -9633,6 +9633,11 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: webgl.enable-debug-renderer-info
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: webgl.enable-draft-extensions
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
|
|
|
@ -3775,7 +3775,6 @@ pref("image.http.accept", "");
|
|||
// Allows image locking of decoded image data in content processes.
|
||||
pref("image.mem.allow_locking_in_content_processes", true);
|
||||
|
||||
pref("webgl.enable-debug-renderer-info", true);
|
||||
pref("webgl.renderer-string-override", "");
|
||||
pref("webgl.vendor-string-override", "");
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "HttpTransactionChild.h"
|
||||
#include "AltSvcTransactionChild.h"
|
||||
#include "EventTokenBucket.h"
|
||||
#include "mozilla/net/WebSocketConnectionChild.h"
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
#include "nsHttpConnectionMgr.h"
|
||||
#include "nsHttpHandler.h"
|
||||
|
@ -177,5 +178,25 @@ mozilla::ipc::IPCResult HttpConnectionMgrChild::RecvSpeculativeConnect(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<PWebSocketConnectionChild>
|
||||
HttpConnectionMgrChild::AllocPWebSocketConnectionChild(
|
||||
PHttpTransactionChild* aTransWithStickyConn) {
|
||||
RefPtr<WebSocketConnectionChild> actor = new WebSocketConnectionChild();
|
||||
return actor.forget();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
HttpConnectionMgrChild::RecvPWebSocketConnectionConstructor(
|
||||
PWebSocketConnectionChild* aActor,
|
||||
PHttpTransactionChild* aTransWithStickyConn) {
|
||||
RefPtr<WebSocketConnectionChild> child =
|
||||
static_cast<WebSocketConnectionChild*>(aActor);
|
||||
nsCOMPtr<nsIHttpUpgradeListener> listener =
|
||||
static_cast<nsIHttpUpgradeListener*>(child.get());
|
||||
Unused << mConnMgr->CompleteUpgrade(
|
||||
ToRealHttpTransaction(aTransWithStickyConn), listener);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -41,6 +41,12 @@ class HttpConnectionMgrChild final : public PHttpConnectionMgrChild {
|
|||
Maybe<SpeculativeConnectionOverriderArgs> aOverriderArgs, uint32_t aCaps,
|
||||
Maybe<PAltSvcTransactionChild*> aTrans);
|
||||
|
||||
already_AddRefed<PWebSocketConnectionChild> AllocPWebSocketConnectionChild(
|
||||
PHttpTransactionChild* aTransWithStickyConn);
|
||||
mozilla::ipc::IPCResult RecvPWebSocketConnectionConstructor(
|
||||
PWebSocketConnectionChild* aActor,
|
||||
PHttpTransactionChild* aTransWithStickyConn) override;
|
||||
|
||||
private:
|
||||
virtual ~HttpConnectionMgrChild();
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "HttpConnectionMgrParent.h"
|
||||
#include "AltSvcTransactionParent.h"
|
||||
#include "mozilla/net/HttpTransactionParent.h"
|
||||
#include "mozilla/net/WebSocketConnectionParent.h"
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
|
@ -252,8 +253,13 @@ nsresult HttpConnectionMgrParent::ClearConnectionHistory() {
|
|||
|
||||
nsresult HttpConnectionMgrParent::CompleteUpgrade(
|
||||
HttpTransactionShell* aTrans, nsIHttpUpgradeListener* aUpgradeListener) {
|
||||
// TODO: fix this in bug 1497249
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
MOZ_ASSERT(aTrans->AsHttpTransactionParent());
|
||||
|
||||
RefPtr<WebSocketConnectionParent> wsConnParent =
|
||||
new WebSocketConnectionParent(aUpgradeListener);
|
||||
Unused << SendPWebSocketConnectionConstructor(
|
||||
wsConnParent, aTrans->AsHttpTransactionParent());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsHttpConnectionMgr* HttpConnectionMgrParent::AsHttpConnectionMgr() {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
include protocol PAltSvcTransaction;
|
||||
include protocol PSocketProcess;
|
||||
include protocol PHttpTransaction;
|
||||
include protocol PWebSocketConnection;
|
||||
|
||||
include NeckoChannelParams;
|
||||
|
||||
|
@ -17,6 +18,7 @@ namespace net {
|
|||
async refcounted protocol PHttpConnectionMgr
|
||||
{
|
||||
manager PSocketProcess;
|
||||
manages PWebSocketConnection;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
@ -33,6 +35,7 @@ child:
|
|||
async SpeculativeConnect(HttpConnectionInfoCloneArgs aConnInfo,
|
||||
SpeculativeConnectionOverriderArgs? aOverriderArgs,
|
||||
uint32_t aCaps, PAltSvcTransaction? aTrans);
|
||||
async PWebSocketConnection(PHttpTransaction aTransWithStickyConn);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -7956,6 +7956,13 @@ nsresult nsHttpChannel::ContinueOnStopRequestAfterAuthRetry(
|
|||
mResponseHead->Status() == 200;
|
||||
|
||||
if (upgradeWebsocket || upgradeConnect) {
|
||||
// TODO: Support connection upgrade for socket process in bug 1632809.
|
||||
if (nsIOService::UseSocketProcess() && upgradeConnect) {
|
||||
Unused << mUpgradeProtocolCallback->OnUpgradeFailed(
|
||||
NS_ERROR_NOT_IMPLEMENTED);
|
||||
return ContinueOnStopRequest(aStatus, aIsFromNet, aContentComplete);
|
||||
}
|
||||
|
||||
nsresult rv = gHttpHandler->CompleteUpgrade(aTransWithStickyConn,
|
||||
mUpgradeProtocolCallback);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче