Merge autoland to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2017-06-01 11:54:08 -04:00
Родитель 5c64ad5e40 32d247eb90
Коммит 4ed4898e21
67 изменённых файлов: 2603 добавлений и 880 удалений

Просмотреть файл

@ -15,8 +15,10 @@ async function calcMaximumAvailSize(aChromeWidth, aChromeHeight) {
// If the chrome UI dimensions is not given, we will calculate it.
if (!aChromeWidth || !aChromeHeight) {
let win = await BrowserTestUtils.openNewBrowserWindow();
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, testPath + "file_dummy.html");
win.gBrowser, testPath + "file_dummy.html");
let contentSize = await ContentTask.spawn(tab.linkedBrowser, null, async function() {
let result = {
@ -29,10 +31,11 @@ async function calcMaximumAvailSize(aChromeWidth, aChromeHeight) {
// Calculate the maximum available window size which is depending on the
// available screen space.
chromeUIWidth = window.outerWidth - contentSize.width;
chromeUIHeight = window.outerHeight - contentSize.height;
chromeUIWidth = win.outerWidth - contentSize.width;
chromeUIHeight = win.outerHeight - contentSize.height;
await BrowserTestUtils.removeTab(tab);
await BrowserTestUtils.closeWindow(win);
} else {
chromeUIWidth = aChromeWidth;
chromeUIHeight = aChromeHeight;

Просмотреть файл

@ -41,6 +41,16 @@ add_UITour_task(async function test_block_target() {
async function checkToggleTarget(targetID) {
let popup = document.getElementById("UITourTooltip");
let trackerOpened = new Promise(function(resolve, reject) {
Services.obs.addObserver(function onopen(subject) {
let asciiSpec = subject.QueryInterface(Ci.nsIHttpChannel).URI.asciiSpec;
if (asciiSpec === "https://tracking.example.com/") {
Services.obs.removeObserver(onopen, "http-on-opening-request");
resolve();
}
}, "http-on-opening-request");
});
await ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
let doc = content.document;
let iframe = doc.createElement("iframe");
@ -49,6 +59,8 @@ async function checkToggleTarget(targetID) {
doc.body.insertBefore(iframe, doc.body.firstChild);
});
await trackerOpened;
let testTargetAvailability = async function(expectedAvailable) {
let data = await getConfigurationPromise("availableTargets");
let available = (data.targets.indexOf(targetID) != -1);

Просмотреть файл

@ -8,4 +8,6 @@ DIRS += ['communicator']
JAR_MANIFESTS += ['jar.mn']
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
include('../tab-svgs.mozbuild')

Просмотреть файл

@ -6,7 +6,6 @@
%include shared.inc
%define toolbarButtonPressed :hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"])
%define windowButtonMarginTop 11px
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
@ -15,7 +14,6 @@
%include ../shared/browser.inc.css
:root {
--space-above-tabbar: 9px;
--tabs-toolbar-color: #333;
--toolbarbutton-vertical-text-padding: calc(var(--toolbarbutton-inner-padding) + 1px);
@ -23,6 +21,8 @@
%ifdef MOZ_PHOTON_THEME
--toolbarbutton-border-radius: 4px;
%else
--space-above-tabbar: 9px;
--toolbarbutton-border-radius: 3px;
--toolbarbutton-hover-background: hsla(0,0%,100%,.1) linear-gradient(hsla(0,0%,100%,.3), hsla(0,0%,100%,.1)) padding-box;
@ -134,7 +134,11 @@ toolbar:-moz-lwtheme {
* tabstrip can overlap it.
*/
#main-window[tabsintitlebar] > #titlebar {
%ifndef MOZ_PHOTON_THEME
min-height: calc(var(--tab-min-height) + var(--space-above-tabbar) - var(--tab-toolbar-navbar-overlap));
%else
min-height: calc(var(--tab-min-height) - var(--tab-toolbar-navbar-overlap));
%endif
}
/**
@ -146,7 +150,11 @@ toolbar:-moz-lwtheme {
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-buttonbox-container,
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button {
margin-top: @windowButtonMarginTop@;
%ifdef MOZ_PHOTON_THEME
margin-top: 6px;
%else
margin-top: 11px;
%endif
}
#main-window:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-buttonbox-container,
@ -1535,10 +1543,11 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
text-shadow: @loweredShadow@;
}
%ifndef MOZ_PHOTON_THEME
#navigator-toolbox[inFullscreen] > #TabsToolbar {
padding-top: var(--space-above-tabbar);
}
%endif
#tabbrowser-tabs {
-moz-box-align: stretch;
}
@ -2210,7 +2219,9 @@ html|*.addon-webext-perm-list {
}
#TabsToolbar > .private-browsing-indicator {
%ifndef MOZ_PHOTON_THEME
transform: translateY(calc(-1 * var(--space-above-tabbar)));
%endif
/* We offset by 38px for mask graphic, plus 4px to account for the
* margin-left, which sums to 42px.
*/

Просмотреть файл

@ -28,12 +28,13 @@
background: var(--chrome-background-color);
}
%ifndef MOZ_PHOTON_THEME
/* Resize things so that the native titlebar is in line with the tabs */
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-buttonbox-container,
#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button {
margin-top: 6px;
}
%endif
/* Prevent the hover styling from on the identity icon from overlapping the
urlbar border. */
#identity-box {

Просмотреть файл

@ -3,6 +3,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%ifdef MOZ_PHOTON_THEME
%ifdef CAN_DRAW_IN_TITLEBAR
/* Add space for dragging the window */
%ifdef MENUBAR_CAN_AUTOHIDE
:root[tabsintitlebar] #toolbar-menubar[autohide=true] ~ #TabsToolbar {
padding-inline-start: 40px;
}
%else
:root[tabsintitlebar] #TabsToolbar {
padding-inline-start: 40px;
}
%endif
%endif
/* Go button */
.urlbar-go-button {
padding: 0 3px;

Просмотреть файл

@ -9,7 +9,9 @@
:root {
--tab-toolbar-navbar-overlap: 0px;
--navbar-tab-toolbar-highlight-overlap: 0px;
%ifndef MOZ_PHOTON_THEME
--space-above-tabbar: 0px;
%endif
--toolbarbutton-text-shadow: none;
--backbutton-urlbar-overlap: 0px;
/* 18px icon + 2 * 5px padding + 1 * 1px border */
@ -98,12 +100,13 @@ toolbar:-moz-lwtheme-darktext {
--toolbarbutton-checkedhover-backgroundcolor: #d7d7d8;
}
%ifndef MOZ_PHOTON_THEME
/* Give some space to drag the window around while customizing
(normal space to left and right of tabs doesn't work in this case) */
#main-window[tabsintitlebar][customizing] {
--space-above-tabbar: 9px;
}
%endif
/* Override @tabCurveHalfWidth@ and @tabCurveWidth@. XXX: Switch to a CSS variable once the perf is sorted out - bug 1088771 */
.tab-background-middle {
border-left-width: 0;

Просмотреть файл

@ -338,11 +338,12 @@
}
}
%ifndef MOZ_PHOTON_THEME
#main-window[sizemode=normal] #TabsToolbar {
padding-left: 1px;
padding-right: 1px;
}
%endif
#appcontent:not(:-moz-lwtheme) {
background-color: -moz-dialog;
}

Просмотреть файл

@ -17,13 +17,13 @@
:root {
--titlebar-text-color: inherit;
--space-above-tabbar: 15px;
--toolbarbutton-vertical-text-padding: calc(var(--toolbarbutton-inner-padding) - 1px);
%ifdef MOZ_PHOTON_THEME
--toolbarbutton-border-radius: 2px;
%else
--space-above-tabbar: 15px;
--toolbarbutton-border-radius: 1px;
--toolbarbutton-hover-background: rgba(0,0,0,.1);
@ -89,6 +89,7 @@ toolbar[brighttext] {
display: none;
}
%ifndef MOZ_PHOTON_THEME
/* We want a 4px gap between the TabsToolbar and the toolbar-menubar when the
toolbar-menu is displayed, and a 16px gap when it is not. 1px is taken care
of by the (light) outer shadow of the tab, the remaining 3/15 are these margins. */
@ -101,7 +102,7 @@ toolbar[brighttext] {
#main-window[tabsintitlebar][sizemode="normal"]:not([inFullscreen]) #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar {
margin-top: var(--space-above-tabbar);
}
%endif
#navigator-toolbox,
#navigator-toolbox > toolbar {
-moz-appearance: none;

Просмотреть файл

@ -72,10 +72,11 @@
@media (-moz-os-version: windows-win7),
(-moz-os-version: windows-win8) {
%ifndef MOZ_PHOTON_THEME
:root {
--space-above-tabbar: 15px;
}
%endif
/* It'd be nice if there was an element in the scrollbox's inner content
that collapsed to the current width of the tabs. Since there isn't we
need to handle overflowing and non-overflowing tabs separately.

Просмотреть файл

@ -9,5 +9,6 @@ DIRS += ['communicator']
JAR_MANIFESTS += ['jar.mn']
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
include('../tab-svgs.mozbuild')

Просмотреть файл

@ -857,6 +857,9 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
gDevToolsBrowser._forgetBrowserWindow(win);
}
// Remove scripts loaded in content process to support the Browser Content Toolbox.
DebuggerServer.removeContentServerScript();
gDevTools.destroy({ shuttingDown });
},
};

Просмотреть файл

@ -0,0 +1,26 @@
/* 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/. */
/* global addMessageListener, removeMessageListener */
"use strict";
const { utils: Cu } = Components;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
function onInit(message) {
// Only reply if we are in a real content process
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
let {init} = Cu.import("resource://devtools/server/content-server.jsm", {});
init(message);
}
}
function onClose() {
removeMessageListener("debug:init-content-server", onInit);
removeMessageListener("debug:close-content-server", onClose);
}
addMessageListener("debug:init-content-server", onInit);
addMessageListener("debug:close-content-server", onClose);

Просмотреть файл

@ -69,6 +69,9 @@ if (isWorker) {
Services.prefs.getBoolPref(VERBOSE_PREF);
}
const CONTENT_PROCESS_DBG_SERVER_SCRIPT =
"resource://devtools/server/content-process-debugger-server.js";
function loadSubScript(url) {
try {
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
@ -149,6 +152,8 @@ function ModuleAPI() {
var DebuggerServer = {
_listeners: [],
_initialized: false,
// Flag to check if the content process debugger server script was already loaded.
_contentProcessScriptLoaded: false,
// Map of global actor names to actor constructors provided by extensions.
globalActorFactories: {},
// Map of tab actor names to actor constructors provided by extensions.
@ -755,7 +760,16 @@ var DebuggerServer = {
deferred.resolve(actor);
});
mm.sendAsyncMessage("DevTools:InitDebuggerServer", {
// Load the content process debugger server script only once.
if (!this._contentProcessScriptLoaded) {
// Load the process script that will receive the debug:init-content-server message
Services.ppmm.loadProcessScript(CONTENT_PROCESS_DBG_SERVER_SCRIPT, true);
this._contentProcessScriptLoaded = true;
}
// Send a message to the content process debugger server script to forward it the
// prefix.
mm.sendAsyncMessage("debug:init-content-server", {
prefix: prefix
});
@ -1368,6 +1382,20 @@ var DebuggerServer = {
}
},
/**
* Called when DevTools are unloaded to remove the contend process server script for the
* list of scripts loaded for each new content process. Will also remove message
* listeners from already loaded scripts.
*/
removeContentServerScript() {
Services.ppmm.removeDelayedProcessScript(CONTENT_PROCESS_DBG_SERVER_SCRIPT);
try {
Services.ppmm.broadcastAsyncMessage("debug:close-content-server");
} catch (e) {
// Nothing to do
}
},
/**
* TESTING ONLY! Searches all active connections for an actor matching an ID.
* This is helpful for some tests which depend on reaching into the server to check some

Просмотреть файл

@ -18,6 +18,7 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
DevToolsModules(
'child.js',
'content-process-debugger-server.js',
'content-server.jsm',
'css-logic.js',
'event-parsers.js',

Просмотреть файл

@ -34,6 +34,11 @@ H264Converter::H264Converter(PlatformDecoderModule* aPDM,
, mDecoderOptions(aParams.mOptions)
{
CreateDecoder(mOriginalConfig, aParams.mDiagnostics);
if (mDecoder) {
MOZ_ASSERT(mp4_demuxer::AnnexB::HasSPS(mOriginalConfig.mExtraData));
// The video metadata contains out of band SPS/PPS (AVC1) store it.
mOriginalExtraData = mOriginalConfig.mExtraData;
}
}
H264Converter::~H264Converter()
@ -79,6 +84,15 @@ H264Converter::Decode(MediaRawData* aSample)
return DecodePromise::CreateAndResolve(DecodedData(), __func__);
}
} else {
// Initialize the members that we couldn't if the extradata was given during
// H264Converter's construction.
if (!mNeedAVCC) {
mNeedAVCC =
Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC);
}
if (!mCanRecycleDecoder) {
mCanRecycleDecoder = Some(CanRecycleDecoder());
}
rv = CheckForSPSChange(aSample);
}
@ -99,11 +113,6 @@ H264Converter::Decode(MediaRawData* aSample)
return DecodePromise::CreateAndResolve(DecodedData(), __func__);
}
if (!mNeedAVCC) {
mNeedAVCC =
Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC);
}
if (!*mNeedAVCC
&& !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
return DecodePromise::CreateAndReject(
@ -260,6 +269,11 @@ H264Converter::OnDecoderInitDone(const TrackType aTrackType)
{
mInitPromiseRequest.Complete();
RefPtr<MediaRawData> sample = mPendingSample.forget();
mNeedAVCC =
Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC);
mCanRecycleDecoder = Some(CanRecycleDecoder());
DecodeFirstSample(sample);
}
@ -289,9 +303,6 @@ H264Converter::DecodeFirstSample(MediaRawData* aSample)
return;
}
mNeedAVCC =
Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC);
if (!*mNeedAVCC
&& !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)) {
mDecodePromise.Reject(
@ -322,15 +333,30 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
{
RefPtr<MediaByteBuffer> extra_data =
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)
|| mp4_demuxer::AnnexB::CompareExtraData(extra_data,
mCurrentConfig.mExtraData)) {
return NS_OK;
}
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
MOZ_ASSERT(mCanRecycleDecoder.isSome());
if (!*mCanRecycleDecoder) {
// If the decoder can't be recycled, the out of band extradata will never
// change as the H264Converter will be recreated by the MediaFormatReader
// instead. So there's no point in testing for changes.
return NS_OK;
}
// This sample doesn't contain inband SPS/PPS
// We now check if the out of band one has changed.
if (mp4_demuxer::AnnexB::HasSPS(aSample->mExtraData) &&
!mp4_demuxer::AnnexB::CompareExtraData(aSample->mExtraData,
mOriginalExtraData)) {
extra_data = mOriginalExtraData = aSample->mExtraData;
}
}
if (mp4_demuxer::AnnexB::CompareExtraData(extra_data,
mCurrentConfig.mExtraData)) {
return NS_OK;
}
RefPtr<MediaRawData> sample = aSample;
if (CanRecycleDecoder()) {
MOZ_ASSERT(mCanRecycleDecoder.isSome());
if (*mCanRecycleDecoder) {
// Do not recreate the decoder, reuse it.
UpdateConfigFromExtraData(extra_data);
if (!sample->mTrackInfo) {

Просмотреть файл

@ -81,6 +81,8 @@ private:
RefPtr<PlatformDecoderModule> mPDM;
const VideoInfo mOriginalConfig;
VideoInfo mCurrentConfig;
// Current out of band extra data (as found in metadata's VideoInfo).
RefPtr<MediaByteBuffer> mOriginalExtraData;
RefPtr<layers::KnowsCompositor> mKnowsCompositor;
RefPtr<layers::ImageContainer> mImageContainer;
const RefPtr<TaskQueue> mTaskQueue;
@ -100,6 +102,7 @@ private:
const TrackInfo::TrackType mType;
MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
const CreateDecoderParams::OptionSet mDecoderOptions;
Maybe<bool> mCanRecycleDecoder;
};
} // namespace mozilla

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/ipc/PChildToParentStreamChild.h"
#include "mozilla/ipc/PParentToChildStreamChild.h"
#include "mozilla/layout/VsyncChild.h"
#include "mozilla/net/HttpBackgroundChannelChild.h"
#include "mozilla/net/PUDPSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "mozilla/dom/WebAuthnTransactionChild.h"
@ -559,6 +560,24 @@ BackgroundChildImpl::DeallocPWebAuthnTransactionChild(PWebAuthnTransactionChild*
return true;
}
net::PHttpBackgroundChannelChild*
BackgroundChildImpl::AllocPHttpBackgroundChannelChild(const uint64_t& aChannelId)
{
MOZ_CRASH("PHttpBackgroundChannelChild actor should be manually constructed!");
return nullptr;
}
bool
BackgroundChildImpl::DeallocPHttpBackgroundChannelChild(PHttpBackgroundChannelChild* aActor)
{
// The reference is increased in BackgroundChannelCreateCallback::ActorCreated
// of HttpBackgroundChannelChild.cpp. We should decrease it after IPC
// destroyed.
RefPtr<net::HttpBackgroundChannelChild> child =
dont_AddRef(static_cast<net::HttpBackgroundChannelChild*>(aActor));
return true;
}
} // namespace ipc
} // namespace mozilla

Просмотреть файл

@ -202,6 +202,12 @@ protected:
virtual bool
DeallocPWebAuthnTransactionChild(PWebAuthnTransactionChild* aActor) override;
virtual PHttpBackgroundChannelChild*
AllocPHttpBackgroundChannelChild(const uint64_t& aChannelId) override;
virtual bool
DeallocPHttpBackgroundChannelChild(PHttpBackgroundChannelChild* aActor) override;
};
class BackgroundChildImpl::ThreadLocal final

Просмотреть файл

@ -37,6 +37,7 @@
#include "mozilla/ipc/PChildToParentStreamParent.h"
#include "mozilla/ipc/PParentToChildStreamParent.h"
#include "mozilla/layout/VsyncParent.h"
#include "mozilla/net/HttpBackgroundChannelParent.h"
#include "mozilla/dom/network/UDPSocketParent.h"
#include "mozilla/dom/WebAuthnTransactionParent.h"
#include "mozilla/Preferences.h"
@ -872,6 +873,53 @@ BackgroundParentImpl::DeallocPWebAuthnTransactionParent(dom::PWebAuthnTransactio
return true;
}
net::PHttpBackgroundChannelParent*
BackgroundParentImpl::AllocPHttpBackgroundChannelParent(const uint64_t& aChannelId)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
RefPtr<net::HttpBackgroundChannelParent> actor =
new net::HttpBackgroundChannelParent();
// hold extra refcount for IPDL
return actor.forget().take();
}
mozilla::ipc::IPCResult
BackgroundParentImpl::RecvPHttpBackgroundChannelConstructor(
net::PHttpBackgroundChannelParent *aActor,
const uint64_t& aChannelId)
{
MOZ_ASSERT(aActor);
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
net::HttpBackgroundChannelParent* aParent =
static_cast<net::HttpBackgroundChannelParent*>(aActor);
if (NS_WARN_IF(NS_FAILED(aParent->Init(aChannelId)))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
bool
BackgroundParentImpl::DeallocPHttpBackgroundChannelParent(
net::PHttpBackgroundChannelParent *aActor)
{
MOZ_ASSERT(aActor);
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
// release extra refcount hold by AllocPHttpBackgroundChannelParent
RefPtr<net::HttpBackgroundChannelParent> actor =
dont_AddRef(static_cast<net::HttpBackgroundChannelParent*>(aActor));
return true;
}
} // namespace ipc
} // namespace mozilla

Просмотреть файл

@ -226,6 +226,15 @@ protected:
virtual bool
DeallocPWebAuthnTransactionParent(PWebAuthnTransactionParent* aActor) override;
virtual PHttpBackgroundChannelParent*
AllocPHttpBackgroundChannelParent(const uint64_t& aChannelId) override;
virtual mozilla::ipc::IPCResult
RecvPHttpBackgroundChannelConstructor(PHttpBackgroundChannelParent *aActor,
const uint64_t& aChannelId) override;
virtual bool
DeallocPHttpBackgroundChannelParent(PHttpBackgroundChannelParent *aActor) override;
};
} // namespace ipc

Просмотреть файл

@ -14,6 +14,7 @@ include protocol PFileDescriptorSet;
include protocol PFileSystemRequest;
include protocol PGamepadEventChannel;
include protocol PGamepadTestChannel;
include protocol PHttpBackgroundChannel;
include protocol PIPCBlobInputStream;
include protocol PPendingIPCBlob;
include protocol PMessagePort;
@ -61,6 +62,7 @@ sync protocol PBackground
manages PFileSystemRequest;
manages PGamepadEventChannel;
manages PGamepadTestChannel;
manages PHttpBackgroundChannel;
manages PIPCBlobInputStream;
manages PPendingIPCBlob;
manages PMessagePort;
@ -115,6 +117,8 @@ parent:
async PGamepadTestChannel();
async PHttpBackgroundChannel(uint64_t channelId);
async PWebAuthnTransaction();
child:

Просмотреть файл

@ -355,15 +355,18 @@ CSSStyleSheet::CSSStyleSheet(const CSSStyleSheet& aCopy,
dom::CSSImportRule* aOwnerRuleToUse,
nsIDocument* aDocumentToUse,
nsINode* aOwningNodeToUse)
: StyleSheet(aCopy, aOwnerRuleToUse, aDocumentToUse, aOwningNodeToUse),
mInRuleProcessorCache(false),
mScopeElement(nullptr),
mRuleProcessors(nullptr)
: StyleSheet(aCopy,
aParentToUse,
aOwnerRuleToUse,
aDocumentToUse,
aOwningNodeToUse)
, mInRuleProcessorCache(false)
, mScopeElement(nullptr)
, mRuleProcessors(nullptr)
{
mParent = aParentToUse;
if (mDirty) { // CSSOM's been there, force full copy now
NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
NS_ASSERTION(mInner->mComplete,
"Why have rules been accessed on an incomplete sheet?");
// FIXME: handle failure?
//
// NOTE: It's important to call this from the subclass, since it could

Просмотреть файл

@ -84,12 +84,15 @@ ServoStyleSheet::ServoStyleSheet(const ServoStyleSheet& aCopy,
dom::CSSImportRule* aOwnerRuleToUse,
nsIDocument* aDocumentToUse,
nsINode* aOwningNodeToUse)
: StyleSheet(aCopy, aOwnerRuleToUse, aDocumentToUse, aOwningNodeToUse)
: StyleSheet(aCopy,
aParentToUse,
aOwnerRuleToUse,
aDocumentToUse,
aOwningNodeToUse)
{
mParent = aParentToUse;
if (mDirty) { // CSSOM's been there, force full copy now
NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
NS_ASSERTION(mInner->mComplete,
"Why have rules been accessed on an incomplete sheet?");
// FIXME: handle failure?
//
// NOTE: It's important to call this from the subclass, since this could

Просмотреть файл

@ -34,10 +34,11 @@ StyleSheet::StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMod
}
StyleSheet::StyleSheet(const StyleSheet& aCopy,
StyleSheet* aParentToUse,
dom::CSSImportRule* aOwnerRuleToUse,
nsIDocument* aDocumentToUse,
nsINode* aOwningNodeToUse)
: mParent(nullptr)
: mParent(aParentToUse)
, mTitle(aCopy.mTitle)
, mDocument(aDocumentToUse)
, mOwningNode(aOwningNodeToUse)
@ -45,8 +46,8 @@ StyleSheet::StyleSheet(const StyleSheet& aCopy,
, mParsingMode(aCopy.mParsingMode)
, mType(aCopy.mType)
, mDisabled(aCopy.mDisabled)
// We only use this constructor during cloning. It's the cloner's
// responsibility to notify us if we end up being owned by a document.
// We only use this constructor during cloning. It's the cloner's
// responsibility to notify us if we end up being owned by a document.
, mDocumentAssociationMode(NotOwnedByDocument)
, mInner(aCopy.mInner) // Shallow copy, but concrete subclasses will fix up.
, mDirty(aCopy.mDirty)

Просмотреть файл

@ -53,6 +53,7 @@ class StyleSheet : public nsIDOMCSSStyleSheet
protected:
StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode);
StyleSheet(const StyleSheet& aCopy,
StyleSheet* aParentToUse,
dom::CSSImportRule* aOwnerRuleToUse,
nsIDocument* aDocumentToUse,
nsINode* aOwningNodeToUse);

Просмотреть файл

@ -277,11 +277,6 @@ AnnexB::ExtractExtraData(const mozilla::MediaRawData* aSample)
MOZ_ASSERT(IsAVCC(aSample));
RefPtr<mozilla::MediaByteBuffer> extradata = new mozilla::MediaByteBuffer;
if (HasSPS(aSample->mExtraData)) {
// We already have an explicit extradata, re-use it.
extradata = aSample->mExtraData;
return extradata.forget();
}
// SPS content
mozilla::Vector<uint8_t> sps;
@ -293,7 +288,20 @@ AnnexB::ExtractExtraData(const mozilla::MediaRawData* aSample)
int numPps = 0;
int nalLenSize = ((*aSample->mExtraData)[4] & 3) + 1;
ByteReader reader(aSample->Data(), aSample->Size());
size_t sampleSize = aSample->Size();
if (aSample->mCrypto.mValid) {
// The content is encrypted, we can only parse the non-encrypted data.
MOZ_ASSERT(aSample->mCrypto.mPlainSizes.Length() > 0);
if (aSample->mCrypto.mPlainSizes.Length() == 0 ||
aSample->mCrypto.mPlainSizes[0] > sampleSize) {
// This is invalid content.
return nullptr;
}
sampleSize = aSample->mCrypto.mPlainSizes[0];
}
ByteReader reader(aSample->Data(), sampleSize);
// Find SPS and PPS NALUs in AVCC data
while (reader.Remaining() > nalLenSize) {
@ -365,47 +373,6 @@ AnnexB::HasSPS(const mozilla::MediaByteBuffer* aExtraData)
return numSps > 0;
}
bool
AnnexB::HasPPS(const mozilla::MediaRawData* aSample)
{
return HasPPS(aSample->mExtraData);
}
bool
AnnexB::HasPPS(const mozilla::MediaByteBuffer* aExtraData)
{
if (!aExtraData) {
return false;
}
ByteReader reader(aExtraData);
const uint8_t* ptr = reader.Read(5);
if (!ptr || !reader.CanRead8()) {
return false;
}
uint8_t numSps = reader.ReadU8() & 0x1f;
// Skip over the included SPS.
for (uint8_t i = 0; i < numSps; i++) {
if (reader.Remaining() < 3) {
return false;
}
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != 7) {
// Not an SPS NAL type.
return false;
}
if (!reader.Read(length)) {
return false;
}
}
if (!reader.CanRead8()) {
return false;
}
uint8_t numPps = reader.ReadU8();
return numPps > 0;
}
bool
AnnexB::ConvertSampleTo4BytesAVCC(mozilla::MediaRawData* aSample)
{

Просмотреть файл

@ -181,27 +181,6 @@ SPSData::SPSData()
memset(scaling_matrix8x8, 16, sizeof(scaling_matrix8x8));
}
PPSData::PPSData()
{
PodZero(this);
memset(scaling_matrix4x4, 16, sizeof(scaling_matrix4x4));
memset(scaling_matrix8x8, 16, sizeof(scaling_matrix8x8));
}
const uint8_t H264::ZZ_SCAN[16] = { 0, 1, 4, 8,
5, 2, 3, 6,
9, 12, 13, 10,
7, 11, 14, 15 };
const uint8_t H264::ZZ_SCAN8[64] = { 0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63 };
/* static */ already_AddRefed<mozilla::MediaByteBuffer>
H264::DecodeNALUnit(const mozilla::MediaByteBuffer* aNAL)
{
@ -606,26 +585,6 @@ H264::vui_parameters(BitReader& aBr, SPSData& aDest)
/* static */ bool
H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSData& aDest)
{
H264ParametersSet ps;
if (!DecodeSPSDataSetFromExtraData(aExtraData, ps.SPSes)) {
return false;
}
uint16_t spsId = 0;
if (DecodePPSDataSetFromExtraData(aExtraData, ps.SPSes, ps.PPSes)) {
// We can't know which PPS is in use without parsing slice header if we
// have multiple PPSes, so we always use the first one.
spsId = ps.PPSes[0].seq_parameter_set_id;
}
aDest = Move(ps.SPSes[spsId]);
return true;
}
/* static */ bool
H264::DecodeSPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSDataSet& aDest)
{
if (!AnnexB::HasSPS(aExtraData)) {
return false;
@ -642,34 +601,31 @@ H264::DecodeSPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
return false;
}
for (uint32_t idx = 0; idx < numSps; idx++) {
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != H264_NAL_SPS) {
// Not a SPS NAL type.
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> sps = DecodeNALUnit(rawNAL);
if (!sps) {
return false;
}
SPSData spsData;
if (!DecodeSPS(sps, spsData)) {
return false;
}
aDest.AppendElement(spsData);
if (numSps > 1) {
NS_WARNING("Multiple SPS, only decoding the first one");
}
return true;
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != H264_NAL_SPS) {
// Not a SPS NAL type.
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> sps = DecodeNALUnit(rawNAL);
if (!sps) {
return false;
}
return DecodeSPS(sps, aDest);
}
/* static */ bool
@ -694,213 +650,6 @@ H264::EnsureSPSIsSane(SPSData& aSPS)
return valid;
}
/* static */ bool
H264::DecodePPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
const SPSDataSet& aSPSes, PPSDataSet& aDest)
{
if (!AnnexB::HasPPS(aExtraData)) {
return false;
}
ByteReader reader(aExtraData);
if (!reader.Read(5)) {
return false;
}
uint8_t numSps = reader.ReadU8() & 0x1f;
if (!numSps) {
// No SPS.
return false;
}
NS_ASSERTION(numSps == 1, "More than one SPS in extradata");
for (uint8_t i = 0; i < numSps; i++) {
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != H264_NAL_SPS) {
// Not a SPS NAL type.
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
}
uint8_t numPps = reader.ReadU8();
if (!numPps) {
// No PPs.
return false;
}
for (uint32_t idx = 0; idx < numPps; idx++) {
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != H264_NAL_PPS) {
// Not a PPS NAL type.
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> pps = DecodeNALUnit(rawNAL);
if (!pps) {
return false;
}
PPSData ppsData;
if (!DecodePPS(pps, aSPSes, ppsData)) {
return false;
}
if (ppsData.pic_parameter_set_id >= aDest.Length()) {
aDest.SetLength(ppsData.pic_parameter_set_id + 1);
}
aDest[ppsData.pic_parameter_set_id] = Move(ppsData);
}
return true;
}
/* static */ bool
H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS, const SPSDataSet& aSPSes,
PPSData& aDest)
{
if (!aPPS) {
return false;
}
if (aSPSes.IsEmpty()) {
return false;
}
BitReader br(aPPS, GetBitLength(aPPS));
READUE(pic_parameter_set_id, MAX_PPS_COUNT - 1);
READUE(seq_parameter_set_id, MAX_SPS_COUNT - 1);
if (aDest.seq_parameter_set_id >= aSPSes.Length()) {
// Invalid SPS id.
return false;
}
const SPSData& sps = aSPSes[aDest.seq_parameter_set_id];
memcpy(aDest.scaling_matrix4x4, sps.scaling_matrix4x4,
sizeof(aDest.scaling_matrix4x4));
memcpy(aDest.scaling_matrix8x8, sps.scaling_matrix8x8,
sizeof(aDest.scaling_matrix8x8));
aDest.entropy_coding_mode_flag = br.ReadBit();
aDest.bottom_field_pic_order_in_frame_present_flag = br.ReadBit();
READUE(num_slice_groups_minus1, 7);
if (aDest.num_slice_groups_minus1 > 0) {
READUE(slice_group_map_type, 6);
switch (aDest.slice_group_map_type) {
case 0:
for (uint8_t iGroup = 0; iGroup <= aDest.num_slice_groups_minus1;
iGroup++) {
aDest.run_length_minus1[iGroup] = br.ReadUE();
}
break;
case 2:
for (uint8_t iGroup = 0; iGroup < aDest.num_slice_groups_minus1;
iGroup++) {
aDest.top_left[iGroup] = br.ReadUE();
aDest.bottom_right[iGroup] = br.ReadUE();
}
break;
case 3:
case 4:
case 5:
aDest.slice_group_change_direction_flag = br.ReadBit();
aDest.slice_group_change_rate_minus1 = br.ReadUE();
break;
case 6:
aDest.pic_size_in_map_units_minus1 = br.ReadUE();
for (uint32_t i = 0; i <= aDest.pic_size_in_map_units_minus1; i++) {
/* slice_group_id[ i ] identifies a slice group of the i-th slice group map
unit in raster scan order. The length of the slice_group_id[i] syntax
element is Ceil(Log2(num_slice_groups_minus1+1)) bits. The value of
slice_group_id[i] shall be in the range of 0 to num_slice_groups_minus1,
inclusive. */
br.ReadBits(std::ceil(std::log2(aDest.num_slice_groups_minus1 + 1)));
}
break;
default:
return false;
}
}
READUE(num_ref_idx_l0_default_active_minus1, 31);
READUE(num_ref_idx_l1_default_active_minus1, 31);
aDest.weighted_pred_flag = br.ReadBit();
aDest.weighted_bipred_idc = br.ReadBits(2);
READSE(pic_init_qp_minus26, -(26 + 6 * sps.bit_depth_luma_minus8), 25);
READSE(pic_init_qs_minus26, -26, 26);
READSE(chroma_qp_index_offset, -12, 12);
aDest.deblocking_filter_control_present_flag = br.ReadBit();
aDest.constrained_intra_pred_flag = br.ReadBit();
aDest.redundant_pic_cnt_present_flag = br.ReadBit();
if (br.BitsLeft()) {
aDest.transform_8x8_mode_flag = br.ReadBit();
if (br.ReadBit()) { // pic_scaling_matrix_present_flag
if (sps.seq_scaling_matrix_present_flag) {
scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra);
scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
aDest.scaling_matrix4x4[0]);
scaling_list(br, aDest.scaling_matrix4x4[2], Default_4x4_Intra,
aDest.scaling_matrix4x4[1]);
scaling_list(br, aDest.scaling_matrix4x4[3], Default_4x4_Inter);
} else {
scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra,
Default_4x4_Intra);
scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
aDest.scaling_matrix4x4[0]);
scaling_list(br, aDest.scaling_matrix4x4[2], Default_4x4_Intra,
aDest.scaling_matrix4x4[1]);
scaling_list(br, aDest.scaling_matrix4x4[3], Default_4x4_Inter,
Default_4x4_Inter);
}
scaling_list(br, aDest.scaling_matrix4x4[4], Default_4x4_Inter,
aDest.scaling_matrix4x4[3]);
scaling_list(br, aDest.scaling_matrix4x4[5], Default_4x4_Inter,
aDest.scaling_matrix4x4[4]);
if (aDest.transform_8x8_mode_flag) {
if (sps.seq_scaling_matrix_present_flag) {
scaling_list(br, aDest.scaling_matrix8x8[0], Default_8x8_Intra);
scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter);
} else {
scaling_list(br, aDest.scaling_matrix8x8[0], Default_8x8_Intra,
Default_8x8_Intra);
scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter,
Default_8x8_Inter);
}
if (sps.chroma_format_idc == 3) {
scaling_list(br, aDest.scaling_matrix8x8[2], Default_8x8_Intra,
aDest.scaling_matrix8x8[0]);
scaling_list(br, aDest.scaling_matrix8x8[3], Default_8x8_Inter,
aDest.scaling_matrix8x8[1]);
scaling_list(br, aDest.scaling_matrix8x8[4], Default_8x8_Intra,
aDest.scaling_matrix8x8[2]);
scaling_list(br, aDest.scaling_matrix8x8[5], Default_8x8_Inter,
aDest.scaling_matrix8x8[3]);
}
}
}
READSE(second_chroma_qp_index_offset, -12, 12);
}
return true;
}
/* static */ bool
H264::DecodeParametersSet(const mozilla::MediaByteBuffer* aExtraData,
H264ParametersSet& aDest)
{
return DecodeSPSDataSetFromExtraData(aExtraData, aDest.SPSes) &&
DecodePPSDataSetFromExtraData(aExtraData, aDest.SPSes, aDest.PPSes);
}
/* static */ uint32_t
H264::ComputeMaxRefFrames(const mozilla::MediaByteBuffer* aExtraData)
{

Просмотреть файл

@ -29,15 +29,12 @@ public:
// Parse an AVCC extradata and construct the Annex B sample header.
static already_AddRefed<mozilla::MediaByteBuffer> ConvertExtraDataToAnnexB(
const mozilla::MediaByteBuffer* aExtraData);
// Extract SPS and PPS NALs from aSample, aSample must be in AVCC format.
// If aSample already contains an extradata with an SPS, it will be returned
// otherwise the SPS/PPS NALs are searched in-band.
// Extract SPS and PPS NALs from aSample by looking into each NALs.
// aSample must be in AVCC format.
static already_AddRefed<mozilla::MediaByteBuffer> ExtractExtraData(
const mozilla::MediaRawData* aSample);
static bool HasSPS(const mozilla::MediaRawData* aSample);
static bool HasSPS(const mozilla::MediaByteBuffer* aExtraData);
static bool HasPPS(const mozilla::MediaRawData* aSample);
static bool HasPPS(const mozilla::MediaByteBuffer* aExtraData);
// Returns true if format is AVCC and sample has valid extradata.
static bool IsAVCC(const mozilla::MediaRawData* aSample);
// Returns true if format is AnnexB.

Просмотреть файл

@ -403,202 +403,6 @@ struct SPSData
SPSData();
};
struct PPSData
{
/*
H264 decoding parameters according to ITU-T H.264 (T-REC-H.264-201402-I/en)
http://www.itu.int/rec/T-REC-H.264-201402-I/en
7.3.2.2 Picture parameter set RBSP syntax
*/
/* pic_parameter_set_id identifies the picture parameter set that is referred
to in the slice header. The value of pic_parameter_set_id shall be in the
range of 0 to 255, inclusive. */
uint8_t pic_parameter_set_id;
/* seq_parameter_set_id refers to the active sequence parameter set. The value
of seq_parameter_set_id shall be in the range of 0 to 31, inclusive. */
uint8_t seq_parameter_set_id;
/* entropy_coding_mode_flag selects the entropy decoding method to be applied
for the syntax elements for which two descriptors appear in the syntax tables
as follows:
If entropy_coding_mode_flag is equal to 0, the method specified by the
left descriptor in the syntax table is applied (Exp-Golomb coded, see
clause 9.1 or CAVLC, see clause 9.2).
Otherwise (entropy_coding_mode_flag is equal to 1), the method specified
by the right descriptor in the syntax table is applied (CABAC, see clause
9.3) */
bool entropy_coding_mode_flag;
/* bottom_field_pic_order_in_frame_present_flag equal to 1 specifies that the
syntax elements delta_pic_order_cnt_bottom (when pic_order_cnt_type is
equal to 0) or delta_pic_order_cnt[ 1 ] (when pic_order_cnt_type is equal to
1), which are related to picture order counts for the bottom field of a
coded frame, are present in the slice headers for coded frames as specified
in clause 7.3.3. bottom_field_pic_order_in_frame_present_flag equal to 0
specifies that the syntax elements delta_pic_order_cnt_bottom and
delta_pic_order_cnt[ 1 ] are not present in the slice headers.
Also known has pic_order_present_flag. */
bool bottom_field_pic_order_in_frame_present_flag;
/* num_slice_groups_minus1 plus 1 specifies the number of slice groups for a
picture. When num_slice_groups_minus1 is equal to 0, all slices of the
picture belong to the same slice group. The allowed range of
num_slice_groups_minus1 is specified in Annex A. */
uint8_t num_slice_groups_minus1;
/* slice_group_map_type specifies how the mapping of slice group map units to
slice groups is coded. The value of slice_group_map_type shall be in the
range of 0 to 6, inclusive. */
uint8_t slice_group_map_type;
/* run_length_minus1[i] is used to specify the number of consecutive slice
group map units to be assigned to the i-th slice group in raster scan order
of slice group map units. The value of run_length_minus1[ i ] shall be in
the range of 0 to PicSizeInMapUnits 1, inclusive. */
uint32_t run_length_minus1[8];
/* top_left[i] and bottom_right[i] specify the top-left and bottom-right
corners of a rectangle, respectively. top_left[i] and bottom_right[i] are
slice group map unit positions in a raster scan of the picture for the slice
group map units. For each rectangle i, all of the following constraints
shall be obeyed by the values of the syntax elements top_left[i] and
bottom_right[i]:
top_left[ i ] shall be less than or equal to bottom_right[i] and
bottom_right[i] shall be less than PicSizeInMapUnits.
(top_left[i] % PicWidthInMbs) shall be less than or equal to the value
of (bottom_right[i] % PicWidthInMbs). */
uint32_t top_left[8];
uint32_t bottom_right[8];
/* slice_group_change_direction_flag is used with slice_group_map_type to
specify the refined map type when slice_group_map_type is 3, 4, or 5. */
bool slice_group_change_direction_flag;
/* slice_group_change_rate_minus1 is used to specify the variable
SliceGroupChangeRate. SliceGroupChangeRate specifies the multiple in number
of slice group map units by which the size of a slice group can change from
one picture to the next. The value of slice_group_change_rate_minus1 shall
be in the range of 0 to PicSizeInMapUnits 1, inclusive.
The SliceGroupChangeRate variable is specified as follows:
SliceGroupChangeRate = slice_group_change_rate_minus1 + 1 */
uint32_t slice_group_change_rate_minus1;
/* pic_size_in_map_units_minus1 is used to specify the number of slice group
map units in the picture. pic_size_in_map_units_minus1 shall be equal to
PicSizeInMapUnits 1. */
uint32_t pic_size_in_map_units_minus1;
/* num_ref_idx_l0_default_active_minus1 specifies how
num_ref_idx_l0_active_minus1 is inferred for P, SP, and B slices
with num_ref_idx_active_override_flag equal to 0. The value of
num_ref_idx_l0_default_active_minus1 shall be in the
range of 0 to 31, inclusive. */
uint8_t num_ref_idx_l0_default_active_minus1;
/* num_ref_idx_l1_default_active_minus1 specifies how
num_ref_idx_l1_active_minus1 is inferred for B slices with
num_ref_idx_active_override_flag equal to 0. The value of
num_ref_idx_l1_default_active_minus1 shall be in the range
of 0 to 31, inclusive. */
uint8_t num_ref_idx_l1_default_active_minus1;
/* weighted_pred_flag equal to 0 specifies that the default weighted
prediction shall be applied to P and SP slices.
weighted_pred_flag equal to 1 specifies that explicit weighted prediction
shall be applied to P and SP slices.weighted_pred_flag 1 */
bool weighted_pred_flag;
/* weighted_bipred_idc equal to 0 specifies that the default weighted
prediction shall be applied to B slices.
weighted_bipred_idc equal to 1 specifies that explicit weighted prediction
shall be applied to B slices. weighted_bipred_idc equal to 2 specifies that
implicit weighted prediction shall be applied to B slices. The value of
weighted_bipred_idc shall be in the range of 0 to 2, inclusive. */
uint8_t weighted_bipred_idc;
/* pic_init_qp_minus26 specifies the initial value minus 26 of SliceQP Y for
each slice. The initial value is modified at the slice layer when a
non-zero value of slice_qp_delta is decoded, and is modified further when a
non-zero value of mb_qp_delta is decoded at the macroblock layer.
The value of pic_init_qp_minus26 shall be in the range of
(26 + QpBdOffset Y ) to +25, inclusive. */
int8_t pic_init_qp_minus26;
/* pic_init_qs_minus26 specifies the initial value minus 26 of SliceQS Y for
all macroblocks in SP or SI slices. The initial value is modified at the
slice layer when a non-zero value of slice_qs_delta is decoded.
The value of pic_init_qs_minus26 shall be in the range of 26 to +25,
inclusive. */
int8_t pic_init_qs_minus26;
/* chroma_qp_index_offset specifies the offset that shall be added to QP Y and
QS Y for addressing the table of QP C values for the Cb chroma component.
The value of chroma_qp_index_offset shall be in the range of 12 to +12,
inclusive. */
int8_t chroma_qp_index_offset;
/* deblocking_filter_control_present_flag equal to 1 specifies that a set of
syntax elements controlling the characteristics of the deblocking filter is
present in the slice header. deblocking_filter_control_present_flag equal to
0 specifies that the set of syntax elements controlling the characteristics
of the deblocking filter is not present in the slice headers and their
inferred values are in effect. */
bool deblocking_filter_control_present_flag;
/* constrained_intra_pred_flag equal to 0 specifies that intra prediction
allows usage of residual data and decoded samples of neighbouring
macroblocks coded using Inter macroblock prediction modes for the prediction
of macroblocks coded using Intra macroblock prediction modes.
constrained_intra_pred_flag equal to 1 specifies constrained intra
prediction, in which case prediction of macroblocks coded using Intra
macroblock prediction modes only uses residual data and decoded samples from
I or SI macroblock types. */
bool constrained_intra_pred_flag;
/* redundant_pic_cnt_present_flag equal to 0 specifies that the
redundant_pic_cnt syntax element is not present in slice headers, coded
slice data partition B NAL units, and coded slice data partition C NAL units
that refer (either directly or by association with a corresponding coded
slice data partition A NAL unit) to the picture parameter set.
redundant_pic_cnt_present_flag equal to 1 specifies that the
redundant_pic_cnt syntax element is present in all slice headers, coded
slice data partition B NAL units, and coded slice data partition C NAL units
that refer (either directly or by association with a corresponding coded
slice data partition A NAL unit) to the picture parameter set. */
bool redundant_pic_cnt_present_flag;
/* transform_8x8_mode_flag equal to 1 specifies that the 8x8 transform
decoding process may be in use (see clause 8.5).
transform_8x8_mode_flag equal to 0 specifies that the 8x8 transform decoding
process is not in use. When transform_8x8_mode_flag is not present, it shall
be inferred to be 0. */
bool transform_8x8_mode_flag;
/* second_chroma_qp_index_offset specifies the offset that shall be added to
QP Y and QS Y for addressing the table of QP C values for the Cr chroma
component.
The value of second_chroma_qp_index_offset shall be in the range of
12 to +12, inclusive.
When second_chroma_qp_index_offset is not present, it shall be inferred to
be equal to chroma_qp_index_offset. */
int8_t second_chroma_qp_index_offset;
uint8_t scaling_matrix4x4[6][16];
uint8_t scaling_matrix8x8[6][64];
PPSData();
};
typedef AutoTArray<SPSData, MAX_SPS_COUNT> SPSDataSet;
typedef AutoTArray<PPSData, MAX_PPS_COUNT> PPSDataSet;
struct H264ParametersSet
{
SPSDataSet SPSes;
PPSDataSet PPSes;
};
class H264
{
public:
@ -616,9 +420,6 @@ public:
static bool DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSData& aDest);
static bool DecodeParametersSet(const mozilla::MediaByteBuffer* aExtraData,
H264ParametersSet& aDest);
// If the given aExtraData is valid, return the aExtraData.max_num_ref_frames
// clamped to be in the range of [4, 16]; otherwise return 4.
static uint32_t ComputeMaxRefFrames(
@ -635,27 +436,9 @@ public:
// (Instantaneous Decoding Refresh) Picture.
static FrameType GetFrameType(const mozilla::MediaRawData* aSample);
// ZigZag index taBles.
// Some hardware requires the tables to be in zigzag order.
// Use ZZ_SCAN table for the scaling_matrix4x4.
// Use ZZ_SCAN8 table for the scaling_matrix8x8.
// e.g. dest_scaling_matrix4x4[i,j] = scaling_matrix4x4[ZZ_SCAN(i,j)]
static const uint8_t ZZ_SCAN[16];
static const uint8_t ZZ_SCAN8[64];
private:
static bool DecodeSPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSDataSet& aDest);
static bool DecodePPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
const SPSDataSet& aPS,
PPSDataSet& aDest);
/* Decode SPS NAL RBSP and fill SPSData structure */
static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest);
/* Decode PPS NAL RBSP and fill PPSData structure */
static bool DecodePPS(const mozilla::MediaByteBuffer* aPPS,
const SPSDataSet& aSPSs, PPSData& aDest);
static bool vui_parameters(BitReader& aBr, SPSData& aDest);
// Read HRD parameters, all data is ignored.
static void hrd_parameters(BitReader& aBr);

