Bug 1326298 implement off-main-thread delivery with start/stop/error listeners, r=kmag

MozReview-Commit-ID: Ke4NsthrbP2

--HG--
extra : rebase_source : 0324030e5f7f534256ff0c469bb486dc52e282c2
This commit is contained in:
Shane Caraveo 2017-04-18 15:50:53 -07:00
parent 150742ba74
commit f6660740ac
11 changed files with 182 additions and 18 deletions

View File

@ -330,6 +330,7 @@
@RESPATH@/components/urlformatter.xpt
@RESPATH@/components/webBrowser_core.xpt
@RESPATH@/components/webbrowserpersist.xpt
@RESPATH@/components/webextensions.xpt
@RESPATH@/components/widget.xpt
#ifdef XP_MACOSX
@RESPATH@/components/widget_cocoa.xpt

View File

@ -241,6 +241,7 @@
@BINPATH@/components/urlformatter.xpt
@BINPATH@/components/webBrowser_core.xpt
@BINPATH@/components/webbrowserpersist.xpt
@BINPATH@/components/webextensions.xpt
@BINPATH@/components/widget.xpt
@BINPATH@/components/widget_android.xpt
@BINPATH@/components/windowcreator.xpt

View File

@ -44,6 +44,8 @@
#include "NativeFileWatcherNotSupported.h"
#endif // (XP_WIN)
#include "nsWebRequestListener.h"
#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
#define MOZ_HAS_TERMINATOR
#endif
@ -125,6 +127,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebRequestListener)
NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID);
#if defined(MOZ_HAS_PERFSTATS)
NS_DEFINE_NAMED_CID(NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID);
@ -158,6 +162,7 @@ NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID);
NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID);
NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_WEBREQUESTLISTENER_CID);
static const Module::CIDEntry kToolkitCIDs[] = {
{ &kNS_TOOLKIT_APPSTARTUP_CID, false, nullptr, nsAppStartupConstructor },
@ -192,6 +197,7 @@ static const Module::CIDEntry kToolkitCIDs[] = {
{ &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor },
{ &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor },
{ &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor },
{ &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor },
{ nullptr }
};
@ -228,6 +234,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
{ NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID },
{ NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID },
{ NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID },
{ NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID },
{ nullptr }
};

View File

@ -39,7 +39,10 @@ TESTING_JS_MODULES += [
'ExtensionXPCShellUtils.jsm',
]
DIRS += ['schemas']
DIRS += [
'schemas',
'webrequest',
]
JAR_MANIFESTS += ['jar.mn']

View File

@ -5,7 +5,9 @@
<meta charset="utf-8">
<script>
"use strict";
window.close();
window.onload = () => {
window.close();
};
</script>
</head>
</html>

View File

@ -239,7 +239,7 @@ add_task(function* test_webRequest_tabId() {
};
extension.sendMessage("set-expected", {expect, origin: location.href});
yield extension.awaitMessage("continue");
let a = addLink("file_WebRequest_page3.html?trigger=a");
let a = addLink(`file_WebRequest_page3.html?trigger=a&nocache=${Math.random()}`);
a.click();
yield extension.awaitMessage("done");
});

View File

@ -0,0 +1,21 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
XPIDL_SOURCES += [
'nsIWebRequestListener.idl',
]
XPIDL_MODULE = 'webextensions'
EXPORTS += [
'nsWebRequestListener.h',
]
UNIFIED_SOURCES += [
'nsWebRequestListener.cpp',
]
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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"
#include "nsIStreamListener.idl"
#include "nsITraceableChannel.idl"
/* nsIWebRequestListener is a nsIThreadRetargetableStreamListener that handles
* forwarding of nsIRequestObserver for JS consumers. nsIWebRequestListener
* is not cycle collected, JS consumers should not keep a reference to this.
*/
[scriptable, uuid(699a50bb-1f18-2844-b9ea-9f216f62cb18)]
interface nsIWebRequestListener : nsISupports
{
void init(in nsIStreamListener aStreamListener,
in nsITraceableChannel aTraceableChannel);
};
%{C++
/* ebea9901-e135-b546-82e2-052666992dbb */
#define NS_WEBREQUESTLISTENER_CID \
{0xebea9901, 0xe135, 0xb546, \
{0x82, 0xe2, 0x05, 0x26, 0x66, 0x99, 0x2d, 0xbb} }
#define NS_WEBREQUESTLISTENER_CONTRACTID "@mozilla.org/webextensions/webRequestListener;1"
%}

View File

