mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1186290 - Notify TabParent to switch process when loading a signed package. r=honzab, r=kanru.
This commit is contained in:
parent
a85371cccc
commit
82e53ac666
@ -108,6 +108,12 @@ using namespace mozilla::services;
|
||||
using namespace mozilla::widget;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
#if DEUBG
|
||||
#define LOG(args...) printf_stderr(args)
|
||||
#else
|
||||
#define LOG(...)
|
||||
#endif
|
||||
|
||||
// The flags passed by the webProgress notifications are 16 bits shifted
|
||||
// from the ones registered by webProgressListeners.
|
||||
#define NOTIFY_FLAG_SHIFT 16
|
||||
@ -437,6 +443,104 @@ TabParent::IsVisible()
|
||||
return visible;
|
||||
}
|
||||
|
||||
static void LogChannelRelevantInfo(nsIURI* aURI,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
nsIPrincipal* aChannelResultPrincipal,
|
||||
nsContentPolicyType aContentPolicyType) {
|
||||
nsCString loadingOrigin;
|
||||
aLoadingPrincipal->GetOrigin(loadingOrigin);
|
||||
|
||||
nsCString uriString;
|
||||
aURI->GetAsciiSpec(uriString);
|
||||
LOG("Loading %s from origin %s (type: %d)\n", uriString.get(),
|
||||
loadingOrigin.get(),
|
||||
aContentPolicyType);
|
||||
|
||||
nsCString resultPrincipalOrigin;
|
||||
aChannelResultPrincipal->GetOrigin(resultPrincipalOrigin);
|
||||
LOG("Result principal origin: %s\n", resultPrincipalOrigin.get());
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::ShouldSwitchProcess(nsIChannel* aChannel)
|
||||
{
|
||||
// If we lack of any information which is required to decide the need of
|
||||
// process switch, consider that we should switch process.
|
||||
|
||||
// Prepare the channel loading principal.
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
NS_ENSURE_TRUE(loadInfo, true);
|
||||
nsCOMPtr<nsIPrincipal> loadingPrincipal;
|
||||
loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal));
|
||||
NS_ENSURE_TRUE(loadingPrincipal, true);
|
||||
|
||||
// Prepare the channel result principal.
|
||||
nsCOMPtr<nsIPrincipal> resultPrincipal;
|
||||
nsContentUtils::GetSecurityManager()->
|
||||
GetChannelResultPrincipal(aChannel, getter_AddRefs(resultPrincipal));
|
||||
|
||||
// Log the debug info which is used to decide the need of proces switch.
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aChannel->GetURI(getter_AddRefs(uri));
|
||||
LogChannelRelevantInfo(uri, loadingPrincipal, resultPrincipal,
|
||||
loadInfo->GetContentPolicyType());
|
||||
|
||||
// Check if the signed package is loaded from the same origin.
|
||||
bool sameOrigin = false;
|
||||
loadingPrincipal->Equals(resultPrincipal, &sameOrigin);
|
||||
if (sameOrigin) {
|
||||
LOG("Loading singed package from the same origin. Don't switch process.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is not a top level document, there's no need to switch process.
|
||||
if (nsIContentPolicy::TYPE_DOCUMENT != loadInfo->GetContentPolicyType()) {
|
||||
LOG("Subresource of a document. No need to switch process.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a brand new process created to load the signed package
|
||||
// (triggered by previous OnStartSignedPackageRequest), the loading origin
|
||||
// will be "moz-safe-about:blank". In that case, we don't need to switch process
|
||||
// again. We compare with "moz-safe-about:blank" without appId/isBrowserElement/etc
|
||||
// taken into account. That's why we use originNoSuffix.
|
||||
nsCString loadingOriginNoSuffix;
|
||||
loadingPrincipal->GetOriginNoSuffix(loadingOriginNoSuffix);
|
||||
if (loadingOriginNoSuffix.EqualsLiteral("moz-safe-about:blank")) {
|
||||
LOG("The content is already loaded by a brand new process.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::OnStartSignedPackageRequest(nsIChannel* aChannel)
|
||||
{
|
||||
if (!ShouldSwitchProcess(aChannel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aChannel->GetURI(getter_AddRefs(uri));
|
||||
|
||||
aChannel->Cancel(NS_BINDING_FAILED);
|
||||
|
||||
nsCString uriString;
|
||||
uri->GetAsciiSpec(uriString);
|
||||
LOG("We decide to switch process. Call nsFrameLoader::SwitchProcessAndLoadURIs: %s\n",
|
||||
uriString.get());
|
||||
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
NS_ENSURE_TRUE_VOID(frameLoader);
|
||||
|
||||
nsresult rv = frameLoader->SwitchProcessAndLoadURI(uri);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to switch process.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::DestroyInternal()
|
||||
{
|
||||
|
@ -442,6 +442,10 @@ public:
|
||||
int32_t& aDragAreaX, int32_t& aDragAreaY);
|
||||
layout::RenderFrameParent* GetRenderFrame();
|
||||
|
||||
// Called by HttpChannelParent. The function may use a new process to
|
||||
// reload the URI associated with the given channel.
|
||||
void OnStartSignedPackageRequest(nsIChannel* aChannel);
|
||||
|
||||
protected:
|
||||
bool ReceiveMessage(const nsString& aMessage,
|
||||
bool aSync,
|
||||
@ -482,6 +486,10 @@ protected:
|
||||
|
||||
void SetHasContentOpener(bool aHasContentOpener);
|
||||
|
||||
// Decide whether we have to use a new process to reload the URI associated
|
||||
// with the given channel.
|
||||
bool ShouldSwitchProcess(nsIChannel* aChannel);
|
||||
|
||||
ContentCacheInParent mContentCache;
|
||||
|
||||
nsIntRect mRect;
|
||||
|
@ -69,6 +69,7 @@ XPIDL_SOURCES += [
|
||||
'nsINSSErrorsService.idl',
|
||||
'nsINullChannel.idl',
|
||||
'nsIPACGenerator.idl',
|
||||
'nsIPackagedAppChannelListener.idl',
|
||||
'nsIPackagedAppService.idl',
|
||||
'nsIPackagedAppUtils.idl',
|
||||
'nsIPackagedAppVerifier.idl',
|
||||
|
25
netwerk/base/nsIPackagedAppChannelListener.idl
Normal file
25
netwerk/base/nsIPackagedAppChannelListener.idl
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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"
|
||||
|
||||
/**
|
||||
* nsIPackagedAppChannelListener
|
||||
*/
|
||||
[scriptable, uuid(27caf7d0-3c0e-11e5-b970-0800200c9a66)]
|
||||
interface nsIPackagedAppChannelListener : nsISupports
|
||||
{
|
||||
/**
|
||||
* @param aPackageId
|
||||
* the package identifier of the signed package that we are going
|
||||
* to load. The identifier will be defined in the manifest of the
|
||||
* package.
|
||||
*
|
||||
* This callback is to notify a signed package is about to load. Some
|
||||
* component else will be in charge of responding to this fact properly.
|
||||
* The procotol layer should have no idea what to do with this.
|
||||
*
|
||||
*/
|
||||
void onStartSignedPackageRequest(in ACString aPackageId);
|
||||
};
|
@ -154,6 +154,7 @@ NS_IMPL_ISUPPORTS(HttpChannelParent,
|
||||
nsIProgressEventSink,
|
||||
nsIRequestObserver,
|
||||
nsIStreamListener,
|
||||
nsIPackagedAppChannelListener,
|
||||
nsIParentChannel,
|
||||
nsIAuthPromptProvider,
|
||||
nsIParentRedirectingChannel,
|
||||
@ -1036,6 +1037,19 @@ HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(const URIParams& uri,
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelParent::nsIPackagedAppChannelListener
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelParent::OnStartSignedPackageRequest(const nsACString& aPackageId)
|
||||
{
|
||||
if (mTabParent) {
|
||||
mTabParent->OnStartSignedPackageRequest(mChannel);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelParent::nsIRequestObserver
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIDeprecationWarner.h"
|
||||
#include "nsIPackagedAppChannelListener.h"
|
||||
|
||||
class nsICacheEntry;
|
||||
class nsIAssociatedContentSecurity;
|
||||
@ -46,6 +47,7 @@ class HttpChannelParent final : public PHttpChannelParent
|
||||
, public nsINetworkInterceptController
|
||||
, public nsIDeprecationWarner
|
||||
, public DisconnectableParent
|
||||
, public nsIPackagedAppChannelListener
|
||||
, public HttpChannelSecurityWarningReporter
|
||||
{
|
||||
virtual ~HttpChannelParent();
|
||||
@ -54,6 +56,7 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPACKAGEDAPPCHANNELLISTENER
|
||||
NS_DECL_NSIPARENTCHANNEL
|
||||
NS_DECL_NSIPARENTREDIRECTINGCHANNEL
|
||||
NS_DECL_NSIPROGRESSEVENTSINK
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsIRedirectChannelRegistrar.h"
|
||||
#include "nsIHttpEventSink.h"
|
||||
#include "nsIPackagedAppChannelListener.h"
|
||||
|
||||
using mozilla::unused;
|
||||
|
||||
@ -38,6 +39,7 @@ NS_IMPL_ISUPPORTS(HttpChannelParentListener,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver,
|
||||
nsIChannelEventSink,
|
||||
nsIPackagedAppChannelListener,
|
||||
nsIRedirectResultListener)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -97,6 +99,22 @@ HttpChannelParentListener::OnDataAvailable(nsIRequest *aRequest,
|
||||
return mNextListener->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelParentListener::nsIPackagedAppChannelListener
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
HttpChannelParentListener::OnStartSignedPackageRequest(const nsACString& aPackageId)
|
||||
{
|
||||
nsCOMPtr<nsIPackagedAppChannelListener> listener = do_QueryInterface(mNextListener);
|
||||
if (listener) {
|
||||
listener->OnStartSignedPackageRequest(aPackageId);
|
||||
} else {
|
||||
NS_WARNING("mNextListener is not nsIPackagedAppChannelListener");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelParentListener::nsIInterfaceRequestor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIRedirectResultListener.h"
|
||||
#include "nsIPackagedAppChannelListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@ -20,12 +21,14 @@ class HttpChannelParent;
|
||||
class HttpChannelParentListener final : public nsIInterfaceRequestor
|
||||
, public nsIChannelEventSink
|
||||
, public nsIRedirectResultListener
|
||||
, public nsIPackagedAppChannelListener
|
||||
, public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSIPACKAGEDAPPCHANNELLISTENER
|
||||
NS_DECL_NSIREDIRECTRESULTLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
@ -726,7 +726,8 @@ PackagedAppService::PackagedAppDownloader::OnDataAvailable(nsIRequest *aRequest,
|
||||
|
||||
nsresult
|
||||
PackagedAppService::PackagedAppDownloader::AddCallback(nsIURI *aURI,
|
||||
nsICacheEntryOpenCallback *aCallback)
|
||||
nsICacheEntryOpenCallback *aCallback,
|
||||
nsIChannel* aRequester)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mCallbacks hashtable is not thread safe");
|
||||
nsAutoCString spec;
|
||||
@ -735,6 +736,8 @@ PackagedAppService::PackagedAppDownloader::AddCallback(nsIURI *aURI,
|
||||
LogURI("PackagedAppDownloader::AddCallback", this, aURI);
|
||||
LOG(("[%p] > callback: %p\n", this, aCallback));
|
||||
|
||||
nsCOMPtr<nsIPackagedAppChannelListener> listener = do_QueryInterface(aRequester);
|
||||
|
||||
// Check if we already have a resource waiting for this resource
|
||||
nsCOMArray<nsICacheEntryOpenCallback>* array = mCallbacks.Get(spec);
|
||||
if (array) {
|
||||
@ -746,9 +749,12 @@ PackagedAppService::PackagedAppDownloader::AddCallback(nsIURI *aURI,
|
||||
|
||||
// This is the case where a package downloader is still running and we
|
||||
// peek data from it.
|
||||
|
||||
// TODO: Bug 1186290 to notify that the signed packaged content is ready
|
||||
// to load.
|
||||
if (mVerifier && mVerifier->GetIsPackageSigned()) {
|
||||
// TODO: Bug 1178526 will deal with the package identifier things.
|
||||
// For now we just use the origin as the identifier.
|
||||
listener->OnStartSignedPackageRequest(mVerifier->GetPackageOrigin());
|
||||
listener = nullptr; // So that the request will not be added to the queue.
|
||||
}
|
||||
mCacheStorage->AsyncOpenURI(aURI, EmptyCString(),
|
||||
nsICacheStorage::OPEN_READONLY, aCallback);
|
||||
} else {
|
||||
@ -765,6 +771,12 @@ PackagedAppService::PackagedAppDownloader::AddCallback(nsIURI *aURI,
|
||||
newArray->AppendObject(aCallback);
|
||||
mCallbacks.Put(spec, newArray);
|
||||
}
|
||||
|
||||
// Add the outer channel for notifying OnStartSignedPackageRequest.
|
||||
if (listener) {
|
||||
mRequesters.AppendObject(listener);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -859,9 +871,19 @@ PackagedAppService::PackagedAppDownloader::ClearCallbacks(nsresult aResult)
|
||||
void
|
||||
PackagedAppService::PackagedAppDownloader::NotifyOnStartSignedPackageRequest(const nsACString& aPackageOrigin)
|
||||
{
|
||||
// TODO: Bug 1186290 to notify whoever wants to know when the signed package is
|
||||
// about to load.
|
||||
LOG(("Notifying the signed package is ready to load."));
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mRequesters is not thread safe");
|
||||
|
||||
LOG(("Ready to notify OnStartSignedPackageRequest to all requesters."));
|
||||
// Notify all requesters that a signed package is about to download and let
|
||||
// TabParent to decide if the request needs to be re-made in a new process.
|
||||
for (uint32_t i = 0; i < mRequesters.Length(); i++) {
|
||||
nsCOMPtr<nsIPackagedAppChannelListener> requester = mRequesters.ObjectAt(i);
|
||||
LOG(("Notifying %p OnStartSignedPackageRequest. New origin: %s", requester.get(),
|
||||
nsCString(aPackageOrigin).get()));
|
||||
requester->OnStartSignedPackageRequest(aPackageOrigin);
|
||||
}
|
||||
|
||||
mRequesters.Clear();
|
||||
}
|
||||
|
||||
void PackagedAppService::PackagedAppDownloader::InstallSignedPackagedApp(const ResourceCacheInfo* aInfo)
|
||||
@ -965,6 +987,15 @@ PackagedAppService::PackagedAppDownloader::OnResourceVerified(const ResourceCach
|
||||
return OnError(ERROR_RESOURCE_VERIFIED_FAILED);
|
||||
}
|
||||
|
||||
// If this package is signed and there is any pending requests, we just notify
|
||||
// right now no matter if this is the requested resource. Doing this can
|
||||
// have the potential process switch be done as early as possible.
|
||||
if (mVerifier->GetIsPackageSigned()) {
|
||||
// TODO: Bug 1178526 will deal with the package identifier things.
|
||||
// For now we just use the origin as the identifier.
|
||||
NotifyOnStartSignedPackageRequest(mVerifier->GetPackageOrigin());
|
||||
}
|
||||
|
||||
// Serve this resource to all listeners.
|
||||
CallCallbacks(aInfo->mURI, aInfo->mCacheEntry, aInfo->mStatusCode);
|
||||
|
||||
@ -1096,8 +1127,7 @@ PackagedAppService::GetResource(nsIChannel *aChannel,
|
||||
// If we find that the package that the file belongs to is currently being
|
||||
// downloaded, we will add the callback to the package's queue, and it will
|
||||
// be called once the file is processed and saved in the cache.
|
||||
|
||||
downloader->AddCallback(uri, aCallback);
|
||||
downloader->AddCallback(uri, aCallback, aChannel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1127,7 +1157,7 @@ PackagedAppService::GetResource(nsIChannel *aChannel,
|
||||
return rv;
|
||||
}
|
||||
|
||||
downloader->AddCallback(uri, aCallback);
|
||||
downloader->AddCallback(uri, aCallback, aChannel);
|
||||
|
||||
nsCOMPtr<nsIStreamConverterService> streamconv =
|
||||
do_GetService("@mozilla.org/streamConverters;1", &rv);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "PackagedAppVerifier.h"
|
||||
#include "nsIMultiPartChannel.h"
|
||||
#include "PackagedAppVerifier.h"
|
||||
#include "nsIPackagedAppChannelListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@ -124,7 +125,10 @@ private:
|
||||
const nsACString& aPackageOrigin);
|
||||
// Registers a callback which gets called when the given nsIURI is downloaded
|
||||
// aURI is the full URI of a subresource, composed of packageURI + !// + subresourcePath
|
||||
nsresult AddCallback(nsIURI *aURI, nsICacheEntryOpenCallback *aCallback);
|
||||
// aRequester is the outer channel who makes the request for aURI.
|
||||
nsresult AddCallback(nsIURI *aURI,
|
||||
nsICacheEntryOpenCallback *aCallback,
|
||||
nsIChannel* aRequester);
|
||||
|
||||
// Remove the callback from the resource callback list.
|
||||
nsresult RemoveCallbacks(nsICacheEntryOpenCallback* aCallback);
|
||||
@ -209,6 +213,9 @@ private:
|
||||
// Deal with verification and delegate callbacks to the downloader.
|
||||
nsRefPtr<PackagedAppVerifier> mVerifier;
|
||||
|
||||
// The outer channels which have issued the request to the downloader.
|
||||
nsCOMArray<nsIPackagedAppChannelListener> mRequesters;
|
||||
|
||||
// The package origin without signed package origin identifier.
|
||||
// If you need the origin with the signity taken into account, use
|
||||
// PackagedAppVerifier::GetPackageOrigin().
|
||||
|
@ -104,6 +104,16 @@ public:
|
||||
// Used to explicitly clear the listener to avoid circula reference.
|
||||
void ClearListener() { mListener = nullptr; }
|
||||
|
||||
bool GetIsPackageSigned() const
|
||||
{
|
||||
return mIsPackageSigned;
|
||||
}
|
||||
|
||||
const nsACString& GetPackageOrigin() const
|
||||
{
|
||||
return mPackageOrigin;
|
||||
}
|
||||
|
||||
static const char* kSignedPakOriginMetadataKey;
|
||||
|
||||
private:
|
||||
|
@ -4853,6 +4853,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPackagedAppChannelListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICachingChannel)
|
||||
@ -5662,6 +5663,25 @@ nsHttpChannel::GetRequestMethod(nsACString& aMethod)
|
||||
return HttpBaseChannel::GetRequestMethod(aMethod);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIPackagedAppChannelListener
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::OnStartSignedPackageRequest(const nsACString& aPackageId)
|
||||
{
|
||||
nsCOMPtr<nsIPackagedAppChannelListener> listener;
|
||||
NS_QueryNotificationCallbacks(this, listener);
|
||||
|
||||
if (listener) {
|
||||
listener->OnStartSignedPackageRequest(aPackageId);
|
||||
} else {
|
||||
LOG(("nsHttpChannel::OnStartSignedPackageRequest [this=%p], no listener on %p", this, mListener.get()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIRequestObserver
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "HttpBaseChannel.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIPackagedAppChannelListener.h"
|
||||
#include "nsICachingChannel.h"
|
||||
#include "nsICacheEntry.h"
|
||||
#include "nsICacheEntryOpenCallback.h"
|
||||
@ -59,6 +60,7 @@ public:
|
||||
class nsHttpChannel final : public HttpBaseChannel
|
||||
, public HttpAsyncAborter<nsHttpChannel>
|
||||
, public nsIStreamListener
|
||||
, public nsIPackagedAppChannelListener
|
||||
, public nsICachingChannel
|
||||
, public nsICacheEntryOpenCallback
|
||||
, public nsITransportEventSink
|
||||
@ -76,6 +78,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPACKAGEDAPPCHANNELLISTENER
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
NS_DECL_NSICACHEINFOCHANNEL
|
||||
NS_DECL_NSICACHINGCHANNEL
|
||||
|
@ -11,6 +11,7 @@ support-files =
|
||||
redirect_idn.html
|
||||
empty.html
|
||||
web_packaged_app.sjs
|
||||
signed_web_packaged_app.sjs
|
||||
|
||||
[test_arraybufferinputstream.html]
|
||||
[test_partially_cached_content.html]
|
||||
@ -25,4 +26,6 @@ skip-if = e10s
|
||||
[test_xhr_method_case.html]
|
||||
skip-if = e10s
|
||||
[test_idn_redirect.html]
|
||||
[test_signed_web_packaged_app.html]
|
||||
skip-if = e10s || buildapp != 'browser'
|
||||
[test_web_packaged_app.html]
|
||||
|
37
netwerk/test/mochitests/signed_web_packaged_app.sjs
Normal file
37
netwerk/test/mochitests/signed_web_packaged_app.sjs
Normal file
@ -0,0 +1,37 @@
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "application/package", false);
|
||||
response.write(octetStreamData.packageHeader + octetStreamData.getData());
|
||||
return;
|
||||
}
|
||||
|
||||
// The package content
|
||||
// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
|
||||
var octetStreamData = {
|
||||
packageHeader: 'manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n',
|
||||
|
||||
content: [
|
||||
{ headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n <head>\r\n <script> alert('OK: hello'); alert('DONE'); </script>\r\n</head>\r\n Web Packaged App Index\r\n</html>\r\n", type: "text/html" },
|
||||
{ headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
|
||||
{ headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
|
||||
],
|
||||
token : "gc0pJq0M:08jU534c0p",
|
||||
getData: function() {
|
||||
var str = "";
|
||||
for (var i in this.content) {
|
||||
str += "--" + this.token + "\r\n";
|
||||
for (var j in this.content[i].headers) {
|
||||
str += this.content[i].headers[j] + "\r\n";
|
||||
}
|
||||
str += "\r\n";
|
||||
str += this.content[i].data + "\r\n";
|
||||
}
|
||||
|
||||
str += "--" + this.token + "--";
|
||||
return str;
|
||||
}
|
||||
}
|
70
netwerk/test/mochitests/test_signed_web_packaged_app.html
Normal file
70
netwerk/test/mochitests/test_signed_web_packaged_app.html
Normal file
@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title> Web packaged app </title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
|
||||
var Cc = SpecialPowers.Cc;
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var Cu = SpecialPowers.Cu;
|
||||
var Cr = SpecialPowers.Cr;
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["network.http.enable-packaged-apps", true],
|
||||
["network.http.packaged-apps-developer-mode", true],
|
||||
["dom.ipc.processPriorityManager.testMode", true],
|
||||
["dom.ipc.processPriorityManager.enabled", true],
|
||||
["dom.ipc.tabs.disabled", false],
|
||||
["dom.ipc.processCount", 3],
|
||||
["dom.mozBrowserFramesEnabled", true]] },
|
||||
() => SpecialPowers.pushPermissions([
|
||||
{ "type": "browser", "allow": 1, "context": document }
|
||||
], function() {
|
||||
runTest();
|
||||
}));
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Listen for and count process-created event. Since we are loading a
|
||||
// signed content from a remote tab, there shouls be two processes created.
|
||||
// One is for remote tab and one for the signed package.
|
||||
var kProcessCreatedTopic = "process-priority-manager:TEST-ONLY:process-created";
|
||||
var processCreatedCnt = 0;
|
||||
SpecialPowers.addObserver(() => {
|
||||
processCreatedCnt++;
|
||||
if (processCreatedCnt == 1) {
|
||||
ok(true, "We have one more process to create.");
|
||||
} else if (processCreatedCnt == 2) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}, kProcessCreatedTopic, /* weak = */ false);
|
||||
|
||||
function runTest() {
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
iframe.setAttribute('remote', 'true');
|
||||
iframe.setAttribute("src", "http://example.org:80");
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function loadend(e) {
|
||||
iframe.removeEventListener("mozbrowserloadend", loadend);
|
||||
ok(true, "Got mozbrowserloadend");
|
||||
iframe.setAttribute("src", "http://mochi.test:8888/tests/netwerk/test/mochitests/signed_web_packaged_app.sjs!//scripts/app.js");
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -41,6 +41,9 @@ Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
let gPrefs = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
// The number of times this package has been requested
|
||||
// This number might be reset by tests that use it
|
||||
var packagedAppRequestsMade = 0;
|
||||
@ -65,7 +68,7 @@ function packagedAppContentHandler(metadata, response)
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function getChannelForURL(url) {
|
||||
function getChannelForURL(url, notificationCallbacks) {
|
||||
let uri = createURI(url);
|
||||
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
@ -77,17 +80,24 @@ function getChannelForURL(url) {
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
|
||||
});
|
||||
|
||||
tmpChannel.notificationCallbacks =
|
||||
new LoadContextCallback(principal.appId,
|
||||
principal.isInBrowserElement,
|
||||
false,
|
||||
false);
|
||||
if (notificationCallbacks) {
|
||||
// Use custom notificationCallbacks if any.
|
||||
tmpChannel.notificationCallbacks = notificationCallbacks;
|
||||
} else {
|
||||
tmpChannel.notificationCallbacks =
|
||||
new LoadContextCallback(principal.appId,
|
||||
principal.isInBrowserElement,
|
||||
false,
|
||||
false);
|
||||
|
||||
}
|
||||
return tmpChannel;
|
||||
}
|
||||
|
||||
// The package content
|
||||
// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
|
||||
var testData = {
|
||||
packageHeader: 'manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n',
|
||||
content: [
|
||||
{ headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n <head>\r\n <script src=\"/scripts/app.js\"></script>\r\n ...\r\n </head>\r\n ...\r\n</html>\r\n", type: "text/html" },
|
||||
{ headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
|
||||
@ -136,8 +146,17 @@ function run_test()
|
||||
packagedAppWorseContentHandler.bind(null, i));
|
||||
}
|
||||
|
||||
httpserver.registerPathHandler("/signedPackage", signedPackagedAppContentHandler);
|
||||
httpserver.start(-1);
|
||||
|
||||
// We will enable the developer mode in 'test_signed_package_callback'.
|
||||
// So restore it after testing.
|
||||
//
|
||||
// TODO: To be removed in Bug 1178518.
|
||||
do_register_cleanup(function() {
|
||||
gPrefs.clearUserPref("network.http.packaged-apps-developer-mode");
|
||||
});
|
||||
|
||||
paservice = Cc["@mozilla.org/network/packaged-app-service;1"]
|
||||
.getService(Ci.nsIPackagedAppService);
|
||||
ok(!!paservice, "test service exists");
|
||||
@ -155,6 +174,9 @@ function run_test()
|
||||
add_test(test_bad_package);
|
||||
add_test(test_bad_package_404);
|
||||
|
||||
add_test(test_signed_package_callback);
|
||||
add_test(test_unsigned_package_callback);
|
||||
|
||||
// Channels created by addons could have no load info.
|
||||
// In debug mode this triggers an assertion, but we still want to test that
|
||||
// it works in optimized mode. See bug 1196021 comment 17
|
||||
@ -474,3 +496,81 @@ function test_worse_package_4() {
|
||||
function test_worse_package_5() {
|
||||
test_worse_package(5, true);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function signedPackagedAppContentHandler(metadata, response)
|
||||
{
|
||||
response.setHeader("Content-Type", 'application/package');
|
||||
var body = testData.packageHeader + testData.getData();
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
// Used as a stub when the cache listener is not important.
|
||||
let dummyCacheListener = {
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsICacheEntryOpenCallback) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
|
||||
onCacheEntryAvailable: function () {}
|
||||
};
|
||||
|
||||
function test_signed_package_callback()
|
||||
{
|
||||
// TODO: To be removed in Bug 1178518.
|
||||
gPrefs.setBoolPref("network.http.packaged-apps-developer-mode", true);
|
||||
|
||||
packagePath = "/signedPackage";
|
||||
let url = uri + packagePath + "!//index.html";
|
||||
let channel = getChannelForURL(url, {
|
||||
onStartSignedPackageRequest: function(aPackageId) {
|
||||
ok(true, "onStartSignedPackageRequest is notifited as expected");
|
||||
run_next_test();
|
||||
},
|
||||
|
||||
getInterface: function (iid) {
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIInterfaceRequestor) ||
|
||||
iid.equals(Ci.nsIPackagedAppChannelListener)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
});
|
||||
|
||||
paservice.getResource(channel, dummyCacheListener);
|
||||
}
|
||||
|
||||
function test_unsigned_package_callback()
|
||||
{
|
||||
packagePath = "/package";
|
||||
let url = uri + packagePath + "!//index.html";
|
||||
let channel = getChannelForURL(url, {
|
||||
onStartSignedPackageRequest: function(aPackageId) {
|
||||
ok(false, "Unsigned package shouldn't be called.");
|
||||
},
|
||||
|
||||
getInterface: function (iid) {
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIInterfaceRequestor) ||
|
||||
iid.equals(Ci.nsIPackagedAppChannelListener)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
});
|
||||
|
||||
// Pass cacheListener since we rely on 'run_next_test' in it.
|
||||
paservice.getResource(channel, cacheListener);
|
||||
}
|
Loading…
Reference in New Issue
Block a user