Просмотреть файл

@ -67,10 +67,7 @@ struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
*/
already_AddRefed() : mRawPtr(nullptr) {}
// The return and argument types here are arbitrarily selected so no
// corresponding member function exists.
typedef void (already_AddRefed::* MatchNullptr)(double, float);
MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {}
MOZ_IMPLICIT already_AddRefed(decltype(nullptr)) : mRawPtr(nullptr) {}
explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {}

Просмотреть файл

@ -391,6 +391,7 @@ ProxyAutoConfig::ProxyAutoConfig()
, mJSNeedsSetup(false)
, mShutdown(false)
, mIncludePath(false)
, mExtraHeapSize(0)
{
MOZ_COUNT_CTOR(ProxyAutoConfig);
}
@ -551,9 +552,9 @@ static const JSFunctionSpec PACGlobalFunctions[] = {
class JSContextWrapper
{
public:
static JSContextWrapper *Create()
static JSContextWrapper *Create(uint32_t aExtraHeapSize)
{
JSContext* cx = JS_NewContext(sContextHeapSize);
JSContext* cx = JS_NewContext(sContextHeapSize + aExtraHeapSize);
if (NS_WARN_IF(!cx))
return nullptr;
@ -598,7 +599,7 @@ class JSContextWrapper
}
private:
static const unsigned sContextHeapSize = 4 << 20; // 4 MB
static const uint32_t sContextHeapSize = 4 << 20; // 4 MB
JSContext *mContext;
JS::PersistentRooted<JSObject*> mGlobal;
@ -676,12 +677,14 @@ ProxyAutoConfig::SetThreadLocalIndex(uint32_t index)
nsresult
ProxyAutoConfig::Init(const nsCString &aPACURI,
const nsCString &aPACScript,
bool aIncludePath)
bool aIncludePath,
uint32_t aExtraHeapSize)
{
mPACURI = aPACURI;
mPACScript = sPacUtils;
mPACScript.Append(aPACScript);
mIncludePath = aIncludePath;
mExtraHeapSize = aExtraHeapSize;
if (!GetRunning())
return SetupJS();
@ -704,7 +707,7 @@ ProxyAutoConfig::SetupJS()
NS_GetCurrentThread()->SetCanInvokeJS(true);
mJSContext = JSContextWrapper::Create();
mJSContext = JSContextWrapper::Create(mExtraHeapSize);
if (!mJSContext)
return NS_ERROR_FAILURE;

Просмотреть файл

@ -31,7 +31,8 @@ public:
nsresult Init(const nsCString &aPACURI,
const nsCString &aPACScript,
bool aIncludePath);
bool aIncludePath,
uint32_t aExtraHeapSize);
void SetThreadLocalIndex(uint32_t index);
void Shutdown();
void GC();
@ -94,6 +95,7 @@ private:
nsCString mPACScript;
nsCString mPACURI;
bool mIncludePath;
uint32_t mExtraHeapSize;
nsCString mRunningHost;
nsCOMPtr<nsITimer> mTimer;
};