@ -0,0 +1,74 @@
/* 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 "mozilla/ModuleUtils.h"
#include "nsWebRequestListener.h"
#ifdef DEBUG
#include "MainThreadUtils.h"
#endif
using namespace mozilla;
NS_IMPL_ISUPPORTS(nsWebRequestListener,
nsIWebRequestListener,
nsIStreamListener,
nsIRequestObserver,
nsIThreadRetargetableStreamListener)
NS_IMETHODIMP
nsWebRequestListener::Init(nsIStreamListener *aStreamListener, nsITraceableChannel *aTraceableChannel)
{
MOZ_ASSERT(aStreamListener, "Should have aStreamListener");
MOZ_ASSERT(aTraceableChannel, "Should have aTraceableChannel");
mTargetStreamListener = aStreamListener;
return aTraceableChannel->SetNewListener(this, getter_AddRefs(mOrigStreamListener));
}
NS_IMETHODIMP
nsWebRequestListener::OnStartRequest(nsIRequest *request, nsISupports * aCtxt)
{
MOZ_ASSERT(mTargetStreamListener, "Should have mTargetStreamListener");
MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
nsresult rv = mTargetStreamListener->OnStartRequest(request, aCtxt);
NS_ENSURE_SUCCESS(rv, rv);
return mOrigStreamListener->OnStartRequest(request, aCtxt);
}
NS_IMETHODIMP
nsWebRequestListener::OnStopRequest(nsIRequest *request, nsISupports *aCtxt,
nsresult aStatus)
{
MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
MOZ_ASSERT(mTargetStreamListener, "Should have mTargetStreamListener");
nsresult rv = mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus);
NS_ENSURE_SUCCESS(rv, rv);
return mTargetStreamListener->OnStopRequest(request, aCtxt, aStatus);
}
NS_IMETHODIMP
nsWebRequestListener::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
nsIInputStream * inStr,
uint64_t sourceOffset, uint32_t count)
{
MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
return mOrigStreamListener->OnDataAvailable(request, aCtxt, inStr, sourceOffset, count);
}
NS_IMETHODIMP
nsWebRequestListener::CheckListenerChain()
{
MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!");
nsresult rv;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(mOrigStreamListener, &rv);
if (retargetableListener) {
return retargetableListener->CheckListenerChain();
}
return rv;
}

View File

@ -0,0 +1,36 @@
/* 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 nsWebRequestListener_h__
#define nsWebRequestListener_h__
#include "nsCOMPtr.h"
#include "nsIWebRequestListener.h"
#include "nsIRequestObserver.h"
#include "nsIStreamListener.h"
#include "nsITraceableChannel.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "mozilla/Attributes.h"
class nsWebRequestListener final : public nsIWebRequestListener
, public nsIStreamListener
, public nsIThreadRetargetableStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBREQUESTLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
nsWebRequestListener() {}
private:
~nsWebRequestListener() {}
nsCOMPtr<nsIStreamListener> mOrigStreamListener;
nsCOMPtr<nsIStreamListener> mTargetStreamListener;
};
#endif // nsWebRequestListener_h__

View File

@ -30,6 +30,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebRequestUpload",
XPCOMUtils.defineLazyGetter(this, "ExtensionError", () => ExtensionUtils.ExtensionError);
let WebRequestListener = Components.Constructor("@mozilla.org/webextensions/webRequestListener;1",
"nsIWebRequestListener", "init");
function attachToChannel(channel, key, data) {
if (channel instanceof Ci.nsIWritablePropertyBag2) {
let wrapper = {wrappedJSObject: data};
@ -326,10 +329,10 @@ var ContentPolicyManager = {
};
ContentPolicyManager.init();
function StartStopListener(manager, loadContext) {
function StartStopListener(manager, channel, loadContext) {
this.manager = manager;
this.loadContext = loadContext;
this.orig = null;
new WebRequestListener(this, channel);
}
StartStopListener.prototype = {
@ -338,21 +341,11 @@ StartStopListener.prototype = {
onStartRequest: function(request, context) {
this.manager.onStartRequest(request, this.loadContext);
this.orig.onStartRequest(request, context);
},
onStopRequest(request, context, statusCode) {
try {
this.orig.onStopRequest(request, context, statusCode);
} catch (e) {
Cu.reportError(e);
}
this.manager.onStopRequest(request, this.loadContext);
},
onDataAvailable(...args) {
return this.orig.onDataAvailable(...args);
},
};
var ChannelEventSink = {
@ -1000,9 +993,7 @@ HttpObserverManager = {
let responseStatus = channel.responseStatus;
// skip redirections, https://bugzilla.mozilla.org/show_bug.cgi?id=728901#c8
if (responseStatus < 300 || responseStatus >= 400) {
let listener = new StartStopListener(this, loadContext);
let orig = channel.setNewListener(listener);
listener.orig = orig;
new StartStopListener(this, channel, loadContext);
channelData.hasListener = true;
}
}