Просмотреть файл

@ -8,6 +8,20 @@ interface nsITabParent;
interface nsIChannel;
interface nsIAsyncVerifyRedirectCallback;
[builtinclass, uuid(01987690-48cf-45de-bae3-e143c2adc2a8)]
interface nsIAsyncVerifyRedirectReadyCallback : nsISupports
{
/**
* Asynchronous callback when redirected channel finishes the preparation for
* completing the verification procedure.
*
* @param result
* SUCCEEDED if preparation for redirection verification succceed.
* If FAILED the redirection must be aborted.
*/
void readyToVerify(in nsresult result);
};
/**
* Implemented by chrome side of IPC protocols that support redirect responses.
*/
@ -33,6 +47,17 @@ interface nsIParentRedirectingChannel : nsIParentChannel
in uint32_t redirectFlags,
in nsIAsyncVerifyRedirectCallback callback);
/**
* Called to new channel when the original channel got Redirect2Verify
* response from child. Callback will be invoked when the new channel
* finishes the preparation for Redirect2Verify and can be called immediately.
*
* @param callback
* redirect ready callback, will be called when redirect verification
* procedure can proceed.
*/
void continueVerification(in nsIAsyncVerifyRedirectReadyCallback callback);
/**
* Called after we are done with redirecting process and we know if to
* redirect or not. Forward the redirect result to the child process. From

Просмотреть файл

@ -50,6 +50,32 @@ HttpRequestSucceeded(nsIStreamLoader *loader)
return result;
}
// Read preference setting of extra JavaScript context heap size.
// PrefService tends to be run on main thread, where ProxyAutoConfig runs on
// ProxyResolution thread, so it's read here and passed to ProxyAutoConfig.
static uint32_t
GetExtraJSContextHeapSize()
{
MOZ_ASSERT(NS_IsMainThread());
static int32_t extraSize = -1;
if (extraSize < 0) {
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
int32_t value;
if (prefs && NS_SUCCEEDED(prefs->GetIntPref(
"network.proxy.autoconfig_extra_jscontext_heap_size", &value))) {
LOG(("autoconfig_extra_jscontext_heap_size: %d\n", value));
extraSize = value;
}
}
return extraSize < 0 ? 0 : extraSize;
}
//-----------------------------------------------------------------------------
// The ExecuteCallback runnable is triggered by
@ -180,6 +206,7 @@ public:
, mCancel(false)
, mCancelStatus(NS_OK)
, mSetupPAC(false)
, mExtraHeapSize(0)
{ }
void CancelQueue (nsresult status)
@ -188,11 +215,15 @@ public:
mCancelStatus = status;
}
void SetupPAC (const char *text, uint32_t datalen, nsCString &pacURI)
void SetupPAC (const char *text,
uint32_t datalen,
nsCString &pacURI,
uint32_t extraHeapSize)
{
mSetupPAC = true;
mSetupPACData.Assign(text, datalen);
mSetupPACURI = pacURI;
mExtraHeapSize = extraHeapSize;
}
NS_IMETHOD Run() override
@ -209,7 +240,8 @@ public:
mPACMan->mPAC.Init(mSetupPACURI,
mSetupPACData,
mPACMan->mIncludePath);
mPACMan->mIncludePath,
mExtraHeapSize);
RefPtr<PACLoadComplete> runnable = new PACLoadComplete(mPACMan);
NS_DispatchToMainThread(runnable);
@ -227,6 +259,7 @@ private:
nsresult mCancelStatus;
bool mSetupPAC;
uint32_t mExtraHeapSize;
nsCString mSetupPACData;
nsCString mSetupPACURI;
};
@ -671,7 +704,7 @@ nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
RefPtr<ExecutePACThreadAction> pending =
new ExecutePACThreadAction(this);
pending->SetupPAC(text, dataLen, pacURI);
pending->SetupPAC(text, dataLen, pacURI, GetExtraJSContextHeapSize());
if (mPACThread)
mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL);

Просмотреть файл

@ -637,6 +637,18 @@
{0x97, 0xa7, 0x06, 0xaf, 0x5e, 0x6d, 0x84, 0xc4} \
}
// Background channel registrar used for pairing HttpChannelParent
// and its background channel
#define NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID \
"@mozilla.org/network/background-channel-registrar;1"
#define NS_BACKGROUNDCHANNELREGISTRAR_CID \
{ /* 6907788a-17cc-4c2a-a7c5-59ad2d9cc079 */ \
0x6907788a, \
0x17cc, \
0x4c2a, \
{ 0xa7, 0xc5, 0x59, 0xad, 0x2d, 0x9c, 0xc0, 0x79} \
}
/******************************************************************************
* netwerk/protocol/ftp/ classes
*/

Просмотреть файл

@ -267,6 +267,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFtpProtocolHandler, Init)
#include "nsHttpNTLMAuth.h"
#include "nsHttpActivityDistributor.h"
#include "ThrottleQueue.h"
#include "BackgroundChannelRegistrar.h"
#undef LOG
#undef LOG_ENABLED
namespace mozilla {
@ -280,6 +281,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpActivityDistributor)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpBasicAuth)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpDigestAuth)
NS_GENERIC_FACTORY_CONSTRUCTOR(ThrottleQueue)
NS_GENERIC_FACTORY_CONSTRUCTOR(BackgroundChannelRegistrar)
} // namespace net
} // namespace mozilla
#endif // !NECKO_PROTOCOL_http
@ -805,6 +807,7 @@ NS_DEFINE_NAMED_CID(NS_HTTPAUTHMANAGER_CID);
NS_DEFINE_NAMED_CID(NS_HTTPCHANNELAUTHPROVIDER_CID);
NS_DEFINE_NAMED_CID(NS_HTTPACTIVITYDISTRIBUTOR_CID);
NS_DEFINE_NAMED_CID(NS_THROTTLEQUEUE_CID);
NS_DEFINE_NAMED_CID(NS_BACKGROUNDCHANNELREGISTRAR_CID);
#endif // !NECKO_PROTOCOL_http
#ifdef NECKO_PROTOCOL_ftp
NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID);
@ -956,6 +959,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
{ &kNS_HTTPCHANNELAUTHPROVIDER_CID, false, nullptr, mozilla::net::nsHttpChannelAuthProviderConstructor },
{ &kNS_HTTPACTIVITYDISTRIBUTOR_CID, false, nullptr, mozilla::net::nsHttpActivityDistributorConstructor },
{ &kNS_THROTTLEQUEUE_CID, false, nullptr, mozilla::net::ThrottleQueueConstructor },
{ &kNS_BACKGROUNDCHANNELREGISTRAR_CID, false, nullptr, mozilla::net::BackgroundChannelRegistrarConstructor },
#endif // !NECKO_PROTOCOL_http
#ifdef NECKO_PROTOCOL_ftp
{ &kNS_FTPPROTOCOLHANDLER_CID, false, nullptr, nsFtpProtocolHandlerConstructor },
@ -1117,6 +1121,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
{ NS_HTTPCHANNELAUTHPROVIDER_CONTRACTID, &kNS_HTTPCHANNELAUTHPROVIDER_CID },
{ NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &kNS_HTTPACTIVITYDISTRIBUTOR_CID },
{ NS_THROTTLEQUEUE_CONTRACTID, &kNS_THROTTLEQUEUE_CID },
{ NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID, &kNS_BACKGROUNDCHANNELREGISTRAR_CID },
#endif // !NECKO_PROTOCOL_http
#ifdef NECKO_PROTOCOL_ftp
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &kNS_FTPPROTOCOLHANDLER_CID },

Просмотреть файл

@ -0,0 +1,97 @@
/* -*- 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 "BackgroundChannelRegistrar.h"
#include "HttpBackgroundChannelParent.h"
#include "HttpChannelParent.h"
#include "nsIInterfaceRequestor.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(BackgroundChannelRegistrar, nsIBackgroundChannelRegistrar)
BackgroundChannelRegistrar::BackgroundChannelRegistrar()
{
// BackgroundChannelRegistrar is a main-thread-only object.
// All the operations should be run on main thread.
// It should be used on chrome process only.
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
}
BackgroundChannelRegistrar::~BackgroundChannelRegistrar()
{
MOZ_ASSERT(NS_IsMainThread());
}
void
BackgroundChannelRegistrar::NotifyChannelLinked(
HttpChannelParent* aChannelParent,
HttpBackgroundChannelParent* aBgParent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChannelParent);
MOZ_ASSERT(aBgParent);
aBgParent->LinkToChannel(aChannelParent);
aChannelParent->OnBackgroundParentReady(aBgParent);
}
// nsIBackgroundChannelRegistrar
void
BackgroundChannelRegistrar::DeleteChannel(uint64_t aKey)
{
MOZ_ASSERT(NS_IsMainThread());
mChannels.Remove(aKey);
mBgChannels.Remove(aKey);
}
void
BackgroundChannelRegistrar::LinkHttpChannel(
uint64_t aKey,
HttpChannelParent* aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChannel);
RefPtr<HttpBackgroundChannelParent> bgParent;
bool found = mBgChannels.Remove(aKey, getter_AddRefs(bgParent));
if (!found) {
mChannels.Put(aKey, aChannel);
return;
}
MOZ_ASSERT(bgParent);
NotifyChannelLinked(aChannel, bgParent);
}
void
BackgroundChannelRegistrar::LinkBackgroundChannel(
uint64_t aKey,
HttpBackgroundChannelParent* aBgChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBgChannel);
RefPtr<HttpChannelParent> parent;
bool found = mChannels.Remove(aKey, getter_AddRefs(parent));
if (!found) {
mBgChannels.Put(aKey, aBgChannel);
return;
}
MOZ_ASSERT(parent);
NotifyChannelLinked(parent, aBgChannel);
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,52 @@
/* -*- 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_net_BackgroundChannelRegistrar_h__
#define mozilla_net_BackgroundChannelRegistrar_h__
#include "nsIBackgroundChannelRegistrar.h"
#include "nsRefPtrHashtable.h"
namespace mozilla {
namespace net {
class HttpBackgroundChannelParent;
class HttpChannelParent;
class BackgroundChannelRegistrar final : public nsIBackgroundChannelRegistrar
{
typedef nsRefPtrHashtable<nsUint64HashKey, HttpChannelParent>
ChannelHashtable;
typedef nsRefPtrHashtable<nsUint64HashKey, HttpBackgroundChannelParent>
BackgroundChannelHashtable;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIBACKGROUNDCHANNELREGISTRAR
explicit BackgroundChannelRegistrar();
private:
virtual ~BackgroundChannelRegistrar();
// A helper function for BackgroundChannelRegistrar itself to callback
// HttpChannelParent and HttpBackgroundChannelParent when both objects are
// ready. aChannelParent and aBgParent is the pair of HttpChannelParent and
// HttpBackgroundChannelParent that should be linked together.
void NotifyChannelLinked(HttpChannelParent* aChannelParent,
HttpBackgroundChannelParent* aBgParent);
// Store unlinked HttpChannelParent objects.
ChannelHashtable mChannels;
// Store unlinked HttpBackgroundChannelParent objects.
BackgroundChannelHashtable mBgChannels;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_BackgroundChannelRegistrar_h__

Просмотреть файл

@ -3,6 +3,7 @@
/* 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 "HttpLog.h"
#include "nsHttp.h"

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsIInterfaceRequestor.h"
#include "nsIStreamListener.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsITimer.h"
#include "mozilla/Attributes.h"

Просмотреть файл

@ -997,7 +997,7 @@ Http2Session::VerifyStream(Http2Stream *aStream, uint32_t aOptionalID = 0)
#ifndef DEBUG
// Only do the real verification in debug builds
return true;
#endif
#else //DEBUG
if (!aStream)
return true;
@ -1043,6 +1043,7 @@ Http2Session::VerifyStream(Http2Stream *aStream, uint32_t aOptionalID = 0)
MOZ_ASSERT(false, "VerifyStream");
return false;
#endif //DEBUG
}
void

Просмотреть файл

@ -0,0 +1,443 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et 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/. */
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include "HttpBackgroundChannelChild.h"
#include "HttpChannelChild.h"
#include "MainThreadUtils.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Unused.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
using mozilla::ipc::BackgroundChild;
using mozilla::ipc::IPCResult;
namespace mozilla {
namespace net {
// Callbacks for PBackgroundChild creation
class BackgroundChannelCreateCallback final
: public nsIIPCBackgroundChildCreateCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
explicit BackgroundChannelCreateCallback(HttpBackgroundChannelChild* aBgChild)
: mBgChild(aBgChild)
{
MOZ_ASSERT(aBgChild);
}
private:
virtual ~BackgroundChannelCreateCallback() { }
RefPtr<HttpBackgroundChannelChild> mBgChild;
};
NS_IMPL_ISUPPORTS(BackgroundChannelCreateCallback,
nsIIPCBackgroundChildCreateCallback)
void
BackgroundChannelCreateCallback::ActorCreated(PBackgroundChild* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aActor);
MOZ_ASSERT(mBgChild);
if (!mBgChild->mChannelChild) {
// HttpChannelChild is closed during PBackground creation,
// abort the rest of steps.
return;
}
const uint64_t channelId = mBgChild->mChannelChild->ChannelId();
if (!aActor->SendPHttpBackgroundChannelConstructor(mBgChild,
channelId)) {
ActorFailed();
return;
}
// hold extra reference for IPDL
RefPtr<HttpBackgroundChannelChild> child = mBgChild;
Unused << child.forget().take();
}
void
BackgroundChannelCreateCallback::ActorFailed()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBgChild);
mBgChild->OnBackgroundChannelCreationFailed();
}
// HttpBackgroundChannelChild
HttpBackgroundChannelChild::HttpBackgroundChannelChild()
{
}
HttpBackgroundChannelChild::~HttpBackgroundChannelChild()
{
}
nsresult
HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild)
{
LOG(("HttpBackgroundChannelChild::Init [this=%p httpChannel=%p channelId=%"
PRIu64 "]\n", this, aChannelChild, aChannelChild->ChannelId()));
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG(aChannelChild);
mChannelChild = aChannelChild;
if (NS_WARN_IF(!CreateBackgroundChannel())) {
mChannelChild = nullptr;
return NS_ERROR_FAILURE;
}
return NS_OK;
}
void
HttpBackgroundChannelChild::OnChannelClosed()
{
LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
// HttpChannelChild is not going to handle any incoming message.
mChannelChild = nullptr;
}
void
HttpBackgroundChannelChild::OnStartRequestReceived()
{
LOG(("HttpBackgroundChannelChild::OnStartRequestReceived [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mChannelChild);
MOZ_ASSERT(!mStartReceived); // Should only be called once.
mStartReceived = true;
nsTArray<nsCOMPtr<nsIRunnable>> runnables;
runnables.SwapElements(mQueuedRunnables);
for (auto event : runnables) {
// Note: these runnables call Recv* methods on HttpBackgroundChannelChild
// but not the Process* methods on HttpChannelChild.
event->Run();
}
// Ensure no new message is enqueued.
MOZ_ASSERT(mQueuedRunnables.IsEmpty());
}
void
HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed()
{
LOG(("HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed"
" [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (mChannelChild) {
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
channelChild->FailedAsyncOpen(NS_ERROR_UNEXPECTED);
}
}
bool
HttpBackgroundChannelChild::CreateBackgroundChannel()
{
LOG(("HttpBackgroundChannelChild::CreateBackgroundChannel [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
RefPtr<BackgroundChannelCreateCallback> callback =
new BackgroundChannelCreateCallback(this);
return BackgroundChild::GetOrCreateForCurrentThread(callback);
}
bool
HttpBackgroundChannelChild::IsWaitingOnStartRequest()
{
// Need to wait for OnStartRequest if it is sent by
// parent process but not received by content process.
return (mStartSent && !mStartReceived);
}
// PHttpBackgroundChannelChild
IPCResult
HttpBackgroundChannelChild::RecvOnStartRequestSent()
{
LOG(("HttpBackgroundChannelChild::RecvOnStartRequestSent [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mStartSent); // Should only receive this message once.
mStartSent = true;
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnTransportAndData(
const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData)
{
LOG(("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
if (IsWaitingOnStartRequest()) {
LOG((" > pending until OnStartRequest [offset=%" PRIu64 " count=%" PRIu32
"]\n", aOffset, aCount));
mQueuedRunnables.AppendElement(
NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
const uint32_t, const nsCString>(
this, &HttpBackgroundChannelChild::RecvOnTransportAndData,
aChannelStatus, aTransportStatus, aOffset,
aCount, aData));
return IPC_OK();
}
mChannelChild->ProcessOnTransportAndData(aChannelStatus,
aTransportStatus,
aOffset,
aCount,
aData);
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnStopRequest(
const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming)
{
LOG(("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
if (IsWaitingOnStartRequest()) {
LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
static_cast<uint32_t>(aChannelStatus)));
mQueuedRunnables.AppendElement(
NewRunnableMethod<const nsresult, const ResourceTimingStruct>(
this, &HttpBackgroundChannelChild::RecvOnStopRequest,
aChannelStatus, aTiming));
return IPC_OK();
}
mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming);
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnProgress(const int64_t& aProgress,
const int64_t& aProgressMax)
{
LOG(("HttpBackgroundChannelChild::RecvOnProgress [this=%p progress=%"
PRId64 " max=%" PRId64 "]\n", this, aProgress, aProgressMax));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
if (IsWaitingOnStartRequest()) {
LOG((" > pending until OnStartRequest [progress=%" PRId64 " max=%"
PRId64 "]\n", aProgress, aProgressMax));
mQueuedRunnables.AppendElement(
NewRunnableMethod<const int64_t, const int64_t>(
this, &HttpBackgroundChannelChild::RecvOnProgress,
aProgress, aProgressMax));
return IPC_OK();
}
mChannelChild->ProcessOnProgress(aProgress, aProgressMax);
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnStatus(const nsresult& aStatus)
{
LOG(("HttpBackgroundChannelChild::RecvOnStatus [this=%p status=%"
PRIx32 "]\n", this, static_cast<uint32_t>(aStatus)));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
if (IsWaitingOnStartRequest()) {
LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
static_cast<uint32_t>(aStatus)));
mQueuedRunnables.AppendElement(
NewRunnableMethod<const nsresult>(
this, &HttpBackgroundChannelChild::RecvOnStatus, aStatus));
return IPC_OK();
}
mChannelChild->ProcessOnStatus(aStatus);
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvFlushedForDiversion()
{
LOG(("HttpBackgroundChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
if (IsWaitingOnStartRequest()) {
LOG((" > pending until OnStartRequest\n"));
mQueuedRunnables.AppendElement(
NewRunnableMethod(this, &HttpBackgroundChannelChild::RecvFlushedForDiversion));
return IPC_OK();
}
mChannelChild->ProcessFlushedForDiversion();
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvDivertMessages()
{
LOG(("HttpBackgroundChannelChild::RecvDivertMessages [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
if (IsWaitingOnStartRequest()) {
LOG((" > pending until OnStartRequest\n"));
mQueuedRunnables.AppendElement(
NewRunnableMethod(this, &HttpBackgroundChannelChild::RecvDivertMessages));
return IPC_OK();
}
mChannelChild->ProcessDivertMessages();
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled()
{
LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
// NotifyTrackingProtectionDisabled has no order dependency to OnStartRequest.
// It this be handled as soon as possible
mChannelChild->ProcessNotifyTrackingProtectionDisabled();
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvNotifyTrackingResource()
{
LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingResource [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
// NotifyTrackingResource has no order dependency to OnStartRequest.
// It this be handled as soon as possible
mChannelChild->ProcessNotifyTrackingResource();
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo(const ClassifierInfo& info)
{
LOG(("HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mChannelChild)) {
return IPC_OK();
}
// SetClassifierMatchedInfo has no order dependency to OnStartRequest.
// It this be handled as soon as possible
mChannelChild->ProcessSetClassifierMatchedInfo(info.list(), info.provider(), info.prefix());
return IPC_OK();
}
void
HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
// Ensure all IPC messages received before ActorDestroy can be
// handled correctly. If there is any pending IPC message, destroyed
// mChannelChild until those messages are flushed.
if (!mQueuedRunnables.IsEmpty()) {
LOG((" > pending until queued messages are flushed\n"));
RefPtr<HttpBackgroundChannelChild> self = this;
mQueuedRunnables.AppendElement(
NS_NewRunnableFunction([self]() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<HttpChannelChild> channelChild = self->mChannelChild.forget();
if (channelChild) {
channelChild->OnBackgroundChildDestroyed();
}
}));
return;
}
if (mChannelChild) {
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
channelChild->OnBackgroundChildDestroyed();
}
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et 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_net_HttpBackgroundChannelChild_h
#define mozilla_net_HttpBackgroundChannelChild_h
#include "mozilla/net/PHttpBackgroundChannelChild.h"
#include "nsIRunnable.h"
#include "nsTArray.h"
using mozilla::ipc::IPCResult;
using mozilla::dom::ClassifierInfo;
namespace mozilla {
namespace net {
class HttpChannelChild;
class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild
{
friend class BackgroundChannelCreateCallback;
public:
explicit HttpBackgroundChannelChild();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HttpBackgroundChannelChild)
// Associate this background channel with a HttpChannelChild and
// initiate the createion of the PBackground IPC channel.
nsresult Init(HttpChannelChild* aChannelChild);
// Callback while the associated HttpChannelChild is not going to
// handle any incoming messages over background channel.
void OnChannelClosed();
// Callback when OnStartRequest is received and handled by HttpChannelChild.
// Enqueued messages in background channel will be flushed.
void OnStartRequestReceived();
// Callback while failed to create PBackground IPC channel.
void OnBackgroundChannelCreationFailed();
protected:
IPCResult RecvOnTransportAndData(const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData) override;
IPCResult RecvOnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming) override;
IPCResult RecvOnProgress(const int64_t& aProgress,
const int64_t& aProgressMax) override;
IPCResult RecvOnStatus(const nsresult& aStatus) override;
IPCResult RecvFlushedForDiversion() override;
IPCResult RecvDivertMessages() override;
IPCResult RecvOnStartRequestSent() override;
IPCResult RecvNotifyTrackingProtectionDisabled() override;
IPCResult RecvNotifyTrackingResource() override;
IPCResult RecvSetClassifierMatchedInfo(const ClassifierInfo& info) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~HttpBackgroundChannelChild();
// Initiate the creation of the PBckground IPC channel.
// Return false if failed.
bool CreateBackgroundChannel();
// Check OnStartRequest is sent by parent process over main thread IPC
// but not yet received on child process.
// return true before RecvOnStartRequestSent is invoked.
// return false if RecvOnStartRequestSent is invoked but not
// OnStartRequestReceived.
// return true after both RecvOnStartRequestSend and OnStartRequestReceived
// are invoked.
bool IsWaitingOnStartRequest();
// Associated HttpChannelChild for handling the channel events.
// Will be removed while failed to create background channel,
// destruction of the background channel, or explicitly dissociation
// via OnChannelClosed callback.
RefPtr<HttpChannelChild> mChannelChild;
// True if OnStartRequest is received by HttpChannelChild.
bool mStartReceived = false;
// True if OnStartRequest is sent by HttpChannelParent.
bool mStartSent = false;
// Store pending messages that require to be handled after OnStartRequest.
// Should be flushed after OnStartRequest is received and handled.
nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_HttpBackgroundChannelChild_h

Просмотреть файл

@ -0,0 +1,411 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et 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/. */
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include "HttpBackgroundChannelParent.h"
#include "HttpChannelParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Unused.h"
#include "nsIBackgroundChannelRegistrar.h"
#include "nsNetCID.h"
#include "nsQueryObject.h"
#include "nsThreadUtils.h"
using mozilla::dom::ContentParent;
using mozilla::ipc::AssertIsInMainProcess;
using mozilla::ipc::AssertIsOnBackgroundThread;
using mozilla::ipc::BackgroundParent;
using mozilla::ipc::IPCResult;
using mozilla::ipc::IsOnBackgroundThread;
namespace mozilla {
namespace net {
/*
* Helper class for continuing the AsyncOpen procedure on main thread.
*/
class ContinueAsyncOpenRunnable final : public Runnable
{
public:
ContinueAsyncOpenRunnable(HttpBackgroundChannelParent* aActor,
const uint64_t& aChannelId)
: mActor(aActor)
, mChannelId(aChannelId)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(mActor);
}
NS_IMETHOD Run() override
{
LOG(("HttpBackgroundChannelParent::ContinueAsyncOpen [this=%p channelId=%"
PRIu64 "]\n", mActor.get(), mChannelId));
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(registrar);
registrar->LinkBackgroundChannel(mChannelId, mActor);
return NS_OK;
}
private:
RefPtr<HttpBackgroundChannelParent> mActor;
const uint64_t mChannelId;
};
HttpBackgroundChannelParent::HttpBackgroundChannelParent()
: mIPCOpened(true)
, mBackgroundThread(NS_GetCurrentThread())
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
HttpBackgroundChannelParent::~HttpBackgroundChannelParent()
{
MOZ_ASSERT(NS_IsMainThread() || IsOnBackgroundThread());
MOZ_ASSERT(!mIPCOpened);
}
nsresult
HttpBackgroundChannelParent::Init(const uint64_t& aChannelId)
{
LOG(("HttpBackgroundChannelParent::Init [this=%p channelId=%" PRIu64 "]\n",
this, aChannelId));
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
RefPtr<ContinueAsyncOpenRunnable> runnable =
new ContinueAsyncOpenRunnable(this, aChannelId);
return NS_DispatchToMainThread(runnable);
}
void
HttpBackgroundChannelParent::LinkToChannel(HttpChannelParent* aChannelParent)
{
LOG(("HttpBackgroundChannelParent::LinkToChannel [this=%p channel=%p]\n",
this, aChannelParent));
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(mIPCOpened);
if (!mIPCOpened) {
return;
}
mChannelParent = aChannelParent;
}
void
HttpBackgroundChannelParent::OnChannelClosed()
{
LOG(("HttpBackgroundChannelParent::OnChannelClosed [this=%p]\n", this));
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
if (!mIPCOpened) {
return;
}
nsresult rv;
RefPtr<HttpBackgroundChannelParent> self = this;
rv = mBackgroundThread->Dispatch(NS_NewRunnableFunction([self]() {
LOG(("HttpBackgroundChannelParent::DeleteRunnable [this=%p]\n", self.get()));
AssertIsOnBackgroundThread();
if (!self->mIPCOpened.compareExchange(true, false)) {
return;
}
Unused << self->Send__delete__(self);
}), NS_DISPATCH_NORMAL);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
bool
HttpBackgroundChannelParent::OnStartRequestSent()
{
LOG(("HttpBackgroundChannelParent::OnStartRequestSent [this=%p]\n", this));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod(this, &HttpBackgroundChannelParent::OnStartRequestSent),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendOnStartRequestSent();
}
bool
HttpBackgroundChannelParent::OnTransportAndData(
const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData)
{
LOG(("HttpBackgroundChannelParent::OnTransportAndData [this=%p]\n", this));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
const uint32_t, const nsCString>
(this, &HttpBackgroundChannelParent::OnTransportAndData,
aChannelStatus, aTransportStatus, aOffset, aCount, aData),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendOnTransportAndData(aChannelStatus, aTransportStatus,
aOffset, aCount, aData);
}
bool
HttpBackgroundChannelParent::OnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming)
{
LOG(("HttpBackgroundChannelParent::OnStopRequest [this=%p "
"status=%" PRIx32 "]\n", this, static_cast<uint32_t>(aChannelStatus)));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod<const nsresult, const ResourceTimingStruct>
(this, &HttpBackgroundChannelParent::OnStopRequest,
aChannelStatus, aTiming),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendOnStopRequest(aChannelStatus, aTiming);
}
bool
HttpBackgroundChannelParent::OnProgress(const int64_t& aProgress,
const int64_t& aProgressMax)
{
LOG(("HttpBackgroundChannelParent::OnProgress [this=%p progress=%" PRId64
" max=%" PRId64 "]\n", this, aProgress, aProgressMax));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod<const int64_t, const int64_t>
(this, &HttpBackgroundChannelParent::OnProgress,
aProgress, aProgressMax),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendOnProgress(aProgress, aProgressMax);
}
bool
HttpBackgroundChannelParent::OnStatus(const nsresult& aStatus)
{
LOG(("HttpBackgroundChannelParent::OnStatus [this=%p stauts=%" PRIx32
"]\n", this, static_cast<uint32_t>(aStatus)));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod<const nsresult>
(this, &HttpBackgroundChannelParent::OnStatus, aStatus),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendOnStatus(aStatus);
}
bool
HttpBackgroundChannelParent::OnDiversion()
{
LOG(("HttpBackgroundChannelParent::OnDiversion [this=%p]\n", this));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod(this, &HttpBackgroundChannelParent::OnDiversion),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
if (!SendFlushedForDiversion()) {
return false;
}
// The listener chain should now be setup; tell HttpChannelChild to divert
// the OnDataAvailables and OnStopRequest to associated HttpChannelParent.
if (!SendDivertMessages()) {
return false;
}
return true;
}
bool
HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled()
{
LOG(("HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled [this=%p]\n", this));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod(this, &HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendNotifyTrackingProtectionDisabled();
}
bool
HttpBackgroundChannelParent::OnNotifyTrackingResource()
{
LOG(("HttpBackgroundChannelParent::OnNotifyTrackingResource [this=%p]\n", this));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod(this, &HttpBackgroundChannelParent::OnNotifyTrackingResource),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
return SendNotifyTrackingResource();
}
bool
HttpBackgroundChannelParent::OnSetClassifierMatchedInfo(
const nsACString& aList,
const nsACString& aProvider,
const nsACString& aPrefix)
{
LOG(("HttpBackgroundChannelParent::OnSetClassifierMatchedInfo [this=%p]\n", this));
AssertIsInMainProcess();
if (NS_WARN_IF(!mIPCOpened)) {
return false;
}
if (!IsOnBackgroundThread()) {
nsresult rv = mBackgroundThread->Dispatch(
NewRunnableMethod<const nsCString, const nsCString, const nsCString>
(this, &HttpBackgroundChannelParent::OnSetClassifierMatchedInfo,
aList, aProvider, aPrefix),
NS_DISPATCH_NORMAL);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return NS_SUCCEEDED(rv);
}
ClassifierInfo info;
info.list() = aList;
info.prefix() = aPrefix;
info.provider() = aProvider;
return SendSetClassifierMatchedInfo(info);
}
void
HttpBackgroundChannelParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("HttpBackgroundChannelParent::ActorDestroy [this=%p]\n", this));
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
mIPCOpened = false;
RefPtr<HttpBackgroundChannelParent> self = this;
DebugOnly<nsresult> rv =
NS_DispatchToMainThread(NS_NewRunnableFunction([self]() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<HttpChannelParent> channelParent =
self->mChannelParent.forget();
if (channelParent) {
channelParent->OnBackgroundParentDestroyed();
}
}));
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,95 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et 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_net_HttpBackgroundChannelParent_h
#define mozilla_net_HttpBackgroundChannelParent_h
#include "mozilla/net/PHttpBackgroundChannelParent.h"
#include "mozilla/Atomics.h"
#include "nsID.h"
#include "nsISupportsImpl.h"
class nsIEventTarget;
namespace mozilla {
namespace net {
class HttpChannelParent;
class HttpBackgroundChannelParent final : public PHttpBackgroundChannelParent
{
public:
explicit HttpBackgroundChannelParent();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HttpBackgroundChannelParent)
// Try to find associated HttpChannelParent with the same
// channel Id.
nsresult Init(const uint64_t& aChannelId);
// Callbacks for BackgroundChannelRegistrar to notify
// the associated HttpChannelParent is found.
void LinkToChannel(HttpChannelParent* aChannelParent);
// Callbacks for HttpChannelParent to close the background
// IPC channel.
void OnChannelClosed();
// To send OnStartRequestSend message over background channel.
bool OnStartRequestSent();
// To send OnTransportAndData message over background channel.
bool OnTransportAndData(const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData);
// To send OnStopRequest message over background channel.
bool OnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming);
// To send OnProgress message over background channel.
bool OnProgress(const int64_t& aProgress,
const int64_t& aProgressMax);
// To send OnStatus message over background channel.
bool OnStatus(const nsresult& aStatus);
// To send FlushedForDiversion and DivertMessages messages
// over background channel.
bool OnDiversion();
// To send NotifyTrackingProtectionDisabled message over background channel.
bool OnNotifyTrackingProtectionDisabled();
// To send NotifyTrackingResource message over background channel.
bool OnNotifyTrackingResource();
// To send SetClassifierMatchedInfo message over background channel.
bool OnSetClassifierMatchedInfo(const nsACString& aList,
const nsACString& aProvider,
const nsACString& aPrefix);
protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~HttpBackgroundChannelParent();
Atomic<bool> mIPCOpened;
nsCOMPtr<nsIEventTarget> mBackgroundThread;
// associated HttpChannelParent for generating the channel events
RefPtr<HttpChannelParent> mChannelParent;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_HttpBackgroundChannelParent_h

Просмотреть файл

@ -62,6 +62,7 @@
#include "nsIXULRuntime.h"
#include "nsICacheInfoChannel.h"
#include "nsIDOMWindowUtils.h"
#include "nsHttpChannel.h"
#include "nsRedirectHistoryEntry.h"
#include <algorithm>

Просмотреть файл

@ -364,6 +364,11 @@ public: /* Necko internal use only... */
mIsTrackingResource = true;
}
const uint64_t& ChannelId() const
{
return mChannelId;
}
protected:
// Handle notifying listener, removing from loadgroup if request failed.
void DoNotifyListener();

Просмотреть файл

@ -20,11 +20,14 @@
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/HttpChannelChild.h"
#include "AltDataOutputStreamChild.h"
#include "HttpBackgroundChannelChild.h"
#include "nsCOMPtr.h"
#include "nsISupportsPrimitives.h"
#include "nsChannelClassifier.h"
#include "nsGlobalWindow.h"
#include "nsStringStream.h"
#include "nsHttpChannel.h"
#include "nsHttpHandler.h"
#include "nsNetUtil.h"
#include "nsSerializationHelper.h"
@ -46,13 +49,10 @@
#include "nsIDOMDocument.h"
#include "nsIDOMWindowUtils.h"
#include "nsIEventTarget.h"
#include "nsRedirectHistoryEntry.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#ifdef OS_POSIX
#include "chrome/common/file_descriptor_set_posix.h"
#endif
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracer.h"
#endif
@ -63,19 +63,6 @@ using namespace mozilla::ipc;
namespace mozilla {
namespace net {
namespace {
const uint32_t kMaxFileDescriptorsPerMessage = 250;
#ifdef OS_POSIX
// Keep this in sync with other platforms.
static_assert(FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE == 250,
"MAX_DESCRIPTORS_PER_MESSAGE mismatch!");
#endif
} // namespace
NS_IMPL_ISUPPORTS(InterceptStreamListener,
nsIStreamListener,
nsIRequestObserver,
@ -286,6 +273,26 @@ HttpChannelChild::ReleaseIPDLReference()
Release();
}
void
HttpChannelChild::OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild)
{
LOG(("HttpChannelChild::OnBackgroundChildReady [this=%p, bgChild=%p]\n",
this, aBgChild));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBgChild);
MOZ_ASSERT(mBgChild == aBgChild);
}
void
HttpChannelChild::OnBackgroundChildDestroyed()
{
LOG(("HttpChannelChild::OnBackgroundChildDestroyed [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
mBgChild = nullptr;
}
class AssociateApplicationCacheEvent : public ChannelEvent
{
public:
@ -439,6 +446,12 @@ HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus,
securityInfoSerialization,
selfAddr, peerAddr, cacheKey,
altDataType, altDataLen));
MOZ_ASSERT(mBgChild);
if (mBgChild) {
mBgChild->OnStartRequestReceived();
}
return IPC_OK();
}
@ -660,22 +673,21 @@ class TransportAndDataEvent : public ChannelEvent
uint32_t mCount;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnTransportAndData(const nsresult& channelStatus,
const nsresult& transportStatus,
const uint64_t& offset,
const uint32_t& count,
const nsCString& data)
void
HttpChannelChild::ProcessOnTransportAndData(const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData)
{
LOG(("HttpChannelChild::RecvOnTransportAndData [this=%p]\n", this));
LOG(("HttpChannelChild::ProcessOnTransportAndData [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"Should not be receiving any more callbacks from parent!");
mEventQ->RunOrEnqueue(new TransportAndDataEvent(this, channelStatus,
transportStatus, data, offset,
count),
mEventQ->RunOrEnqueue(new TransportAndDataEvent(this, aChannelStatus,
aTransportStatus, aData,
aOffset, aCount),
mDivertingToParent);
return IPC_OK();
}
class MaybeDivertOnDataHttpEvent : public ChannelEvent
@ -903,17 +915,17 @@ class StopRequestEvent : public ChannelEvent
ResourceTimingStruct mTiming;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnStopRequest(const nsresult& channelStatus,
const ResourceTimingStruct& timing)
void
HttpChannelChild::ProcessOnStopRequest(const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming)
{
LOG(("HttpChannelChild::RecvOnStopRequest [this=%p]\n", this));
LOG(("HttpChannelChild::ProcessOnStopRequest [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"Should not be receiving any more callbacks from parent!");
mEventQ->RunOrEnqueue(new StopRequestEvent(this, channelStatus, timing),
mEventQ->RunOrEnqueue(new StopRequestEvent(this, aChannelStatus, aTiming),
mDivertingToParent);
return IPC_OK();
}
class MaybeDivertOnStopHttpEvent : public ChannelEvent
@ -1044,6 +1056,8 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
// DoOnStopRequest() calls ReleaseListeners()
}
CleanupBackgroundChannel();
// DocumentChannelCleanup actually nulls out mCacheEntry in the parent, which
// we might need later to open the Alt-Data output stream, so just return here
if (!mPreferredCachedAltDataType.IsEmpty()) {
@ -1142,12 +1156,13 @@ class ProgressEvent : public ChannelEvent
int64_t mProgress, mProgressMax;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnProgress(const int64_t& progress,
const int64_t& progressMax)
void
HttpChannelChild::ProcessOnProgress(const int64_t& aProgress,
const int64_t& aProgressMax)
{
mEventQ->RunOrEnqueue(new ProgressEvent(this, progress, progressMax));
return IPC_OK();
LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
mEventQ->RunOrEnqueue(new ProgressEvent(this, aProgress, aProgressMax));
}
void
@ -1197,11 +1212,12 @@ class StatusEvent : public ChannelEvent
nsresult mStatus;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnStatus(const nsresult& status)
void
HttpChannelChild::ProcessOnStatus(const nsresult& aStatus)
{
mEventQ->RunOrEnqueue(new StatusEvent(this, status));
return IPC_OK();
LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
mEventQ->RunOrEnqueue(new StatusEvent(this, aStatus));
}
void
@ -1266,6 +1282,9 @@ void
HttpChannelChild::HandleAsyncAbort()
{
HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
// Ignore all the messages from background channel after channel aborted.
CleanupBackgroundChannel();
}
void
@ -1273,6 +1292,14 @@ HttpChannelChild::FailedAsyncOpen(const nsresult& status)
{
LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%" PRIx32 "]\n",
this, static_cast<uint32_t>(status)));
MOZ_ASSERT(NS_IsMainThread());
// Might be called twice in race condition in theory.
// (one by RecvFailedAsyncOpen, another by
// HttpBackgroundChannelChild::ActorFailed)
if (NS_WARN_IF(NS_FAILED(mStatus))) {
return;
}
mStatus = status;
@ -1284,6 +1311,27 @@ HttpChannelChild::FailedAsyncOpen(const nsresult& status)
}
}
void
HttpChannelChild::CleanupBackgroundChannel()
{
LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p bgChild=%p]\n",
this, mBgChild.get()));
if (!mBgChild) {
return;
}
RefPtr<HttpBackgroundChannelChild> bgChild = mBgChild.forget();
if (!NS_IsMainThread()) {
SystemGroup::Dispatch(
"HttpChannelChild::CleanupBackgroundChannel",
TaskCategory::Other,
NewRunnableMethod(bgChild, &HttpBackgroundChannelChild::OnChannelClosed));
} else {
bgChild->OnChannelClosed();
}
}
void
HttpChannelChild::DoNotifyListenerCleanup()
{
@ -1673,29 +1721,32 @@ class HttpFlushedForDiversionEvent : public ChannelEvent
HttpChannelChild* mChild;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvFlushedForDiversion()
void
HttpChannelChild::ProcessFlushedForDiversion()
{
LOG(("HttpChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
LOG(("HttpChannelChild::ProcessFlushedForDiversion [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mDivertingToParent);
mEventQ->RunOrEnqueue(new HttpFlushedForDiversionEvent(this), true);
return IPC_OK();
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvNotifyTrackingProtectionDisabled()
void
HttpChannelChild::ProcessNotifyTrackingProtectionDisabled()
{
LOG(("HttpChannelChild::ProcessNotifyTrackingProtectionDisabled [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
nsChannelClassifier::NotifyTrackingProtectionDisabled(this);
return IPC_OK();
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvNotifyTrackingResource()
void
HttpChannelChild::ProcessNotifyTrackingResource()
{
LOG(("HttpChannelChild::ProcessNotifyTrackingResource [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
SetIsTrackingResource();
return IPC_OK();
}
void
@ -1712,26 +1763,28 @@ HttpChannelChild::FlushedForDiversion()
SendDivertComplete();
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvSetClassifierMatchedInfo(const ClassifierInfo& aInfo)
void
HttpChannelChild::ProcessSetClassifierMatchedInfo(const nsCString& aList,
const nsCString& aProvider,
const nsCString& aPrefix)
{
SetMatchedInfo(aInfo.list(), aInfo.provider(), aInfo.prefix());
return IPC_OK();
LOG(("HttpChannelChild::ProcessSetClassifierMatchedInfo [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
SetMatchedInfo(aList, aProvider, aPrefix);
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvDivertMessages()
void
HttpChannelChild::ProcessDivertMessages()
{
LOG(("HttpChannelChild::RecvDivertMessages [this=%p]\n", this));
LOG(("HttpChannelChild::ProcessDivertMessages [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mDivertingToParent);
MOZ_RELEASE_ASSERT(mSuspendCount > 0);
// DivertTo() has been called on parent, so we can now start sending queued
// IPDL messages back to parent listener.
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(Resume()));
return IPC_OK();
}
// Returns true if has actually completed the redirect and cleaned up the
@ -1849,6 +1902,20 @@ HttpChannelChild::ConnectParent(uint32_t registrarId)
return NS_ERROR_FAILURE;
}
{
MOZ_ASSERT(!mBgChild);
RefPtr<HttpBackgroundChannelChild> bgChild =
new HttpBackgroundChannelChild();
nsresult rv = bgChild->Init(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mBgChild = bgChild.forget();
}
return NS_OK;
}
@ -2477,6 +2544,26 @@ HttpChannelChild::ContinueAsyncOpen()
return NS_ERROR_FAILURE;
}
{
// Service worker might use the same HttpChannelChild to do async open
// twice. Need to disconnect with previous background channel before
// creating the new one.
if (mBgChild) {
RefPtr<HttpBackgroundChannelChild> prevBgChild = mBgChild.forget();
prevBgChild->OnChannelClosed();
}
RefPtr<HttpBackgroundChannelChild> bgChild =
new HttpBackgroundChannelChild();
rv = bgChild->Init(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mBgChild = bgChild.forget();
}
return NS_OK;
}

Просмотреть файл

@ -39,6 +39,7 @@ class nsInputStreamPump;
namespace mozilla {
namespace net {
class HttpBackgroundChannelChild;
class InterceptedChannelContent;
class InterceptStreamListener;
@ -110,13 +111,15 @@ public:
MOZ_MUST_USE bool IsSuspended();
mozilla::ipc::IPCResult RecvNotifyTrackingProtectionDisabled() override;
mozilla::ipc::IPCResult RecvNotifyTrackingResource() override;
void FlushedForDiversion();
mozilla::ipc::IPCResult RecvSetClassifierMatchedInfo(const ClassifierInfo& aInfo) override;
void OnCopyComplete(nsresult aStatus) override;
// Callback while background channel is ready.
void OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild);
// Callback while background channel is destroyed.
void OnBackgroundChildDestroyed();
protected:
mozilla::ipc::IPCResult RecvOnStartRequest(const nsresult& channelStatus,
const nsHttpResponseHead& responseHead,
@ -133,14 +136,6 @@ protected:
const uint32_t& cacheKey,
const nsCString& altDataType,
const int64_t& altDataLen) override;
mozilla::ipc::IPCResult RecvOnTransportAndData(const nsresult& channelStatus,
const nsresult& status,
const uint64_t& offset,
const uint32_t& count,
const nsCString& data) override;
mozilla::ipc::IPCResult RecvOnStopRequest(const nsresult& statusCode, const ResourceTimingStruct& timing) override;
mozilla::ipc::IPCResult RecvOnProgress(const int64_t& progress, const int64_t& progressMax) override;
mozilla::ipc::IPCResult RecvOnStatus(const nsresult& status) override;
mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override;
mozilla::ipc::IPCResult RecvRedirect1Begin(const uint32_t& registrarId,
const URIParams& newURI,
@ -152,8 +147,6 @@ protected:
mozilla::ipc::IPCResult RecvRedirect3Complete() override;
mozilla::ipc::IPCResult RecvAssociateApplicationCache(const nsCString& groupID,
const nsCString& clientID) override;
mozilla::ipc::IPCResult RecvFlushedForDiversion() override;
mozilla::ipc::IPCResult RecvDivertMessages() override;
mozilla::ipc::IPCResult RecvDeleteSelf() override;
mozilla::ipc::IPCResult RecvFinishInterceptedRedirect() override;
@ -217,6 +210,26 @@ private:
MOZ_MUST_USE nsresult ContinueAsyncOpen();
// Callbacks while receiving OnTransportAndData/OnStopRequest/OnProgress/
// OnStatus/FlushedForDiversion/DivertMessages on background IPC channel.
void ProcessOnTransportAndData(const nsresult& aChannelStatus,
const nsresult& aStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData);
void ProcessOnStopRequest(const nsresult& aStatusCode,
const ResourceTimingStruct& aTiming);
void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax);
void ProcessOnStatus(const nsresult& aStatus);
void ProcessFlushedForDiversion();
void ProcessDivertMessages();
void ProcessNotifyTrackingProtectionDisabled();
void ProcessNotifyTrackingResource();
void ProcessSetClassifierMatchedInfo(const nsCString& aList,
const nsCString& aProvider,
const nsCString& aPrefix);
void DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
void DoOnStatus(nsIRequest* aRequest, nsresult status);
void DoOnProgress(nsIRequest* aRequest, int64_t progress, int64_t progressMax);
@ -312,6 +325,12 @@ private:
// is synthesized.
bool mSuspendParentAfterSynthesizeResponse;
RefPtr<HttpBackgroundChannelChild> mBgChild;
// Remove the association with background channel after OnStopRequest
// or AsyncAbort.
void CleanupBackgroundChannel();
// Needed to call AsyncOpen in FinishInterceptedRedirect
nsCOMPtr<nsIStreamListener> mInterceptedRedirectListener;
nsCOMPtr<nsISupports> mInterceptedRedirectContext;
@ -403,6 +422,7 @@ private:
friend class HttpAsyncAborter<HttpChannelChild>;
friend class InterceptStreamListener;
friend class InterceptedChannelContent;
friend class HttpBackgroundChannelChild;
};
// A stream listener interposed between the nsInputStreamPump used for intercepted channels

Просмотреть файл

@ -8,17 +8,23 @@
#include "HttpLog.h"
#include "mozilla/ipc/FileDescriptorSetParent.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/net/HttpChannelParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "HttpBackgroundChannelParent.h"
#include "HttpChannelParentListener.h"
#include "nsHttpHandler.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsISupportsPriority.h"
#include "nsIAuthPromptProvider.h"
#include "nsIBackgroundChannelRegistrar.h"
#include "nsSerializationHelper.h"
#include "nsISerializable.h"
#include "nsIAssociatedContentSecurity.h"
@ -37,12 +43,14 @@
#include "nsCORSListenerProxy.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsIPrompt.h"
#include "nsIRedirectChannelRegistrar.h"
#include "nsIWindowWatcher.h"
#include "nsIDocument.h"
#include "nsStreamUtils.h"
#include "nsStringStream.h"
#include "nsIStorageStream.h"
#include "nsQueryObject.h"
#include "nsIURIClassifier.h"
#include "mozilla/dom/ContentParent.h"
using mozilla::BasePrincipal;
using namespace mozilla::dom;
@ -56,7 +64,6 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
PBOverrideStatus aOverrideStatus)
: mIPCClosed(false)
, mIgnoreProgress(false)
, mSentRedirect1Begin(false)
, mSentRedirect1BeginFailed(false)
, mReceivedRedirect2Verify(false)
, mPBOverride(aOverrideStatus)
@ -91,6 +98,7 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
HttpChannelParent::~HttpChannelParent()
{
LOG(("Destroying HttpChannelParent [this=%p]\n", this));
CleanupBackgroundChannel();
}
void
@ -106,6 +114,8 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
if (mParentListener) {
mParentListener->ClearInterceptedChannel();
}
CleanupBackgroundChannel();
}
bool
@ -151,6 +161,101 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
}
}
void
HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv)
{
LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32
"]\n", this, mAsyncOpenBarrier, static_cast<uint32_t>(aRv)));
MOZ_ASSERT(NS_IsMainThread());
// TryInvokeAsyncOpen is called more than we expected.
// Assert in nightly build but ignore it in release channel.
MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier > 0);
if (NS_WARN_IF(!mAsyncOpenBarrier)) {
return;
}
if (--mAsyncOpenBarrier > 0 && NS_SUCCEEDED(aRv)) {
// Need to wait for more events.
return;
}
InvokeAsyncOpen(aRv);
}
void
HttpChannelParent::OnBackgroundParentReady(
HttpBackgroundChannelParent* aBgParent)
{
LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n",
this, aBgParent));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mBgParent);
mBgParent = aBgParent;
mPromise.ResolveIfExists(true, __func__);
}
void
HttpChannelParent::OnBackgroundParentDestroyed()
{
LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (!mPromise.IsEmpty()) {
MOZ_ASSERT(!mBgParent);
mPromise.Reject(NS_ERROR_FAILURE, __func__);
return;
}
if (!mBgParent) {
return;
}
// Background channel is closed unexpectly, abort PHttpChannel operation.
mBgParent = nullptr;
Delete();
}
void
HttpChannelParent::CleanupBackgroundChannel()
{
LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n",
this, mBgParent.get()));
MOZ_ASSERT(NS_IsMainThread());
if (mBgParent) {
RefPtr<HttpBackgroundChannelParent> bgParent = mBgParent.forget();
bgParent->OnChannelClosed();
return;
}
if (!mPromise.IsEmpty()) {
mRequest.DisconnectIfExists();
mPromise.Reject(NS_ERROR_FAILURE, __func__);
if (!mChannel) {
return;
}
// This HttpChannelParent might still have a reference from
// BackgroundChannelRegistrar.
nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(registrar);
registrar->DeleteChannel(mChannel->ChannelId());
// If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure
// is still on going. we need to abort AsyncOpen with failure to destroy
// PHttpChannel actor.
if (mAsyncOpenBarrier) {
TryInvokeAsyncOpen(NS_ERROR_FAILURE);
}
}
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsISupports
//-----------------------------------------------------------------------------
@ -166,6 +271,7 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelParent)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel)
NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel)
if (aIID.Equals(NS_GET_IID(HttpChannelParent))) {
foundInterface = static_cast<nsIInterfaceRequestor*>(this);
@ -232,18 +338,38 @@ HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
// HttpChannelParent::PHttpChannelParent
//-----------------------------------------------------------------------------
void
HttpChannelParent::AsyncOpenFailed(nsresult aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(NS_FAILED(aRv));
// Break the reference cycle among HttpChannelParent,
// HttpChannelParentListener, and nsHttpChannel to avoid memory leakage.
mChannel = nullptr;
mParentListener = nullptr;
if (!mIPCClosed) {
Unused << SendFailedAsyncOpen(aRv);
}
}
void
HttpChannelParent::InvokeAsyncOpen(nsresult rv)
{
LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32 "]\n",
this, static_cast<uint32_t>(rv)));
MOZ_ASSERT(NS_IsMainThread());
if (NS_FAILED(rv)) {
Unused << SendFailedAsyncOpen(rv);
AsyncOpenFailed(rv);
return;
}
nsCOMPtr<nsILoadInfo> loadInfo;
rv = mChannel->GetLoadInfo(getter_AddRefs(loadInfo));
if (NS_FAILED(rv)) {
Unused << SendFailedAsyncOpen(rv);
AsyncOpenFailed(rv);
return;
}
if (loadInfo && loadInfo->GetEnforceSecurity()) {
@ -253,7 +379,7 @@ HttpChannelParent::InvokeAsyncOpen(nsresult rv)
rv = mChannel->AsyncOpen(mParentListener, nullptr);
}
if (NS_FAILED(rv)) {
Unused << SendFailedAsyncOpen(rv);
AsyncOpenFailed(rv);
}
}
@ -273,7 +399,7 @@ public:
NS_IMETHOD Run()
{
RefPtr<HttpChannelParent> channel = do_QueryObject(mChannel.get());
channel->InvokeAsyncOpen(mStatus);
channel->TryInvokeAsyncOpen(mStatus);
return NS_OK;
}
};
@ -384,64 +510,62 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
return SendFailedAsyncOpen(rv);
}
mChannel = do_QueryObject(channel, &rv);
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(channel, &rv);
if (NS_FAILED(rv)) {
return SendFailedAsyncOpen(rv);
}
// Set the channelId allocated in child to the parent instance
mChannel->SetChannelId(aChannelId);
mChannel->SetTopLevelContentWindowId(aContentWindowId);
mChannel->SetTopLevelOuterContentWindowId(aTopLevelOuterContentWindowId);
httpChannel->SetChannelId(aChannelId);
httpChannel->SetTopLevelContentWindowId(aContentWindowId);
httpChannel->SetTopLevelOuterContentWindowId(aTopLevelOuterContentWindowId);
mChannel->SetWarningReporter(this);
mChannel->SetTimingEnabled(true);
httpChannel->SetWarningReporter(this);
httpChannel->SetTimingEnabled(true);
if (mPBOverride != kPBOverride_Unset) {
mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
httpChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
}
if (doResumeAt)
mChannel->ResumeAt(startPos, entityID);
httpChannel->ResumeAt(startPos, entityID);
if (originalUri)
mChannel->SetOriginalURI(originalUri);
httpChannel->SetOriginalURI(originalUri);
if (docUri)
mChannel->SetDocumentURI(docUri);
httpChannel->SetDocumentURI(docUri);
if (referrerUri) {
rv = mChannel->SetReferrerWithPolicyInternal(referrerUri, aReferrerPolicy);
rv = httpChannel->SetReferrerWithPolicyInternal(referrerUri, aReferrerPolicy);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
if (apiRedirectToUri)
mChannel->RedirectTo(apiRedirectToUri);
httpChannel->RedirectTo(apiRedirectToUri);
if (topWindowUri) {
rv = mChannel->SetTopWindowURI(topWindowUri);
rv = httpChannel->SetTopWindowURI(topWindowUri);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
if (aLoadFlags != nsIRequest::LOAD_NORMAL)
mChannel->SetLoadFlags(aLoadFlags);
httpChannel->SetLoadFlags(aLoadFlags);
for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
if (requestHeaders[i].mEmpty) {
mChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader);
httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader);
} else {
mChannel->SetRequestHeader(requestHeaders[i].mHeader,
httpChannel->SetRequestHeader(requestHeaders[i].mHeader,
requestHeaders[i].mValue,
requestHeaders[i].mMerge);
}
}
mParentListener = new HttpChannelParentListener(this);
RefPtr<HttpChannelParentListener> parentListener
= new HttpChannelParentListener(this);
mChannel->SetNotificationCallbacks(mParentListener);
mChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
httpChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
mChannel->SetCorsPreflightParameters(args.unsafeHeaders());
httpChannel->SetCorsPreflightParameters(args.unsafeHeaders());
}
bool delayAsyncOpen = false;
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream);
if (stream) {
// FIXME: The fast path of using the existing stream currently only applies to streams
@ -449,7 +573,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
// Once bug 1294446 and bug 1294450 are fixed it is worth revisiting this heuristic.
nsCOMPtr<nsIIPCSerializableInputStream> completeStream = do_QueryInterface(stream);
if (!completeStream) {
delayAsyncOpen = true;
// Wait for completion of async copying IPC upload stream to a local input stream.
++mAsyncOpenBarrier;
// buffer size matches PChildToParentStream transfer size.
const uint32_t kBufferSize = 32768;
@ -494,29 +619,29 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
return SendFailedAsyncOpen(rv);
}
mChannel->InternalSetUploadStream(newUploadStream);
httpChannel->InternalSetUploadStream(newUploadStream);
} else {
mChannel->InternalSetUploadStream(stream);
httpChannel->InternalSetUploadStream(stream);
}
mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
httpChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
}
if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) {
mParentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead());
parentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead());
mWillSynthesizeResponse = true;
mChannel->SetCouldBeSynthesized();
httpChannel->SetCouldBeSynthesized();
if (!aSecurityInfoSerialization.IsEmpty()) {
nsCOMPtr<nsISupports> secInfo;
NS_DeserializeObject(aSecurityInfoSerialization, getter_AddRefs(secInfo));
rv = mChannel->OverrideSecurityInfo(secInfo);
rv = httpChannel->OverrideSecurityInfo(secInfo);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
} else {
nsLoadFlags newLoadFlags;
mChannel->GetLoadFlags(&newLoadFlags);
httpChannel->GetLoadFlags(&newLoadFlags);
newLoadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
mChannel->SetLoadFlags(newLoadFlags);
httpChannel->SetLoadFlags(newLoadFlags);
}
nsCOMPtr<nsISupportsPRUint32> cacheKey =
@ -530,37 +655,37 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
return SendFailedAsyncOpen(rv);
}
mChannel->SetCacheKey(cacheKey);
mChannel->PreferAlternativeDataType(aPreferredAlternativeType);
httpChannel->SetCacheKey(cacheKey);
httpChannel->PreferAlternativeDataType(aPreferredAlternativeType);
mChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);
httpChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);
mChannel->SetContentType(aContentTypeHint);
httpChannel->SetContentType(aContentTypeHint);
if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
mChannel->SetPriority(priority);
httpChannel->SetPriority(priority);
}
if (classOfService) {
mChannel->SetClassFlags(classOfService);
httpChannel->SetClassFlags(classOfService);
}
mChannel->SetRedirectionLimit(redirectionLimit);
mChannel->SetAllowSTS(allowSTS);
mChannel->SetThirdPartyFlags(thirdPartyFlags);
mChannel->SetAllowSpdy(allowSpdy);
mChannel->SetAllowAltSvc(allowAltSvc);
mChannel->SetBeConservative(beConservative);
mChannel->SetInitialRwin(aInitialRwin);
mChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
httpChannel->SetRedirectionLimit(redirectionLimit);
httpChannel->SetAllowSTS(allowSTS);
httpChannel->SetThirdPartyFlags(thirdPartyFlags);
httpChannel->SetAllowSpdy(allowSpdy);
httpChannel->SetAllowAltSvc(allowAltSvc);
httpChannel->SetBeConservative(beConservative);
httpChannel->SetInitialRwin(aInitialRwin);
httpChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
mChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
mChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
mChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
mChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
mChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
mChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd);
httpChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
httpChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
httpChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
httpChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
httpChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
httpChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd);
nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
do_QueryObject(mChannel);
do_QueryObject(httpChannel);
nsCOMPtr<nsIApplicationCacheService> appCacheService =
do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
@ -582,7 +707,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
if (setChooseApplicationCache) {
OriginAttributes attrs;
NS_GetOriginAttributes(mChannel, attrs);
NS_GetOriginAttributes(httpChannel, attrs);
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(uri, attrs);
@ -596,17 +721,61 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
}
}
mChannel->SetRequestContextID(aRequestContextID);
httpChannel->SetRequestContextID(aRequestContextID);
// Store the strong reference of channel and parent listener object until
// all the initialization procedure is complete without failure, to remove
// cycle reference in fail case and to avoid memory leakage.
mChannel = httpChannel.forget();
mParentListener = parentListener.forget();
mChannel->SetNotificationCallbacks(mParentListener);
mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse;
if (!delayAsyncOpen) {
InvokeAsyncOpen(NS_OK);
}
MOZ_ASSERT(!mBgParent);
MOZ_ASSERT(mPromise.IsEmpty());
// Wait for HttpBackgrounChannel to continue the async open procedure.
++mAsyncOpenBarrier;
RefPtr<GenericPromise> promise = WaitForBgParent();
RefPtr<HttpChannelParent> self = this;
promise->Then(AbstractThread::MainThread(), __func__,
[self]() {
self->mRequest.Complete();
self->TryInvokeAsyncOpen(NS_OK);
},
[self](nsresult aStatus) {
self->mRequest.Complete();
self->TryInvokeAsyncOpen(aStatus);
})
->Track(mRequest);
return true;
}
already_AddRefed<GenericPromise>
HttpChannelParent::WaitForBgParent()
{
LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this));
MOZ_ASSERT(!mBgParent);
MOZ_ASSERT(mChannel);
nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(registrar);
registrar->LinkHttpChannel(mChannel->ChannelId(), this);
if (mBgParent) {
already_AddRefed<GenericPromise> promise = mPromise.Ensure(__func__);
// resolve promise immediatedly if bg channel is ready.
mPromise.Resolve(true, __func__);
return promise;
}
return mPromise.Ensure(__func__);;
}
bool
HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept)
{
@ -647,6 +816,20 @@ HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shoul
}
}
MOZ_ASSERT(!mBgParent);
MOZ_ASSERT(mPromise.IsEmpty());
// Waiting for background channel
RefPtr<GenericPromise> promise = WaitForBgParent();
RefPtr<HttpChannelParent> self = this;
promise->Then(AbstractThread::MainThread(), __func__,
[self]() {
self->mRequest.Complete();
},
[self](const nsresult& aResult) {
NS_ERROR("failed to establish the background channel");
self->mRequest.Complete();
})
->Track(mRequest);
return true;
}
@ -803,15 +986,89 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
}
}
// Continue the verification procedure if child has veto the redirection.
if (NS_FAILED(result)) {
ContinueRedirect2Verify(result);
return IPC_OK();
}
// Wait for background channel ready on target channel
nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
do_GetService(NS_REDIRECTCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(redirectReg);
nsCOMPtr<nsIParentChannel> redirectParentChannel;
rv = redirectReg->GetParentChannel(mRedirectRegistrarId,
getter_AddRefs(redirectParentChannel));
MOZ_ASSERT(redirectParentChannel);
if (!redirectParentChannel) {
ContinueRedirect2Verify(rv);
return IPC_OK();
}
nsCOMPtr<nsIParentRedirectingChannel> redirectedParent =
do_QueryInterface(redirectParentChannel);
if (!redirectedParent) {
// Continue verification procedure if redirecting to non-Http protocol
ContinueRedirect2Verify(result);
return IPC_OK();
}
// Ask redirected channel if verification can proceed.
// ContinueRedirect2Verify will be invoked when redirected channel is ready.
redirectedParent->ContinueVerification(this);
return IPC_OK();
}
// from nsIParentRedirectingChannel
NS_IMETHODIMP
HttpChannelParent::ContinueVerification(nsIAsyncVerifyRedirectReadyCallback* aCallback)
{
LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n",
this, aCallback));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aCallback);
// Continue the verification procedure if background channel is ready.
if (mBgParent) {
aCallback->ReadyToVerify(NS_OK);
return NS_OK;
}
// ConnectChannel must be received before Redirect2Verify.
MOZ_ASSERT(!mPromise.IsEmpty());
// Otherwise, wait for the background channel.
RefPtr<GenericPromise> promise = WaitForBgParent();
nsCOMPtr<nsIAsyncVerifyRedirectReadyCallback> callback = aCallback;
promise->Then(AbstractThread::MainThread(), __func__,
[callback]() {
callback->ReadyToVerify(NS_OK);
},
[callback](const nsresult& aResult) {
NS_ERROR("failed to establish the background channel");
callback->ReadyToVerify(aResult);
});
return NS_OK;
}
void
HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult)
{
LOG(("HttpChannelParent::ContinueRedirect2Verify [this=%p result=%" PRIx32 "]\n",
this, static_cast<uint32_t>(aResult)));
if (!mRedirectCallback) {
// This should according the logic never happen, log the situation.
if (mReceivedRedirect2Verify)
LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
if (mSentRedirect1BeginFailed)
LOG(("RecvRedirect2Verify[%p]: Send to child failed", this));
if (mSentRedirect1Begin && NS_FAILED(result))
if ((mRedirectRegistrarId > 0) && NS_FAILED(aResult))
LOG(("RecvRedirect2Verify[%p]: Redirect failed", this));
if (mSentRedirect1Begin && NS_SUCCEEDED(result))
if ((mRedirectRegistrarId > 0) && NS_SUCCEEDED(aResult))
LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this));
if (!mRedirectChannel)
LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this));
@ -823,20 +1080,19 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
mReceivedRedirect2Verify = true;
if (mRedirectCallback) {
LOG(("HttpChannelParent::RecvRedirect2Verify call OnRedirectVerifyCallback"
LOG(("HttpChannelParent::ContinueRedirect2Verify call OnRedirectVerifyCallback"
" [this=%p result=%" PRIx32 ", mRedirectCallback=%p]\n",
this, static_cast<uint32_t>(result), mRedirectCallback.get()));
mRedirectCallback->OnRedirectVerifyCallback(result);
this, static_cast<uint32_t>(aResult), mRedirectCallback.get()));
mRedirectCallback->OnRedirectVerifyCallback(aResult);
mRedirectCallback = nullptr;
}
return IPC_OK();
}
mozilla::ipc::IPCResult
HttpChannelParent::RecvDocumentChannelCleanup()
{
// From now on only using mAssociatedContentSecurity. Free everything else.
CleanupBackgroundChannel(); // Background channel can be closed.
mChannel = nullptr; // Reclaim some memory sooner.
mCacheEntry = nullptr; // Else we'll block other channels reading same URI
return IPC_OK();
@ -1128,6 +1384,7 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n",
this, aRequest));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mDivertingFromChild,
"Cannot call OnStartRequest if diverting is set!");
@ -1236,6 +1493,17 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
rv = NS_ERROR_UNEXPECTED;
}
requestHead->Exit();
// OnStartRequest is sent to content process successfully.
// Notify PHttpBackgroundChannelChild that all following IPC mesasges
// should be run after OnStartRequest is handled.
if (NS_SUCCEEDED(rv)) {
MOZ_ASSERT(mBgParent);
if (!mBgParent->OnStartRequestSent()) {
rv = NS_ERROR_UNEXPECTED;
}
}
return rv;
}
@ -1246,6 +1514,7 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
{
LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32 "]\n",
this, aRequest, static_cast<uint32_t>(aStatusCode)));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mDivertingFromChild,
"Cannot call OnStopRequest if diverting is set!");
@ -1269,8 +1538,15 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
mChannel->GetCacheReadStart(&timing.cacheReadStart);
mChannel->GetCacheReadEnd(&timing.cacheReadEnd);
if (mIPCClosed || !SendOnStopRequest(aStatusCode, timing))
// Either IPC channel is closed or background channel
// is ready to send OnStopRequest.
MOZ_ASSERT(mIPCClosed || mBgParent);
if (mIPCClosed ||
!mBgParent || !mBgParent->OnStopRequest(aStatusCode, timing)) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
@ -1285,8 +1561,9 @@ HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
uint64_t aOffset,
uint32_t aCount)
{
LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p]\n",
this, aRequest));
LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64
" count=%" PRIu32 "]\n", this, aRequest, aOffset, aCount));
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mDivertingFromChild,
"Cannot call OnDataAvailable if diverting is set!");
@ -1313,8 +1590,13 @@ HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
return rv;
}
if (mIPCClosed || !SendOnTransportAndData(channelStatus, transportStatus,
aOffset, toRead, data)) {
// Either IPC channel is closed or background channel
// is ready to send OnTransportAndData.
MOZ_ASSERT(mIPCClosed || mBgParent);
if (mIPCClosed || !mBgParent ||
!mBgParent->OnTransportAndData(channelStatus, transportStatus,
aOffset, toRead, data)) {
return NS_ERROR_UNEXPECTED;
}
@ -1336,16 +1618,25 @@ HttpChannelParent::OnProgress(nsIRequest *aRequest,
int64_t aProgress,
int64_t aProgressMax)
{
LOG(("HttpChannelParent::OnStatus [this=%p progress=%" PRId64 "max=%" PRId64
"]\n", this, aProgress, aProgressMax));
MOZ_ASSERT(NS_IsMainThread());
// If it indicates this precedes OnDataAvailable, child can derive the value in ODA.
if (mIgnoreProgress) {
mIgnoreProgress = false;
return NS_OK;
}
// Either IPC channel is closed or background channel
// is ready to send OnProgress.
MOZ_ASSERT(mIPCClosed || mBgParent);
// Send OnProgress events to the child for data upload progress notifications
// (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has
// LOAD_BACKGROUND set.
if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax)) {
if (mIPCClosed || !mBgParent
|| !mBgParent->OnProgress(aProgress, aProgressMax)) {
return NS_ERROR_UNEXPECTED;
}
@ -1358,6 +1649,10 @@ HttpChannelParent::OnStatus(nsIRequest *aRequest,
nsresult aStatus,
const char16_t *aStatusArg)
{
LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n",
this, static_cast<uint32_t>(aStatus)));
MOZ_ASSERT(NS_IsMainThread());
// If this precedes OnDataAvailable, transportStatus will be derived in ODA.
if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
aStatus == NS_NET_STATUS_READING) {
@ -1368,8 +1663,12 @@ HttpChannelParent::OnStatus(nsIRequest *aRequest,
return NS_OK;
}
// Either IPC channel is closed or background channel
// is ready to send OnStatus.
MOZ_ASSERT(mIPCClosed || mBgParent);
// Otherwise, send to child now
if (mIPCClosed || !SendOnStatus(aStatus)) {
if (mIPCClosed || !mBgParent || !mBgParent->OnStatus(aStatus)) {
return NS_ERROR_UNEXPECTED;
}
@ -1396,8 +1695,11 @@ HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener)
NS_IMETHODIMP
HttpChannelParent::NotifyTrackingProtectionDisabled()
{
if (!mIPCClosed)
Unused << SendNotifyTrackingProtectionDisabled();
LOG(("HttpChannelParent::NotifyTrackingProtectionDisabled [this=%p]\n", this));
if (!mIPCClosed) {
MOZ_ASSERT(mBgParent);
Unused << mBgParent->OnNotifyTrackingProtectionDisabled();
}
return NS_OK;
}
@ -1406,13 +1708,10 @@ HttpChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
const nsACString& aProvider,
const nsACString& aPrefix)
{
LOG(("HttpChannelParent::SetClassifierMatchedInfo [this=%p]\n", this));
if (!mIPCClosed) {
ClassifierInfo info;
info.list() = aList;
info.prefix() = aPrefix;
info.provider() = aProvider;
Unused << SendSetClassifierMatchedInfo(info);
MOZ_ASSERT(mBgParent);
Unused << mBgParent->OnSetClassifierMatchedInfo(aList, aProvider, aPrefix);
}
return NS_OK;
}
@ -1420,8 +1719,11 @@ HttpChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
NS_IMETHODIMP
HttpChannelParent::NotifyTrackingResource()
{
if (!mIPCClosed)
Unused << SendNotifyTrackingResource();
LOG(("HttpChannelParent::NotifyTrackingResource [this=%p]\n", this));
if (!mIPCClosed) {
MOZ_ASSERT(mBgParent);
Unused << mBgParent->OnNotifyTrackingResource();
}
return NS_OK;
}
@ -1487,7 +1789,9 @@ HttpChannelParent::StartRedirect(uint32_t registrarId,
}
// Bug 621446 investigation
mSentRedirect1Begin = true;
// Store registrar Id of the new channel to find the redirect
// HttpChannelParent later in verification phase.
mRedirectRegistrarId = registrarId;
// Result is handled in RecvRedirect2Verify above
@ -1704,14 +2008,11 @@ HttpChannelParent::StartDiversion()
MOZ_ASSERT(NS_SUCCEEDED(rvdbg));
mDivertListener = nullptr;
if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
FailDiversion(NS_ERROR_UNEXPECTED);
return;
}
// Either IPC channel is closed or background channel
// is ready to send FlushedForDiversion and DivertMessages.
MOZ_ASSERT(mIPCClosed || mBgParent);
// The listener chain should now be setup; tell HttpChannelChild to divert
// the OnDataAvailables and OnStopRequest to this HttpChannelParent.
if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
if (NS_WARN_IF(mIPCClosed || !mBgParent || !mBgParent->OnDiversion())) {
FailDiversion(NS_ERROR_UNEXPECTED);
return;
}
@ -1789,12 +2090,16 @@ HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
if (!isPending) {
mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
}
mParentListener = nullptr;
mChannel = nullptr;
if (!mIPCClosed) {
Unused << DoSendDeleteSelf();
}
// DoSendDeleteSelf will need channel Id to remove the strong reference in
// BackgroundChannelRegistrar if channel pairing is aborted.
// Thus we need to keep mChannel until DoSendDeleteSelf is done.
mParentListener = nullptr;
mChannel = nullptr;
}
nsresult
@ -1837,6 +2142,9 @@ HttpChannelParent::DoSendDeleteSelf()
{
bool rv = SendDeleteSelf();
mIPCClosed = true;
CleanupBackgroundChannel();
return rv;
}
@ -1887,6 +2195,22 @@ HttpChannelParent::IssueWarning(uint32_t aWarning, bool aAsError)
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsIAsyncVerifyRedirectReadyCallback
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::ReadyToVerify(nsresult aResult)
{
LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n",
this, static_cast<uint32_t>(aResult)));
MOZ_ASSERT(NS_IsMainThread());
ContinueRedirect2Verify(aResult);
return NS_OK;
}
void
HttpChannelParent::DoSendSetPriority(int16_t aValue)
{

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/net/PHttpChannelParent.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/MozPromise.h"
#include "nsIObserver.h"
#include "nsIParentRedirectingChannel.h"
#include "nsIProgressEventSink.h"
@ -37,6 +38,7 @@ class PBrowserOrId;
namespace net {
class HttpBackgroundChannelParent;
class HttpChannelParentListener;
class ChannelEventQueue;
@ -52,6 +54,7 @@ class HttpChannelParent final : public nsIInterfaceRequestor
, public nsIAuthPromptProvider
, public nsIDeprecationWarner
, public HttpChannelSecurityWarningReporter
, public nsIAsyncVerifyRedirectReadyCallback
{
virtual ~HttpChannelParent();
@ -65,6 +68,7 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIAUTHPROMPTPROVIDER
NS_DECL_NSIDEPRECATIONWARNER
NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK
NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_CHANNEL_PARENT_IID)
@ -99,10 +103,22 @@ public:
MOZ_MUST_USE nsresult OpenAlternativeOutputStream(const nsACString & type,
nsIOutputStream * *_retval);
// Callbacks for each asynchronous tasks required in AsyncOpen
// procedure, will call InvokeAsyncOpen when all the expected
// tasks is finished successfully or when any failure happened.
// @see mAsyncOpenBarrier.
void TryInvokeAsyncOpen(nsresult aRv);
void InvokeAsyncOpen(nsresult rv);
// Calls SendSetPriority if mIPCClosed is false.
void DoSendSetPriority(int16_t aValue);
// Callback while background channel is ready.
void OnBackgroundParentReady(HttpBackgroundChannelParent* aBgParent);
// Callback while background channel is destroyed.
void OnBackgroundParentDestroyed();
protected:
// used to connect redirected-to channel in parent with just created
// ChildChannel. Used during redirects.
@ -217,6 +233,26 @@ private:
void MaybeFlushPendingDiversion();
void ResponseSynthesized();
// final step for Redirect2Verify procedure, will be invoked while both
// redirecting and redirected channel are ready or any error happened.
// OnRedirectVerifyCallback will be invoked for finishing the async
// redirect verification procedure.
void ContinueRedirect2Verify(const nsresult& aResult);
void AsyncOpenFailed(nsresult aRv);
// Request to pair with a HttpBackgroundChannelParent with the same channel
// id, a promise will be returned so the caller can append callbacks on it.
// If called multiple times before mBgParent is available, the same promise
// will be returned and the callbacks will be invoked in order.
already_AddRefed<GenericPromise> WaitForBgParent();
// Remove the association with background channel after main-thread IPC
// is about to be destroyed or no further event is going to be sent, i.e.,
// DocumentChannelCleanup.
void CleanupBackgroundChannel();
friend class HttpBackgroundChannelParent;
friend class DivertDataAvailableEvent;
friend class DivertStopRequestEvent;
friend class DivertCompleteEvent;
@ -236,7 +272,6 @@ private:
// since the information can be recontructed from ODA.
bool mIgnoreProgress : 1;
bool mSentRedirect1Begin : 1;
bool mSentRedirect1BeginFailed : 1;
bool mReceivedRedirect2Verify : 1;
@ -272,6 +307,20 @@ private:
dom::TabId mNestedFrameId;
RefPtr<ChannelEventQueue> mEventQ;
RefPtr<HttpBackgroundChannelParent> mBgParent;
// Number of events to wait before actually invoking AsyncOpen on the main
// channel. For each asynchronous step required before InvokeAsyncOpen, should
// increase 1 to mAsyncOpenBarrier and invoke TryInvokeAsyncOpen after
// finished. This attribute is main thread only.
uint8_t mAsyncOpenBarrier = 0;
// Corresponding redirect channel registrar Id. 0 means redirection is not started.
uint32_t mRedirectRegistrarId = 0;
MozPromiseHolder<GenericPromise> mPromise;
MozPromiseRequestHolder<GenericPromise> mRequest;
};
NS_DEFINE_STATIC_IID_ACCESSOR(HttpChannelParent,

Просмотреть файл

@ -16,6 +16,7 @@
#include "nsIHttpHeaderVisitor.h"
#include "nsIRedirectChannelRegistrar.h"
#include "nsIPromptFactory.h"
#include "nsIWindowWatcher.h"
#include "nsQueryObject.h"
using mozilla::Unused;

Просмотреть файл

@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 protocol PBackground;
include NeckoChannelParams;
include PURLClassifierInfo;
include "mozilla/net/NeckoMessageUtils.h";
using struct mozilla::net::ResourceTimingStruct from "mozilla/net/TimingStruct.h";
namespace mozilla {
namespace net {
//-------------------------------------------------------------------
async protocol PHttpBackgroundChannel
{
manager PBackground;
child:
// OnStartRequest is sent over main thread IPC. The following
// OnTransportAndData/OnStopRequest/OnProgress/OnStatus/FlushForDiversion/
// DivertMessages needs to wait in content process until OnStartRequest
// is processed. For synchronizing the event sequence.
async OnStartRequestSent();
// Combines a single OnDataAvailable and its associated OnProgress &
// OnStatus calls into one IPDL message
async OnTransportAndData(nsresult channelStatus,
nsresult transportStatus,
uint64_t offset,
uint32_t count,
nsCString data);
async OnStopRequest(nsresult channelStatus, ResourceTimingStruct timing);
async OnProgress(int64_t progress, int64_t progressMax);
async OnStatus(nsresult status);
// Parent has been suspended for diversion; no more events to be enqueued.
async FlushedForDiversion();
// Child should resume processing the ChannelEventQueue, i.e. diverting any
// OnDataAvailable and OnStopRequest messages in the queue back to the parent.
async DivertMessages();
// Tell the child that tracking protection was disabled for this load.
async NotifyTrackingProtectionDisabled();
// Tell the child that the resource being loaded is on the tracking
// protection list.
async NotifyTrackingResource();
// Tell the child information of matched URL againts SafeBrowsing list
async SetClassifierMatchedInfo(ClassifierInfo info);
async __delete__();
};
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -10,7 +10,6 @@ include InputStreamParams;
include URIParams;
include PBackgroundSharedTypes;
include NeckoChannelParams;
include PURLClassifierInfo;
include "mozilla/net/NeckoMessageUtils.h";
@ -109,20 +108,6 @@ child:
nsCString altDataType,
int64_t altDataLength);
// Combines a single OnDataAvailable and its associated OnProgress &
// OnStatus calls into one IPDL message
async OnTransportAndData(nsresult channelStatus,
nsresult transportStatus,
uint64_t offset,
uint32_t count,
nsCString data);
async OnStopRequest(nsresult channelStatus, ResourceTimingStruct timing);
async OnProgress(int64_t progress, int64_t progressMax);
async OnStatus(nsresult status);
// Used to cancel child channel if we hit errors during creating and
// AsyncOpen of nsHttpChannel on the parent.
async FailedAsyncOpen(nsresult status);
@ -144,20 +129,6 @@ child:
async AssociateApplicationCache(nsCString groupID,
nsCString clientID);
// Tell the child that tracking protection was disabled for this load.
async NotifyTrackingProtectionDisabled();
// Tell the child that the resource being loaded is on the tracking
// protection list.
async NotifyTrackingResource();
// Parent has been suspended for diversion; no more events to be enqueued.
async FlushedForDiversion();
// Child should resume processing the ChannelEventQueue, i.e. diverting any
// OnDataAvailable and OnStopRequest messages in the queue back to the parent.
async DivertMessages();
// Report a security message to the console associated with this
// channel.
async ReportSecurityMessage(nsString messageTag, nsString messageCategory);
@ -169,9 +140,6 @@ child:
// Tell the child to issue a deprecation warning.
async IssueDeprecationWarning(uint32_t warning, bool asError);
// Tell the child information of matched URL againts SafeBrowsing list
async SetClassifierMatchedInfo(ClassifierInfo info);
both:
// After receiving this message, the parent also calls
// SendFinishInterceptedRedirect, and makes sure not to send any more messages

Просмотреть файл

@ -8,6 +8,7 @@ with Files('**'):
BUG_COMPONENT = ('Core', 'Networking: HTTP')
XPIDL_SOURCES += [
'nsIBackgroundChannelRegistrar.idl',
'nsIHstsPrimingCallback.idl',
'nsIHttpActivityObserver.idl',
'nsIHttpAuthenticableChannel.idl',
@ -39,6 +40,8 @@ EXPORTS.mozilla.net += [
'AltDataOutputStreamChild.h',
'AltDataOutputStreamParent.h',
'HttpAuthUtils.h',
'HttpBackgroundChannelChild.h',
'HttpBackgroundChannelParent.h',
'HttpBaseChannel.h',
'HttpChannelChild.h',
'HttpChannelParent.h',
@ -58,6 +61,7 @@ UNIFIED_SOURCES += [
'AltDataOutputStreamParent.cpp',
'AlternateServices.cpp',
'ASpdySession.cpp',
'BackgroundChannelRegistrar.cpp',
'CacheControlParser.cpp',
'ConnectionDiagnostics.cpp',
'HSTSPrimerListener.cpp',
@ -66,6 +70,8 @@ UNIFIED_SOURCES += [
'Http2Session.cpp',
'Http2Stream.cpp',
'HttpAuthUtils.cpp',
'HttpBackgroundChannelChild.cpp',
'HttpBackgroundChannelParent.cpp',
'HttpBaseChannel.cpp',
'HttpChannelChild.cpp',
'HttpChannelParent.cpp',
@ -101,6 +107,7 @@ SOURCES += [
IPDL_SOURCES += [
'PAltDataOutputStream.ipdl',
'PHttpBackgroundChannel.ipdl',
'PHttpChannel.ipdl',
]

Просмотреть файл

@ -64,6 +64,7 @@
#include "nsIClassOfService.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsIScriptSecurityManager.h"
#include "nsISSLStatus.h"
#include "nsISSLStatusProvider.h"

Просмотреть файл

@ -5,11 +5,14 @@
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include <errno.h>
#include "nsHttpChunkedDecoder.h"
#include <algorithm>
#include "plstr.h"
#include "mozilla/Unused.h"
namespace mozilla {
namespace net {

Просмотреть файл

@ -33,6 +33,7 @@
#include "nsISocketTransportService.h"
#include <algorithm>
#include "mozilla/ChaosMode.h"
#include "mozilla/SizePrintfMacros.h"
#include "mozilla/Unused.h"
#include "nsIURI.h"

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- 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 "nsISupports.idl"
%{ C++
namespace mozilla {
namespace net {
class HttpBackgroundChannelParent;
class HttpChannelParent;
}
}
%}
[ptr] native HttpChannelParent(mozilla::net::HttpChannelParent);
[ptr] native HttpBackgroundChannelParent(mozilla::net::HttpBackgroundChannelParent);
/*
* Registrar for pairing HttpChannelParent and HttpBackgroundChannelParent via
* channel Id. HttpChannelParent::OnBackgroundParentReady and
* HttpBackgroundChannelParent::LinkToChannel will be invoked to notify the
* existence of associated channel object.
*/
[builtinclass, uuid(8acaa9b1-f0c4-4ade-baeb-39b0d4b96e5b)]
interface nsIBackgroundChannelRegistrar : nsISupports
{
/*
* Link the provided channel parent actor with the given channel Id.
* callbacks will be invoked immediately when the HttpBackgroundChannelParent
* associated with the same channel Id is found. Store the HttpChannelParent
* until a matched linkBackgroundChannel is invoked.
*
* @param aKey the channel Id
* @param aChannel the channel parent actor to be paired
*/
[noscript,notxpcom,nostdcall] void linkHttpChannel(in uint64_t aKey,
in HttpChannelParent aChannel);
/*
* Link the provided background channel with the given channel Id.
* callbacks will be invoked immediately when the HttpChannelParent associated
* with the same channel Id is found. Store the HttpBackgroundChannelParent
* until a matched linkHttpChannel is invoked.
*
* @param aKey the channel Id
* @param aBgChannel the background channel to be paired
*/
[noscript,notxpcom,nostdcall] void linkBackgroundChannel(in uint64_t aKey,
in HttpBackgroundChannelParent aBgChannel);
/*
* Delete previous stored HttpChannelParent or HttpBackgroundChannelParent
* if no need to wait for the paired channel object, e.g. background channel
* is destroyed before pairing is completed.
*
* @param aKey the channel Id
*/
[noscript,notxpcom,nostdcall] void deleteChannel(in uint64_t aKey);
};

Просмотреть файл

@ -60,6 +60,16 @@ ExtensionPreferencesManager.addSetting("network.networkPredictionEnabled", {
},
});
ExtensionPreferencesManager.addSetting("network.peerConnectionEnabled", {
prefNames: [
"media.peerconnection.enabled",
],
setCallback(value) {
return {[this.prefNames[0]]: value};
},
});
ExtensionPreferencesManager.addSetting("network.webRTCIPHandlingPolicy", {
prefNames: [
"media.peerconnection.ice.default_address_only",
@ -119,6 +129,11 @@ this.privacy = class extends ExtensionAPI {
Preferences.get("network.http.speculative-parallel-limit") > 0 &&
!Preferences.get("network.dns.disablePrefetch");
}),
peerConnectionEnabled: getAPI(extension,
"network.peerConnectionEnabled",
() => {
return Preferences.get("media.peerconnection.enabled");
}),
webRTCIPHandlingPolicy: getAPI(extension,
"network.webRTCIPHandlingPolicy",
() => {

Просмотреть файл

@ -38,6 +38,10 @@
"$ref": "types.Setting",
"description": "If enabled, the browser attempts to speed up your web browsing experience by pre-resolving DNS entries, prerendering sites (<code>&lt;link rel='prefetch' ...&gt;</code>), and preemptively opening TCP and SSL connections to servers. This preference's value is a boolean, defaulting to <code>true</code>."
},
"peerConnectionEnabled": {
"$ref": "types.Setting",
"description": "Allow users to enable and disable RTCPeerConnections (aka WebRTC)."
},
"webRTCIPHandlingPolicy": {
"$ref": "types.Setting",
"description": "Allow users to specify the media performance/privacy tradeoffs which impacts how WebRTC traffic will be routed and how much local address information is exposed. This preference's value is of type IPHandlingPolicy, defaulting to <code>default</code>."

Просмотреть файл

@ -214,46 +214,60 @@ add_task(async function test_privacy() {
await promiseShutdownManager();
});
add_task(async function test_privacy_webRTCIPHandlingPolicy() {
// Create a object to hold the default values of all the prefs.
const PREF_DEFAULTS = {
"media.peerconnection.ice.default_address_only": null,
"media.peerconnection.ice.no_host": null,
"media.peerconnection.ice.proxy_only": null,
// This test can be used for any settings that are added which utilize only
// boolean prefs.
add_task(async function test_privacy_boolean_prefs() {
// Create an object to hold the values to which we will initialize the prefs.
const SETTINGS = {
"network.webRTCIPHandlingPolicy": {
"media.peerconnection.ice.default_address_only": false,
"media.peerconnection.ice.no_host": false,
"media.peerconnection.ice.proxy_only": false,
},
"network.peerConnectionEnabled": {
"media.peerconnection.enabled": true,
},
};
// Store the default values of each pref.
for (let pref in PREF_DEFAULTS) {
PREF_DEFAULTS[pref] = ExtensionPreferencesManager.getDefaultValue(pref);
async function background() {
browser.test.onMessage.addListener(async (msg, ...args) => {
let data = args[0];
// The second argument is the end of the api name,
// e.g., "network.webRTCIPHandlingPolicy".
let apiObj = args[1].split(".").reduce((o, i) => o[i], browser.privacy);
let settingData;
switch (msg) {
case "set":
await apiObj.set(data);
settingData = await apiObj.get({});
browser.test.sendMessage("settingData", settingData);
break;
case "clear":
await apiObj.clear(data);
settingData = await apiObj.get({});
browser.test.sendMessage("settingData", settingData);
break;
}
});
}
// Set prefs to our initial values.
for (let setting in SETTINGS) {
for (let pref in SETTINGS[setting]) {
Preferences.set(pref, SETTINGS[setting][pref]);
}
}
do_register_cleanup(() => {
// Reset the prefs.
for (let pref in PREF_DEFAULTS) {
Preferences.reset(pref);
for (let setting in SETTINGS) {
for (let pref in SETTINGS[setting]) {
Preferences.reset(pref);
}
}
});
async function background() {
browser.test.onMessage.addListener(async (msg, value) => {
let rtcData;
switch (msg) {
case "set":
await browser.privacy.network.webRTCIPHandlingPolicy.set({value});
rtcData = await browser.privacy.network.webRTCIPHandlingPolicy.get({});
browser.test.sendMessage("rtcData", rtcData);
break;
case "clear":
await browser.privacy.network.webRTCIPHandlingPolicy.clear({});
rtcData = await browser.privacy.network.webRTCIPHandlingPolicy.get({});
browser.test.sendMessage("rtcData", rtcData);
break;
}
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
@ -265,33 +279,35 @@ add_task(async function test_privacy_webRTCIPHandlingPolicy() {
await promiseStartupManager();
await extension.startup();
async function testSetting(value, truePrefs) {
extension.sendMessage("set", value);
let data = await extension.awaitMessage("rtcData");
async function testSetting(setting, value, truePrefs) {
extension.sendMessage("set", {value: value}, setting);
let data = await extension.awaitMessage("settingData");
equal(data.value, value);
for (let pref in PREF_DEFAULTS) {
for (let pref in SETTINGS[setting]) {
let prefValue = Preferences.get(pref);
if (truePrefs.includes(pref)) {
ok(prefValue, `${pref} set correctly for ${value}`);
} else {
equal(prefValue, PREF_DEFAULTS[pref], `${pref} contains default value for ${value}`);
}
equal(prefValue, truePrefs.includes(pref), `${pref} set correctly for ${value}`);
}
}
await testSetting(
"network.webRTCIPHandlingPolicy",
"default_public_and_private_interfaces",
["media.peerconnection.ice.default_address_only"]);
await testSetting(
"network.webRTCIPHandlingPolicy",
"default_public_interface_only",
["media.peerconnection.ice.default_address_only", "media.peerconnection.ice.no_host"]);
await testSetting(
"network.webRTCIPHandlingPolicy",
"disable_non_proxied_udp",
["media.peerconnection.ice.proxy_only"]);
await testSetting("default", []);
await testSetting("network.webRTCIPHandlingPolicy", "default", []);
await testSetting("network.peerConnectionEnabled", false, []);
await testSetting("network.peerConnectionEnabled", true, ["media.peerconnection.enabled"]);
await extension.unload();

Просмотреть файл

@ -49,7 +49,6 @@ ContentProcessSingleton.prototype = {
case "app-startup": {
Services.obs.addObserver(this, "console-api-log-event");
Services.obs.addObserver(this, "xpcom-shutdown");
cpmm.addMessageListener("DevTools:InitDebuggerServer", this);
TelemetryController.observe(null, topic, null);
break;
}
@ -103,19 +102,9 @@ ContentProcessSingleton.prototype = {
case "xpcom-shutdown":
Services.obs.removeObserver(this, "console-api-log-event");
Services.obs.removeObserver(this, "xpcom-shutdown");
cpmm.removeMessageListener("DevTools:InitDebuggerServer", this);
break;
}
},
receiveMessage(message) {
// load devtools component on-demand
// Only reply if we are in a real content process
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
let {init} = Cu.import("resource://devtools/server/content-server.jsm", {});
init(message);
}
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentProcessSingleton]);

Просмотреть файл

@ -517,6 +517,7 @@ STUB(gdk_display_get_device_manager)
STUB(gdk_error_trap_pop_ignored)
STUB(gdk_event_get_source_device)
STUB(gdk_window_get_type)
STUB(gdk_window_get_window_type)
STUB(gdk_x11_window_get_xid)
STUB(gdk_x11_display_get_type)
STUB(gtk_box_new)

Просмотреть файл

@ -220,6 +220,8 @@ static void theme_changed_cb (GtkSettings *settings,
nsWindow *data);
static void check_resize_cb (GtkContainer* container,
gpointer user_data);
static void composited_changed_cb (GtkWidget* widget,
gpointer user_data);
#if (MOZ_WIDGET_GTK == 3)
static void scale_changed_cb (GtkWidget* widget,
@ -3369,6 +3371,19 @@ nsWindow::OnCheckResize()
mPendingConfigures++;
}
void
nsWindow::OnCompositedChanged()
{
if (mWidgetListener) {
nsIPresShell* presShell = mWidgetListener->GetPresShell();
if (presShell) {
// Update CSD after the change in alpha visibility
presShell->ThemeChanged();
}
}
CleanLayerManagerRecursive();
}
void
nsWindow::DispatchDragEvent(EventMessage aMsg, const LayoutDeviceIntPoint& aRefPoint,
guint aTime)
@ -3604,6 +3619,31 @@ nsWindow::Create(nsIWidget* aParent,
GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP;
mShell = gtk_window_new(type);
bool useAlphaVisual = (mWindowType == eWindowType_popup &&
aInitData->mSupportTranslucency);
// mozilla.widget.use-argb-visuals is a hidden pref defaulting to false
// to allow experimentation
if (Preferences::GetBool("mozilla.widget.use-argb-visuals", false))
useAlphaVisual = true;
// We need to select an ARGB visual here instead of in
// SetTransparencyMode() because it has to be done before the
// widget is realized. An ARGB visual is only useful if we
// are on a compositing window manager.
if (useAlphaVisual) {
GdkScreen *screen = gtk_widget_get_screen(mShell);
if (gdk_screen_is_composited(screen)) {
#if (MOZ_WIDGET_GTK == 2)
GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
gtk_widget_set_colormap(mShell, colormap);
#else
GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
gtk_widget_set_visual(mShell, visual);
#endif
}
}
// We only move a general managed toplevel window if someone has
// actually placed the window somewhere. If no placement has taken
// place, we just let the window manager Do The Right Thing.
@ -3627,23 +3667,6 @@ nsWindow::Create(nsIWidget* aParent,
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup",
gdk_get_program_class());
if (aInitData->mSupportTranslucency) {
// We need to select an ARGB visual here instead of in
// SetTransparencyMode() because it has to be done before the
// widget is realized. An ARGB visual is only useful if we
// are on a compositing window manager.
GdkScreen *screen = gtk_widget_get_screen(mShell);
if (gdk_screen_is_composited(screen)) {
#if (MOZ_WIDGET_GTK == 2)
GdkColormap *colormap =
gdk_screen_get_rgba_colormap(screen);
gtk_widget_set_colormap(mShell, colormap);
#else
GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
gtk_widget_set_visual(mShell, visual);
#endif
}
}
if (aInitData->mNoAutoHide) {
// ... but the window manager does not decorate this window,
// nor provide a separate taskbar icon.
@ -3829,6 +3852,8 @@ nsWindow::Create(nsIWidget* aParent,
G_CALLBACK(window_state_event_cb), nullptr);
g_signal_connect(mShell, "check-resize",
G_CALLBACK(check_resize_cb), nullptr);
g_signal_connect(mShell, "composited-changed",
G_CALLBACK(composited_changed_cb), nullptr);
GtkSettings* default_settings = gtk_settings_get_default();
g_signal_connect_after(default_settings,
@ -4345,6 +4370,33 @@ nsWindow::GetTransparencyMode()
return mIsTransparent ? eTransparencyTransparent : eTransparencyOpaque;
}
#if (MOZ_WIDGET_GTK >= 3)
void nsWindow::UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion)
{
// Available as of GTK 3.10+
static auto sGdkWindowSetOpaqueRegion =
(void (*)(GdkWindow*, cairo_region_t*))
dlsym(RTLD_DEFAULT, "gdk_window_set_opaque_region");
if (sGdkWindowSetOpaqueRegion && mGdkWindow &&
gdk_window_get_window_type(mGdkWindow) == GDK_WINDOW_TOPLEVEL) {
if (aOpaqueRegion.IsEmpty()) {
(*sGdkWindowSetOpaqueRegion)(mGdkWindow, nullptr);
} else {
cairo_region_t *region = cairo_region_create();
for (auto iter = aOpaqueRegion.RectIter(); !iter.Done();
iter.Next()) {
const LayoutDeviceIntRect &r = iter.Get();
cairo_rectangle_int_t rect = { r.x, r.y, r.width, r.height };
cairo_region_union_rectangle(region, &rect);
}
(*sGdkWindowSetOpaqueRegion)(mGdkWindow, region);
cairo_region_destroy(region);
}
}
}
#endif
nsresult
nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
@ -5836,6 +5888,16 @@ check_resize_cb (GtkContainer* container, gpointer user_data)
window->OnCheckResize();
}
static void
composited_changed_cb (GtkWidget* widget, gpointer user_data)
{
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
return;
}
window->OnCompositedChanged();
}
#if (MOZ_WIDGET_GTK == 3)
static void
scale_changed_cb (GtkWidget* widget, GParamSpec* aPSpec, gpointer aPointer)
@ -6436,7 +6498,10 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
// during shutdown. Just return what we currently have, which is most likely null.
return mLayerManager;
}
if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) {
if (!mLayerManager &&
eTransparencyTransparent == GetTransparencyMode())
{
mLayerManager = CreateBasicLayerManager();
}
@ -6745,3 +6810,17 @@ void nsWindow::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInit
GetClientSize());
#endif
}
bool
nsWindow::IsComposited() const
{
if (!mGdkWindow) {
NS_WARNING("nsWindow::HasARGBVisual called before realization!");
return false;
}
GdkScreen* gdkScreen = gdk_screen_get_default();
return gdk_screen_is_composited(gdkScreen) &&
(gdk_window_get_visual(mGdkWindow)
== gdk_screen_get_rgba_visual(gdkScreen));
}

Просмотреть файл

@ -251,6 +251,7 @@ public:
void ThemeChanged(void);
void OnDPIChanged(void);
void OnCheckResize(void);
void OnCompositedChanged(void);
#ifdef MOZ_X11
Window mOldFocusWindow;
@ -307,6 +308,9 @@ public:
virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
virtual nsTransparencyMode GetTransparencyMode() override;
#if (MOZ_WIDGET_GTK >= 3)
virtual void UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion) override;
#endif
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
nsresult UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
uint8_t* aAlphas, int32_t aStride);
@ -430,6 +434,8 @@ private:
gint* aRootX, gint* aRootY);
void ClearCachedResources();
nsIWidgetListener* GetListener();
bool IsComposited() const;
GtkWidget *mShell;
MozContainer *mContainer;