mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Backed out changeset 25f90464e93b (bug 1065216) for Android mochitest failures.
This commit is contained in:
parent
8858594e1f
commit
5abea51e9a
@ -52,7 +52,6 @@
|
||||
#include "nsIAuthPrompt2.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
@ -1042,7 +1041,6 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
|
||||
NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
|
||||
|
||||
///*****************************************************************************
|
||||
@ -13923,52 +13921,6 @@ nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate, bool* aShouldIntercept)
|
||||
{
|
||||
*aShouldIntercept = false;
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
if (!swm) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIsNavigate) {
|
||||
return swm->IsAvailableForURI(aURI, aShouldIntercept);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
if (!doc) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return swm->IsControlled(doc, aShouldIntercept);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
if (!swm) {
|
||||
aChannel->Cancel();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool isNavigation = false;
|
||||
nsresult rv = aChannel->GetIsNavigation(&isNavigation);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
|
||||
if (!isNavigation) {
|
||||
doc = GetDocument();
|
||||
if (!doc) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return swm->DispatchFetchEvent(doc, aChannel);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetPaymentRequestId(const nsAString& aPaymentRequestId)
|
||||
{
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIScrollable.h"
|
||||
#include "nsITextScroll.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
@ -153,7 +152,6 @@ class nsDocShell MOZ_FINAL
|
||||
, public nsILinkHandler
|
||||
, public nsIClipboardCommands
|
||||
, public nsIDOMStorageManager
|
||||
, public nsINetworkInterceptController
|
||||
, public mozilla::SupportsWeakPtr<nsDocShell>
|
||||
{
|
||||
friend class nsDSURIContentListener;
|
||||
@ -184,7 +182,6 @@ public:
|
||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||
NS_DECL_NSICLIPBOARDCOMMANDS
|
||||
NS_DECL_NSIWEBSHELLSERVICES
|
||||
NS_DECL_NSINETWORKINTERCEPTCONTROLLER
|
||||
NS_FORWARD_SAFE_NSIDOMSTORAGEMANAGER(TopSessionStorageManager())
|
||||
|
||||
NS_IMETHOD Stop() MOZ_OVERRIDE {
|
||||
|
@ -622,7 +622,7 @@ protected:
|
||||
DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER)
|
||||
#undef DECL_SHIM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add an ExternalResource for aURI. aViewer and aLoadGroup might be null
|
||||
* when this is called if the URI didn't result in an XML document. This
|
||||
|
@ -418,14 +418,6 @@ DOMInterfaces = {
|
||||
'nativeType': 'mozilla::dom::workers::ExtendableEvent',
|
||||
},
|
||||
|
||||
'FetchEvent': {
|
||||
'headerFile': 'ServiceWorkerEvents.h',
|
||||
'nativeType': 'mozilla::dom::workers::FetchEvent',
|
||||
'binaryNames': {
|
||||
'request': 'request_'
|
||||
},
|
||||
},
|
||||
|
||||
'FileList': {
|
||||
'headerFile': 'mozilla/dom/File.h',
|
||||
},
|
||||
|
@ -866,11 +866,6 @@ FetchBody<Request>::FetchBody();
|
||||
template
|
||||
FetchBody<Response>::FetchBody();
|
||||
|
||||
template <class Derived>
|
||||
FetchBody<Derived>::~FetchBody()
|
||||
{
|
||||
}
|
||||
|
||||
// Returns true if addref succeeded.
|
||||
// Always succeeds on main thread.
|
||||
// May fail on worker if RegisterFeature() fails. In that case, it will release
|
||||
|
@ -135,12 +135,6 @@ public:
|
||||
void
|
||||
CancelPump();
|
||||
|
||||
void
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
|
||||
// Always set whenever the FetchBody is created on the worker thread.
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
@ -151,7 +145,15 @@ public:
|
||||
protected:
|
||||
FetchBody();
|
||||
|
||||
virtual ~FetchBody();
|
||||
virtual ~FetchBody()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
|
||||
void
|
||||
SetMimeType(ErrorResult& aRv);
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIDocument;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIURI;
|
||||
|
||||
@ -19,7 +18,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
|
||||
[noscript] void UnregisterFailed();
|
||||
};
|
||||
|
||||
[builtinclass, uuid(464882c8-81c0-4620-b9c4-44c12085b65b)]
|
||||
[builtinclass, uuid(861b55e9-d6ac-47cf-a528-8590e9b44de6)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -52,15 +51,6 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
// Remove ready pending Promise
|
||||
void removeReadyPromise(in nsIDOMWindow aWindow);
|
||||
|
||||
// Returns true if a ServiceWorker is available for the scope of aURI.
|
||||
bool isAvailableForURI(in nsIURI aURI);
|
||||
|
||||
// Returns true if a given document is currently controlled by a ServiceWorker
|
||||
bool isControlled(in nsIDocument aDocument);
|
||||
|
||||
// Cause a fetch event to be dispatched to the worker global associated with the given document.
|
||||
void dispatchFetchEvent(in nsIDocument aDoc, in nsIInterceptedChannel aChannel);
|
||||
|
||||
// aTarget MUST be a ServiceWorkerRegistration.
|
||||
[noscript] void AddRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
|
||||
[noscript] void RemoveRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
|
||||
|
@ -1,27 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* For more information on this interface, please see
|
||||
* http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
|
||||
*/
|
||||
|
||||
[Constructor(DOMString type, optional FetchEventInit eventInitDict),
|
||||
Func="mozilla::dom::workers::ServiceWorkerVisible",
|
||||
Exposed=(ServiceWorker)]
|
||||
interface FetchEvent : Event {
|
||||
readonly attribute Request request;
|
||||
readonly attribute ServiceWorkerClient client; // The window issuing the request.
|
||||
readonly attribute boolean isReload;
|
||||
|
||||
[Throws] void respondWith(Promise<Response> r);
|
||||
Promise<Response> forwardTo(USVString url);
|
||||
Promise<Response> default();
|
||||
};
|
||||
|
||||
dictionary FetchEventInit : EventInit {
|
||||
Request request;
|
||||
ServiceWorkerClient client;
|
||||
boolean isReload;
|
||||
};
|
@ -132,7 +132,6 @@ WEBIDL_FILES = [
|
||||
'EventTarget.webidl',
|
||||
'ExtendableEvent.webidl',
|
||||
'Fetch.webidl',
|
||||
'FetchEvent.webidl',
|
||||
'File.webidl',
|
||||
'FileList.webidl',
|
||||
'FileMode.webidl',
|
||||
|
@ -5,20 +5,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ServiceWorkerEvents.h"
|
||||
#include "ServiceWorkerClient.h"
|
||||
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
#include "mozilla/dom/FetchEventBinding.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/WorkerScope.h"
|
||||
#include "mozilla/dom/workers/bindings/ServiceWorker.h"
|
||||
|
||||
@ -26,271 +15,6 @@ using namespace mozilla::dom;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
FetchEvent::FetchEvent(EventTarget* aOwner)
|
||||
: Event(aOwner, nullptr, nullptr)
|
||||
, mWindowId(0)
|
||||
, mIsReload(false)
|
||||
, mWaitToRespond(false)
|
||||
{
|
||||
}
|
||||
|
||||
FetchEvent::~FetchEvent()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FetchEvent::PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
uint64_t aWindowId)
|
||||
{
|
||||
mChannel = aChannel;
|
||||
mServiceWorker = aServiceWorker;
|
||||
mWindowId = aWindowId;
|
||||
}
|
||||
|
||||
/*static*/ already_AddRefed<FetchEvent>
|
||||
FetchEvent::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const FetchEventInit& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<EventTarget> owner = do_QueryObject(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(owner);
|
||||
nsRefPtr<FetchEvent> e = new FetchEvent(owner);
|
||||
bool trusted = e->Init(owner);
|
||||
e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
|
||||
e->SetTrusted(trusted);
|
||||
e->mRequest = aOptions.mRequest.WasPassed() ?
|
||||
&aOptions.mRequest.Value() : nullptr;
|
||||
e->mIsReload = aOptions.mIsReload.WasPassed() ?
|
||||
aOptions.mIsReload.Value() : false;
|
||||
e->mClient = aOptions.mClient.WasPassed() ?
|
||||
&aOptions.mClient.Value() : nullptr;
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CancelChannelRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
public:
|
||||
explicit CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = mChannel->Cancel();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class FinishResponse MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
public:
|
||||
explicit FinishResponse(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
nsresult rv = mChannel->FinishSynthesizedResponse();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to finish synthesized response");
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
class RespondWithHandler MOZ_FINAL : public PromiseNativeHandler
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
public:
|
||||
RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
|
||||
: mInterceptedChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
{
|
||||
}
|
||||
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
|
||||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
|
||||
|
||||
void CancelRequest();
|
||||
};
|
||||
|
||||
struct RespondWithClosure
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
|
||||
explicit RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mInterceptedChannel(aChannel)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
|
||||
{
|
||||
nsAutoPtr<RespondWithClosure> data(static_cast<RespondWithClosure*>(aClosure));
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
event = new FinishResponse(data->mInterceptedChannel);
|
||||
} else {
|
||||
event = new CancelChannelRunnable(data->mInterceptedChannel);
|
||||
}
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoCancel
|
||||
{
|
||||
nsRefPtr<RespondWithHandler> mOwner;
|
||||
|
||||
public:
|
||||
explicit AutoCancel(RespondWithHandler* aOwner)
|
||||
: mOwner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
~AutoCancel()
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->CancelRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mOwner = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
AutoCancel autoCancel(this);
|
||||
|
||||
if (!aValue.isObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Response> response;
|
||||
nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
response->GetBody(getter_AddRefs(body));
|
||||
if (NS_WARN_IF(!body) || NS_WARN_IF(response->BodyUsed())) {
|
||||
return;
|
||||
}
|
||||
response->SetBodyUsed();
|
||||
|
||||
nsCOMPtr<nsIOutputStream> responseBody;
|
||||
rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel));
|
||||
|
||||
nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(!stsThread)) {
|
||||
return;
|
||||
}
|
||||
rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096,
|
||||
RespondWithCopyComplete, closure.forget());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoCancel.Reset();
|
||||
}
|
||||
|
||||
void
|
||||
RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
CancelRequest();
|
||||
}
|
||||
|
||||
void
|
||||
RespondWithHandler::CancelRequest()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = new CancelChannelRunnable(mInterceptedChannel);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
FetchEvent::RespondWith(Promise& aPromise, ErrorResult& aRv)
|
||||
{
|
||||
if (mWaitToRespond) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
mWaitToRespond = true;
|
||||
nsRefPtr<RespondWithHandler> handler = new RespondWithHandler(mChannel, mServiceWorker);
|
||||
aPromise.AppendNativeHandler(handler);
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerClient>
|
||||
FetchEvent::Client()
|
||||
{
|
||||
if (!mClient) {
|
||||
mClient = new ServiceWorkerClient(GetParentObject(), mWindowId);
|
||||
}
|
||||
nsRefPtr<ServiceWorkerClient> client = mClient;
|
||||
return client.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchEvent::ForwardTo(const nsAString& aUrl)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
MOZ_ASSERT(global);
|
||||
ErrorResult result;
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchEvent::Default()
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
MOZ_ASSERT(global);
|
||||
ErrorResult result;
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, result);
|
||||
if (result.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FetchEvent, Event)
|
||||
NS_IMPL_RELEASE_INHERITED(FetchEvent, Event)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(Event)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, Event, mRequest, mClient)
|
||||
|
||||
ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
|
||||
: Event(aOwner, nullptr, nullptr)
|
||||
{
|
||||
|
@ -8,87 +8,12 @@
|
||||
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/ExtendableEventBinding.h"
|
||||
#include "mozilla/dom/FetchEventBinding.h"
|
||||
#include "mozilla/dom/InstallEventBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
class nsIInterceptedChannel;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Request;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class ServiceWorker;
|
||||
class ServiceWorkerClient;
|
||||
|
||||
class FetchEvent MOZ_FINAL : public Event
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsRefPtr<ServiceWorkerClient> mClient;
|
||||
nsRefPtr<Request> mRequest;
|
||||
uint64_t mWindowId;
|
||||
bool mIsReload;
|
||||
bool mWaitToRespond;
|
||||
protected:
|
||||
explicit FetchEvent(EventTarget* aOwner);
|
||||
~FetchEvent();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, Event)
|
||||
NS_FORWARD_TO_EVENT
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
|
||||
{
|
||||
return FetchEventBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
void PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
uint64_t aWindowId);
|
||||
|
||||
static already_AddRefed<FetchEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const FetchEventInit& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
WaitToRespond() const
|
||||
{
|
||||
return mWaitToRespond;
|
||||
}
|
||||
|
||||
Request*
|
||||
Request_() const
|
||||
{
|
||||
return mRequest;
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerClient>
|
||||
Client();
|
||||
|
||||
bool
|
||||
IsReload() const
|
||||
{
|
||||
return mIsReload;
|
||||
}
|
||||
|
||||
void
|
||||
RespondWith(Promise& aPromise, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ForwardTo(const nsAString& aUrl);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Default();
|
||||
};
|
||||
|
||||
class ExtendableEvent : public Event
|
||||
{
|
||||
|
@ -11,10 +11,7 @@
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
@ -22,13 +19,9 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/InstallEventBinding.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
@ -2128,267 +2121,6 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class FetchEventRunnable : public WorkerRunnable
|
||||
, public nsIHttpHeaderVisitor {
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsTArray<nsCString> mHeaderNames;
|
||||
nsTArray<nsCString> mHeaderValues;
|
||||
uint64_t mWindowId;
|
||||
nsCString mSpec;
|
||||
nsCString mMethod;
|
||||
bool mIsReload;
|
||||
public:
|
||||
FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
uint64_t aWindowId)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mInterceptedChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
VisitHeader(const nsACString& aHeader, const nsACString& aValue)
|
||||
{
|
||||
mHeaderNames.AppendElement(aHeader);
|
||||
mHeaderValues.AppendElement(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init()
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv = mInterceptedChannel->GetChannel(getter_AddRefs(channel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = channel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = uri->GetSpec(mSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
NS_ENSURE_TRUE(httpChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
rv = httpChannel->GetRequestMethod(mMethod);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t loadFlags;
|
||||
rv = channel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//TODO(jdm): we should probably include reload-ness in the loadinfo or as a separate load flag
|
||||
mIsReload = false;
|
||||
|
||||
rv = httpChannel->VisitRequestHeaders(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
return DispatchFetchEvent(aCx, aWorkerPrivate);
|
||||
}
|
||||
|
||||
private:
|
||||
~FetchEventRunnable() {}
|
||||
|
||||
class ResumeRequest MOZ_FINAL : public nsRunnable {
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
public:
|
||||
explicit ResumeRequest(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
nsresult rv = mChannel->ResetInterception();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to resume intercepted network request");
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DispatchFetchEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
|
||||
GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
|
||||
|
||||
RequestOrUSVString requestInfo;
|
||||
*requestInfo.SetAsUSVString().ToAStringPtr() = NS_ConvertUTF8toUTF16(mSpec);
|
||||
|
||||
RootedDictionary<RequestInit> reqInit(aCx);
|
||||
reqInit.mMethod.Construct(mMethod);
|
||||
|
||||
nsRefPtr<InternalHeaders> internalHeaders = new InternalHeaders(HeadersGuardEnum::Request);
|
||||
MOZ_ASSERT(mHeaderNames.Length() == mHeaderValues.Length());
|
||||
for (uint32_t i = 0; i < mHeaderNames.Length(); i++) {
|
||||
ErrorResult rv;
|
||||
internalHeaders->Set(mHeaderNames[i], mHeaderValues[i], rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Headers> headers = new Headers(globalObj.GetAsSupports(), internalHeaders);
|
||||
reqInit.mHeaders.Construct();
|
||||
reqInit.mHeaders.Value().SetAsHeaders() = headers;
|
||||
|
||||
//TODO(jdm): set request body
|
||||
//TODO(jdm): set request same-origin mode and credentials
|
||||
|
||||
ErrorResult rv;
|
||||
nsRefPtr<Request> request = Request::Constructor(globalObj, requestInfo, reqInit, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedDictionary<FetchEventInit> init(aCx);
|
||||
init.mRequest.Construct();
|
||||
init.mRequest.Value() = request;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = true;
|
||||
init.mIsReload.Construct(mIsReload);
|
||||
nsRefPtr<FetchEvent> event =
|
||||
FetchEvent::Constructor(globalObj, NS_LITERAL_STRING("fetch"), init, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event->PostInit(mInterceptedChannel, mServiceWorker, mWindowId);
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
|
||||
nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
|
||||
nsCOMPtr<nsIRunnable> runnable = new ResumeRequest(mInterceptedChannel);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChannel* aChannel)
|
||||
{
|
||||
MOZ_ASSERT(aChannel);
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
|
||||
bool isNavigation = false;
|
||||
nsresult rv = aChannel->GetIsNavigation(&isNavigation);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isNavigation) {
|
||||
MOZ_ASSERT(aDoc);
|
||||
rv = GetDocumentController(aDoc->GetWindow(), getter_AddRefs(serviceWorker));
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> internalChannel;
|
||||
rv = aChannel->GetChannel(getter_AddRefs(internalChannel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = internalChannel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
GetServiceWorkerRegistrationInfo(uri);
|
||||
// This should only happen if IsAvailableForURI() returned true.
|
||||
MOZ_ASSERT(registration);
|
||||
MOZ_ASSERT(registration->mActiveWorker);
|
||||
|
||||
nsRefPtr<ServiceWorker> sw;
|
||||
rv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker->ScriptSpec(),
|
||||
registration->mScope,
|
||||
getter_AddRefs(sw));
|
||||
serviceWorker = sw.forget();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
|
||||
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
|
||||
|
||||
uint64_t windowId = aDoc ? aDoc->GetInnerWindow()->WindowID() : 0;
|
||||
|
||||
nsRefPtr<ServiceWorker> sw = static_cast<ServiceWorker*>(serviceWorker.get());
|
||||
nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
|
||||
new nsMainThreadPtrHolder<ServiceWorker>(sw));
|
||||
|
||||
nsRefPtr<FetchEventRunnable> event =
|
||||
new FetchEventRunnable(sw->GetWorkerPrivate(), handle, serviceWorkerHandle, windowId);
|
||||
rv = event->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AutoJSAPI api;
|
||||
api.Init();
|
||||
if (NS_WARN_IF(!event->Dispatch(api.cx()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::IsAvailableForURI(nsIURI* aURI, bool* aIsAvailable)
|
||||
{
|
||||
MOZ_ASSERT(aURI);
|
||||
MOZ_ASSERT(aIsAvailable);
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
GetServiceWorkerRegistrationInfo(aURI);
|
||||
*aIsAvailable = registration && registration->mActiveWorker;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::IsControlled(nsIDocument* aDoc, bool* aIsControlled)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
MOZ_ASSERT(aIsControlled);
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
nsresult rv = GetDocumentRegistration(aDoc, getter_AddRefs(registration));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aIsControlled = !!registration;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
|
||||
ServiceWorkerRegistrationInfo** aRegistrationInfo)
|
||||
{
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
if (!mControlledDocuments.Get(aDoc, getter_AddRefs(registration))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the document is controlled, the current worker MUST be non-null.
|
||||
if (!registration->mActiveWorker) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
registration.forget(aRegistrationInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The .controller is for the registration associated with the document when
|
||||
* the document was loaded.
|
||||
@ -2405,16 +2137,21 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
nsresult rv = GetDocumentRegistration(doc, getter_AddRefs(registration));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
if (!mControlledDocuments.Get(doc, getter_AddRefs(registration))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the document is controlled, the current worker MUST be non-null.
|
||||
if (!registration->mActiveWorker) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker->ScriptSpec(),
|
||||
registration->mScope,
|
||||
getter_AddRefs(serviceWorker));
|
||||
nsresult rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker->ScriptSpec(),
|
||||
registration->mScope,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -399,9 +399,6 @@ private:
|
||||
nsresult
|
||||
Update(ServiceWorkerRegistrationInfo* aRegistration);
|
||||
|
||||
nsresult
|
||||
GetDocumentRegistration(nsIDocument* aDoc, ServiceWorkerRegistrationInfo** aRegistrationInfo);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
const nsACString& aScriptSpec,
|
||||
|
@ -1,54 +0,0 @@
|
||||
function fetch(name, onload, onerror, headers) {
|
||||
expectAsyncResult();
|
||||
|
||||
onload = onload || function() {
|
||||
my_ok(false, "XHR load should not complete successfully");
|
||||
finish();
|
||||
};
|
||||
onerror = onerror || function() {
|
||||
my_ok(false, "XHR load should be intercepted successfully");
|
||||
finish();
|
||||
};
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('GET', name, true);
|
||||
x.onload = function() { onload(x) };
|
||||
x.onerror = function() { onerror(x) };
|
||||
headers = headers || [];
|
||||
headers.forEach(function(header) {
|
||||
x.setRequestHeader(header[0], header[1]);
|
||||
});
|
||||
x.send();
|
||||
}
|
||||
|
||||
fetch('synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('ignored.txt', function(xhr) {
|
||||
my_ok(xhr.status == 404, "load should be uninterrupted");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('rejected.txt', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "load should not complete");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('nonresponse.txt', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "load should not complete");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('nonresponse2.txt', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "load should not complete");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('headers.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "1", "request header checks should have passed");
|
||||
finish();
|
||||
}, null, [["X-Test1", "header1"], ["X-Test2", "header2"]]);
|
@ -1,29 +0,0 @@
|
||||
function my_ok(v, msg) {
|
||||
postMessage({type: "ok", value: v, msg: msg});
|
||||
}
|
||||
|
||||
function finish() {
|
||||
postMessage('finish');
|
||||
}
|
||||
|
||||
function expectAsyncResult() {
|
||||
postMessage('expect');
|
||||
}
|
||||
|
||||
expectAsyncResult();
|
||||
try {
|
||||
var success = false;
|
||||
importScripts("nonexistent_imported_script.js");
|
||||
} catch(x) {
|
||||
}
|
||||
|
||||
my_ok(success, "worker imported script should be intercepted");
|
||||
finish();
|
||||
|
||||
function check_intercepted_script() {
|
||||
success = true;
|
||||
}
|
||||
|
||||
importScripts('fetch_tests.js')
|
||||
|
||||
finish(); //corresponds to the gExpected increment before creating this worker
|
@ -1,147 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 94048 - test install event.</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>
|
||||
<div id="style-test" style="background-color: white"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
function my_ok(result, msg) {
|
||||
window.opener.postMessage({status: "ok", result: result, message: msg}, "*");
|
||||
}
|
||||
|
||||
function check_intercepted_script() {
|
||||
document.getElementById('intercepted-script').test_result =
|
||||
document.currentScript == document.getElementById('intercepted-script');
|
||||
}
|
||||
|
||||
function fetch(name, onload, onerror, headers) {
|
||||
gExpected++;
|
||||
|
||||
onload = onload || function() {
|
||||
my_ok(false, "load should not complete successfully");
|
||||
finish();
|
||||
};
|
||||
onerror = onerror || function() {
|
||||
my_ok(false, "load should be intercepted successfully");
|
||||
finish();
|
||||
};
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('GET', name, true);
|
||||
x.onload = function() { onload(x) };
|
||||
x.onerror = function() { onerror(x) };
|
||||
headers = headers || [];
|
||||
headers.forEach(function(header) {
|
||||
x.setRequestHeader(header[0], header[1]);
|
||||
});
|
||||
x.send();
|
||||
}
|
||||
|
||||
var gExpected = 0;
|
||||
var gEncountered = 0;
|
||||
function finish() {
|
||||
gEncountered++;
|
||||
if (gEncountered == gExpected) {
|
||||
window.opener.postMessage({status: "done"}, "*");
|
||||
}
|
||||
}
|
||||
|
||||
function test_onload(creator, complete) {
|
||||
gExpected++;
|
||||
var elem = creator();
|
||||
elem.onload = function() {
|
||||
complete.call(elem);
|
||||
finish();
|
||||
};
|
||||
elem.onerror = function() {
|
||||
my_ok(false, elem.tagName + " load should complete successfully");
|
||||
finish();
|
||||
};
|
||||
document.body.appendChild(elem);
|
||||
}
|
||||
|
||||
function expectAsyncResult() {
|
||||
gExpected++;
|
||||
}
|
||||
|
||||
my_ok(navigator.serviceWorker.controller != null, "should be controlled");
|
||||
</script>
|
||||
<script src="fetch_tests.js"></script>
|
||||
<script>
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('img');
|
||||
elem.src = "nonexistent_image.gifs";
|
||||
elem.id = 'intercepted-img';
|
||||
return elem;
|
||||
}, function() {
|
||||
my_ok(this.complete, "image should be complete");
|
||||
my_ok(this.naturalWidth == 1 && this.naturalHeight == 1, "image should be 1x1 gif");
|
||||
});
|
||||
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('script');
|
||||
elem.id = 'intercepted-script';
|
||||
elem.src = "nonexistent_script.js";
|
||||
return elem;
|
||||
}, function() {
|
||||
my_ok(this.test_result, "script load should be intercepted");
|
||||
});
|
||||
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('link');
|
||||
elem.href = "nonexistent_stylesheet.css";
|
||||
elem.rel = "stylesheet";
|
||||
return elem;
|
||||
}, function() {
|
||||
var styled = document.getElementById('style-test');
|
||||
my_ok(window.getComputedStyle(styled).backgroundColor == 'rgb(0, 0, 0)',
|
||||
"stylesheet load should be intercepted");
|
||||
});
|
||||
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('iframe');
|
||||
elem.id = 'intercepted-iframe';
|
||||
elem.src = "nonexistent_page.html";
|
||||
return elem;
|
||||
}, function() {
|
||||
my_ok(this.test_result, "iframe load should be intercepted");
|
||||
});
|
||||
|
||||
gExpected++;
|
||||
var worker = new Worker('nonexistent_worker_script.js');
|
||||
worker.onmessage = function(e) {
|
||||
my_ok(e.data == "worker-intercept-success", "worker load intercepted");
|
||||
finish();
|
||||
};
|
||||
worker.onerror = function() {
|
||||
my_ok(false, "worker load should be intercepted");
|
||||
};
|
||||
|
||||
gExpected++;
|
||||
var worker = new Worker('fetch_worker_script.js');
|
||||
worker.onmessage = function(e) {
|
||||
if (e.data == "finish") {
|
||||
finish();
|
||||
} else if (e.data == "expect") {
|
||||
gExpected++;
|
||||
} else if (e.data.type == "ok") {
|
||||
my_ok(e.data.value, e.data.msg);
|
||||
}
|
||||
};
|
||||
worker.onerror = function() {
|
||||
my_ok(false, "worker should not cause any errors");
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,86 +0,0 @@
|
||||
onfetch = function(ev) {
|
||||
if (ev.request.url.contains("synthesized.txt")) {
|
||||
var p = new Promise(function(resolve) {
|
||||
var r = new Response("synthesized response body", {});
|
||||
resolve(r);
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("ignored.txt")) {
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("rejected.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
reject();
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonresponse.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(5);
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonresponse2.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve({});
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("headers.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
var ok = true;
|
||||
ok &= ev.request.headers.get("X-Test1") == "header1";
|
||||
ok &= ev.request.headers.get("X-Test2") == "header2";
|
||||
var r = new Response(ok.toString(), {});
|
||||
resolve(r);
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_image.gif")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response(atob("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs"), {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_script.js")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("check_intercepted_script();", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_stylesheet.css")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("#style-test { background-color: black !important; }", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_page.html")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("<script>window.frameElement.test_result = true;</script>", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_worker_script.js")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("postMessage('worker-intercept-success')", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_imported_script.js")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("check_intercepted_script();", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ support-files =
|
||||
worker.js
|
||||
worker2.js
|
||||
worker3.js
|
||||
fetch_event_worker.js
|
||||
parse_error_worker.js
|
||||
activate_event_error_worker.js
|
||||
install_event_worker.js
|
||||
@ -21,14 +20,10 @@ support-files =
|
||||
worker_unregister.js
|
||||
worker_update.js
|
||||
message_posting_worker.js
|
||||
fetch/index.html
|
||||
fetch/fetch_worker_script.js
|
||||
fetch/fetch_tests.js
|
||||
|
||||
[test_unregister.html]
|
||||
skip-if = true # Bug 1133805
|
||||
[test_installation_simple.html]
|
||||
[test_fetch_event.html]
|
||||
[test_get_serviced.html]
|
||||
[test_install_event.html]
|
||||
[test_navigator.html]
|
||||
|
@ -1,61 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 94048 - test install event.</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"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function simpleRegister() {
|
||||
var p = navigator.serviceWorker.register("fetch_event_worker.js", { scope: "./fetch" });
|
||||
return p;
|
||||
}
|
||||
|
||||
function testController() {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "done") {
|
||||
window.onmessage = null;
|
||||
w.close();
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var w = window.open("fetch/index.html");
|
||||
return p;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
simpleRegister()
|
||||
.then(testController)
|
||||
.then(function() {
|
||||
SimpleTest.finish();
|
||||
}).catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.fetch.enabled", true]
|
||||
]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIChannel;
|
||||
interface nsIHttpChannelInternal;
|
||||
interface nsIOutputStream;
|
||||
interface nsIURI;
|
||||
|
||||
@ -16,7 +16,7 @@ interface nsIURI;
|
||||
* which do not implement nsIChannel.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(9d127b63-dfad-484d-a0e1-cb82697a095b)]
|
||||
[scriptable, uuid(0b5f82a7-5824-4a0d-bf5c-8a8a7684c0c8)]
|
||||
interface nsIInterceptedChannel : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -37,28 +37,6 @@ interface nsIInterceptedChannel : nsISupports
|
||||
* after this point.
|
||||
*/
|
||||
void finishSynthesizedResponse();
|
||||
|
||||
/**
|
||||
* Cancel the pending intercepted request.
|
||||
* @return NS_ERROR_FAILURE if the response has already been synthesized or
|
||||
* the original request has been instructed to continue.
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* The synthesized response body to be produced.
|
||||
*/
|
||||
readonly attribute nsIOutputStream responseBody;
|
||||
|
||||
/**
|
||||
* The underlying channel object that was intercepted.
|
||||
*/
|
||||
readonly attribute nsIChannel channel;
|
||||
|
||||
/**
|
||||
* True if the underlying request was caused by a navigation attempt.
|
||||
*/
|
||||
readonly attribute bool isNavigation;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -67,7 +45,7 @@ interface nsIInterceptedChannel : nsISupports
|
||||
* request should be intercepted before any network request is initiated.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(69150b77-b561-43a2-bfba-7301dd5a35d0)]
|
||||
[scriptable, uuid(b3ad3e9b-91d8-44d0-a0c5-dc2e9374f599)]
|
||||
interface nsINetworkInterceptController : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -75,15 +53,15 @@ interface nsINetworkInterceptController : nsISupports
|
||||
* requests until specifically instructed to do so.
|
||||
*
|
||||
* @param aURI the URI being requested by a channel
|
||||
* @param aIsNavigate True if the request is for a navigation, false for a fetch.
|
||||
*/
|
||||
bool shouldPrepareForIntercept(in nsIURI aURI, in bool aIsNavigate);
|
||||
bool shouldPrepareForIntercept(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Notification when a given intercepted channel is prepared to accept a synthesized
|
||||
* response via the provided stream.
|
||||
*
|
||||
* @param aChannel the controlling interface for a channel that has been intercepted
|
||||
* @param aStream a stream directly into the channel's synthesized response body
|
||||
*/
|
||||
void channelIntercepted(in nsIInterceptedChannel aChannel);
|
||||
void channelIntercepted(in nsIInterceptedChannel aChannel, in nsIOutputStream aStream);
|
||||
};
|
||||
|
@ -1933,12 +1933,6 @@ HttpBaseChannel::GetURIPrincipal()
|
||||
return mPrincipal;
|
||||
}
|
||||
|
||||
bool
|
||||
HttpBaseChannel::IsNavigation()
|
||||
{
|
||||
return mLoadFlags & LOAD_DOCUMENT_URI;
|
||||
}
|
||||
|
||||
bool
|
||||
HttpBaseChannel::ShouldIntercept()
|
||||
{
|
||||
@ -1946,9 +1940,7 @@ HttpBaseChannel::ShouldIntercept()
|
||||
GetCallback(controller);
|
||||
bool shouldIntercept = false;
|
||||
if (controller && !mForceNoIntercept) {
|
||||
nsresult rv = controller->ShouldPrepareForIntercept(mURI,
|
||||
IsNavigation(),
|
||||
&shouldIntercept);
|
||||
nsresult rv = controller->ShouldPrepareForIntercept(mURI, &shouldIntercept);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
return shouldIntercept;
|
||||
|
@ -241,7 +241,7 @@ public:
|
||||
const NetAddr& GetPeerAddr() { return mPeerAddr; }
|
||||
|
||||
public: /* Necko internal use only... */
|
||||
bool IsNavigation();
|
||||
|
||||
|
||||
// Return whether upon a redirect code of httpStatus for method, the
|
||||
// request method should be rewritten to GET.
|
||||
|
@ -56,111 +56,6 @@ static_assert(FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE == 250,
|
||||
|
||||
}
|
||||
|
||||
// A stream listener interposed between the nsInputStreamPump used for intercepted channels
|
||||
// and this channel's original listener. This is only used to ensure the original listener
|
||||
// sees the channel as the request object, and to synthesize OnStatus and OnProgress notifications.
|
||||
class InterceptStreamListener : public nsIStreamListener
|
||||
, public nsIProgressEventSink
|
||||
{
|
||||
nsRefPtr<HttpChannelChild> mOwner;
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
virtual ~InterceptStreamListener() {}
|
||||
public:
|
||||
InterceptStreamListener(HttpChannelChild* aOwner, nsISupports* aContext)
|
||||
: mOwner(aOwner)
|
||||
, mContext(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPROGRESSEVENTSINK
|
||||
|
||||
void Cleanup();
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(InterceptStreamListener,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver,
|
||||
nsIProgressEventSink)
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->DoOnStartRequest(mOwner, mContext);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsISupports* aContext,
|
||||
nsresult status, const char16_t* aStatusArg)
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->DoOnStatus(mOwner, status);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnProgress(nsIRequest* aRequest, nsISupports* aContext,
|
||||
int64_t aProgress, int64_t aProgressMax)
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->DoOnProgress(mOwner, aProgress, aProgressMax);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
|
||||
nsIInputStream* aInputStream, uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
if (!mOwner) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t loadFlags;
|
||||
mOwner->GetLoadFlags(&loadFlags);
|
||||
|
||||
if (!(loadFlags & HttpBaseChannel::LOAD_BACKGROUND)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mOwner->GetURI(getter_AddRefs(uri));
|
||||
|
||||
nsAutoCString host;
|
||||
uri->GetHost(host);
|
||||
|
||||
OnStatus(mOwner, aContext, NS_NET_STATUS_READING, NS_ConvertUTF8toUTF16(host).get());
|
||||
|
||||
int64_t progress = aOffset + aCount;
|
||||
OnProgress(mOwner, aContext, progress, mOwner->GetResponseHead()->ContentLength());
|
||||
}
|
||||
|
||||
mOwner->DoOnDataAvailable(mOwner, mContext, aInputStream, aOffset, aCount);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatusCode)
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->DoPreOnStopRequest(aStatusCode);
|
||||
mOwner->DoOnStopRequest(mOwner, mContext);
|
||||
}
|
||||
Cleanup();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
InterceptStreamListener::Cleanup()
|
||||
{
|
||||
mOwner = nullptr;
|
||||
mContext = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelChild
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -957,10 +852,6 @@ HttpChannelChild::DoNotifyListenerCleanup()
|
||||
LOG(("HttpChannelChild::DoNotifyListenerCleanup [this=%p]\n", this));
|
||||
if (mIPCOpen)
|
||||
PHttpChannelChild::Send__delete__(this);
|
||||
if (mInterceptListener) {
|
||||
mInterceptListener->Cleanup();
|
||||
mInterceptListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteSelfEvent : public ChannelEvent
|
||||
@ -1346,10 +1237,6 @@ HttpChannelChild::Cancel(nsresult status)
|
||||
mStatus = status;
|
||||
if (RemoteChannelExists())
|
||||
SendCancel(status);
|
||||
if (mSynthesizedResponsePump) {
|
||||
mSynthesizedResponsePump->Cancel(status);
|
||||
}
|
||||
mInterceptListener = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1456,6 +1343,89 @@ HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// A stream listener interposed between the nsInputStreamPump used for intercepted channels
|
||||
// and this channel's original listener. This is only used to ensure the original listener
|
||||
// sees the channel as the request object, and to synthesize OnStatus and OnProgress notifications.
|
||||
class InterceptStreamListener : public nsIStreamListener
|
||||
, public nsIProgressEventSink
|
||||
{
|
||||
nsRefPtr<HttpChannelChild> mOwner;
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
virtual ~InterceptStreamListener() {}
|
||||
public:
|
||||
InterceptStreamListener(HttpChannelChild* aOwner, nsISupports* aContext)
|
||||
: mOwner(aOwner)
|
||||
, mContext(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIPROGRESSEVENTSINK
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(InterceptStreamListener,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver,
|
||||
nsIProgressEventSink)
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
{
|
||||
mOwner->DoOnStartRequest(mOwner, mContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsISupports* aContext,
|
||||
nsresult status, const char16_t* aStatusArg)
|
||||
{
|
||||
mOwner->DoOnStatus(mOwner, status);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnProgress(nsIRequest* aRequest, nsISupports* aContext,
|
||||
int64_t aProgress, int64_t aProgressMax)
|
||||
{
|
||||
mOwner->DoOnProgress(mOwner, aProgress, aProgressMax);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
|
||||
nsIInputStream* aInputStream, uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
uint32_t loadFlags;
|
||||
mOwner->GetLoadFlags(&loadFlags);
|
||||
|
||||
if (!(loadFlags & HttpBaseChannel::LOAD_BACKGROUND)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mOwner->GetURI(getter_AddRefs(uri));
|
||||
|
||||
nsAutoCString host;
|
||||
uri->GetHost(host);
|
||||
|
||||
OnStatus(mOwner, aContext, NS_NET_STATUS_READING, NS_ConvertUTF8toUTF16(host).get());
|
||||
|
||||
int64_t progress = aOffset + aCount;
|
||||
OnProgress(mOwner, aContext, progress, mOwner->GetResponseHead()->ContentLength());
|
||||
}
|
||||
|
||||
mOwner->DoOnDataAvailable(mOwner, mContext, aInputStream, aOffset, aCount);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptStreamListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatusCode)
|
||||
{
|
||||
mOwner->DoPreOnStopRequest(aStatusCode);
|
||||
mOwner->DoOnStopRequest(mOwner, mContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
|
||||
{
|
||||
@ -2073,7 +2043,6 @@ HttpChannelChild::DivertToParent(ChannelDiverterChild **aChild)
|
||||
void
|
||||
HttpChannelChild::ResetInterception()
|
||||
{
|
||||
mInterceptListener->Cleanup();
|
||||
mInterceptListener = nullptr;
|
||||
|
||||
// Continue with the original cross-process request
|
||||
@ -2082,7 +2051,7 @@ HttpChannelChild::ResetInterception()
|
||||
}
|
||||
|
||||
void
|
||||
HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>& aResponseHead,
|
||||
HttpChannelChild::OverrideWithSynthesizedResponse(nsHttpResponseHead* aResponseHead,
|
||||
nsInputStreamPump* aPump)
|
||||
{
|
||||
mSynthesizedResponsePump = aPump;
|
||||
@ -2094,10 +2063,6 @@ HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>&
|
||||
nsresult rv = mSynthesizedResponsePump->Suspend();
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
|
||||
if (mCanceled) {
|
||||
mSynthesizedResponsePump->Cancel(mStatus);
|
||||
}
|
||||
}
|
||||
|
||||
}} // mozilla::net
|
||||
|
@ -159,7 +159,7 @@ private:
|
||||
|
||||
// Override this channel's pending response with a synthesized one. The content will be
|
||||
// asynchronously read from the pump.
|
||||
void OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>& aResponseHead, nsInputStreamPump* aPump);
|
||||
void OverrideWithSynthesizedResponse(nsHttpResponseHead* aResponseHead, nsInputStreamPump* aPump);
|
||||
|
||||
RequestHeaderTuples mClientSetRequestHeaders;
|
||||
nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
|
||||
|
@ -26,10 +26,8 @@ DoAddCacheEntryHeaders(nsHttpChannel *self,
|
||||
|
||||
NS_IMPL_ISUPPORTS(InterceptedChannelBase, nsIInterceptedChannel)
|
||||
|
||||
InterceptedChannelBase::InterceptedChannelBase(nsINetworkInterceptController* aController,
|
||||
bool aIsNavigation)
|
||||
InterceptedChannelBase::InterceptedChannelBase(nsINetworkInterceptController* aController)
|
||||
: mController(aController)
|
||||
, mIsNavigation(aIsNavigation)
|
||||
{
|
||||
}
|
||||
|
||||
@ -37,36 +35,21 @@ InterceptedChannelBase::~InterceptedChannelBase()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelBase::GetResponseBody(nsIOutputStream** aStream)
|
||||
{
|
||||
NS_IF_ADDREF(*aStream = mResponseBody);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
InterceptedChannelBase::EnsureSynthesizedResponse()
|
||||
{
|
||||
if (mSynthesizedResponseHead.isNothing()) {
|
||||
mSynthesizedResponseHead.emplace(new nsHttpResponseHead());
|
||||
mSynthesizedResponseHead.emplace();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InterceptedChannelBase::DoNotifyController()
|
||||
InterceptedChannelBase::DoNotifyController(nsIOutputStream* aOut)
|
||||
{
|
||||
nsresult rv = mController->ChannelIntercepted(this);
|
||||
mController = nullptr;
|
||||
nsresult rv = mController->ChannelIntercepted(this, aOut);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelBase::GetIsNavigation(bool* aIsNavigation)
|
||||
{
|
||||
*aIsNavigation = mIsNavigation;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, const nsACString& aValue)
|
||||
{
|
||||
@ -74,7 +57,7 @@ InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, const nsACSt
|
||||
|
||||
nsAutoCString header = aName + NS_LITERAL_CSTRING(": ") + aValue;
|
||||
// Overwrite any existing header.
|
||||
nsresult rv = (*mSynthesizedResponseHead)->ParseHeaderLine(header.get());
|
||||
nsresult rv = mSynthesizedResponseHead->ParseHeaderLine(header.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -82,7 +65,7 @@ InterceptedChannelBase::DoSynthesizeHeader(const nsACString& aName, const nsACSt
|
||||
InterceptedChannelChrome::InterceptedChannelChrome(nsHttpChannel* aChannel,
|
||||
nsINetworkInterceptController* aController,
|
||||
nsICacheEntry* aEntry)
|
||||
: InterceptedChannelBase(aController, aChannel->IsNavigation())
|
||||
: InterceptedChannelBase(aController)
|
||||
, mChannel(aChannel)
|
||||
, mSynthesizedCacheEntry(aEntry)
|
||||
{
|
||||
@ -93,17 +76,10 @@ InterceptedChannelChrome::NotifyController()
|
||||
{
|
||||
nsCOMPtr<nsIOutputStream> out;
|
||||
|
||||
nsresult rv = mSynthesizedCacheEntry->OpenOutputStream(0, getter_AddRefs(mResponseBody));
|
||||
nsresult rv = mSynthesizedCacheEntry->OpenOutputStream(0, getter_AddRefs(out));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
DoNotifyController();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelChrome::GetChannel(nsIChannel** aChannel)
|
||||
{
|
||||
NS_IF_ADDREF(*aChannel = mChannel);
|
||||
return NS_OK;
|
||||
DoNotifyController(out);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -156,7 +132,7 @@ InterceptedChannelChrome::FinishSynthesizedResponse()
|
||||
|
||||
rv = DoAddCacheEntryHeaders(mChannel, mSynthesizedCacheEntry,
|
||||
mChannel->GetRequestHead(),
|
||||
mSynthesizedResponseHead.ref(), securityInfo);
|
||||
mSynthesizedResponseHead.ptr(), securityInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
@ -180,24 +156,10 @@ InterceptedChannelChrome::FinishSynthesizedResponse()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelChrome::Cancel()
|
||||
{
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// we need to use AsyncAbort instead of Cancel since there's no active pump
|
||||
// to cancel which will provide OnStart/OnStopRequest to the channel.
|
||||
nsresult rv = mChannel->AsyncAbort(NS_BINDING_ABORTED);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
InterceptedChannelContent::InterceptedChannelContent(HttpChannelChild* aChannel,
|
||||
nsINetworkInterceptController* aController,
|
||||
nsIStreamListener* aListener)
|
||||
: InterceptedChannelBase(aController, aChannel->IsNavigation())
|
||||
: InterceptedChannelBase(aController)
|
||||
, mChannel(aChannel)
|
||||
, mStreamListener(aListener)
|
||||
{
|
||||
@ -207,18 +169,11 @@ void
|
||||
InterceptedChannelContent::NotifyController()
|
||||
{
|
||||
nsresult rv = NS_NewPipe(getter_AddRefs(mSynthesizedInput),
|
||||
getter_AddRefs(mResponseBody),
|
||||
getter_AddRefs(mSynthesizedOutput),
|
||||
0, UINT32_MAX, true, true);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
DoNotifyController();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelContent::GetChannel(nsIChannel** aChannel)
|
||||
{
|
||||
NS_IF_ADDREF(*aChannel = mChannel);
|
||||
return NS_OK;
|
||||
DoNotifyController(mSynthesizedOutput);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -228,7 +183,7 @@ InterceptedChannelContent::ResetInterception()
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mResponseBody = nullptr;
|
||||
mSynthesizedOutput = nullptr;
|
||||
mSynthesizedInput = nullptr;
|
||||
|
||||
mChannel->ResetInterception();
|
||||
@ -239,7 +194,7 @@ InterceptedChannelContent::ResetInterception()
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelContent::SynthesizeHeader(const nsACString& aName, const nsACString& aValue)
|
||||
{
|
||||
if (!mResponseBody) {
|
||||
if (!mSynthesizedOutput) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
@ -249,7 +204,7 @@ InterceptedChannelContent::SynthesizeHeader(const nsACString& aName, const nsACS
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelContent::FinishSynthesizedResponse()
|
||||
{
|
||||
if (NS_WARN_IF(!mChannel)) {
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
@ -257,36 +212,19 @@ InterceptedChannelContent::FinishSynthesizedResponse()
|
||||
|
||||
nsresult rv = nsInputStreamPump::Create(getter_AddRefs(mStoragePump), mSynthesizedInput,
|
||||
int64_t(-1), int64_t(-1), 0, 0, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
mSynthesizedInput->Close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
mResponseBody = nullptr;
|
||||
mSynthesizedOutput = nullptr;
|
||||
|
||||
rv = mStoragePump->AsyncRead(mStreamListener, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mChannel->OverrideWithSynthesizedResponse(mSynthesizedResponseHead.ref(), mStoragePump);
|
||||
mChannel->OverrideWithSynthesizedResponse(mSynthesizedResponseHead.ptr(), mStoragePump);
|
||||
|
||||
mChannel = nullptr;
|
||||
mStreamListener = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelContent::Cancel()
|
||||
{
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// we need to use AsyncAbort instead of Cancel since there's no active pump
|
||||
// to cancel which will provide OnStart/OnStopRequest to the channel.
|
||||
nsresult rv = mChannel->AsyncAbort(NS_BINDING_ABORTED);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mChannel = nullptr;
|
||||
mStreamListener = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -30,32 +30,22 @@ protected:
|
||||
// The interception controller to notify about the successful channel interception
|
||||
nsCOMPtr<nsINetworkInterceptController> mController;
|
||||
|
||||
// The stream to write the body of the synthesized response
|
||||
nsCOMPtr<nsIOutputStream> mResponseBody;
|
||||
|
||||
// Response head for use when synthesizing
|
||||
Maybe<nsAutoPtr<nsHttpResponseHead>> mSynthesizedResponseHead;
|
||||
|
||||
// Whether this intercepted channel was performing a navigation.
|
||||
bool mIsNavigation;
|
||||
Maybe<nsHttpResponseHead> mSynthesizedResponseHead;
|
||||
|
||||
void EnsureSynthesizedResponse();
|
||||
void DoNotifyController();
|
||||
void DoNotifyController(nsIOutputStream* aOut);
|
||||
nsresult DoSynthesizeHeader(const nsACString& aName, const nsACString& aValue);
|
||||
|
||||
virtual ~InterceptedChannelBase();
|
||||
public:
|
||||
InterceptedChannelBase(nsINetworkInterceptController* aController,
|
||||
bool aIsNavigation);
|
||||
explicit InterceptedChannelBase(nsINetworkInterceptController* aController);
|
||||
|
||||
// Notify the interception controller that the channel has been intercepted
|
||||
// and prepare the response body output stream.
|
||||
virtual void NotifyController() = 0;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD GetResponseBody(nsIOutputStream** aOutput) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetIsNavigation(bool* aIsNavigation) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class InterceptedChannelChrome : public InterceptedChannelBase
|
||||
@ -70,11 +60,7 @@ public:
|
||||
nsINetworkInterceptController* aController,
|
||||
nsICacheEntry* aEntry);
|
||||
|
||||
NS_IMETHOD ResetInterception() MOZ_OVERRIDE;
|
||||
NS_IMETHOD FinishSynthesizedResponse() MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetChannel(nsIChannel** aChannel) MOZ_OVERRIDE;
|
||||
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) MOZ_OVERRIDE;
|
||||
NS_IMETHOD Cancel() MOZ_OVERRIDE;
|
||||
NS_DECL_NSIINTERCEPTEDCHANNEL
|
||||
|
||||
virtual void NotifyController() MOZ_OVERRIDE;
|
||||
};
|
||||
@ -84,7 +70,8 @@ class InterceptedChannelContent : public InterceptedChannelBase
|
||||
// The actual channel being intercepted.
|
||||
nsRefPtr<HttpChannelChild> mChannel;
|
||||
|
||||
// Reader-side of the response body when synthesizing in a child proces
|
||||
// Writeable buffer for use when synthesizing a response in a child process
|
||||
nsCOMPtr<nsIOutputStream> mSynthesizedOutput;
|
||||
nsCOMPtr<nsIInputStream> mSynthesizedInput;
|
||||
|
||||
// Pump to read the synthesized body in child processes
|
||||
@ -98,11 +85,7 @@ public:
|
||||
nsINetworkInterceptController* aController,
|
||||
nsIStreamListener* aListener);
|
||||
|
||||
NS_IMETHOD ResetInterception() MOZ_OVERRIDE;
|
||||
NS_IMETHOD FinishSynthesizedResponse() MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetChannel(nsIChannel** aChannel) MOZ_OVERRIDE;
|
||||
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) MOZ_OVERRIDE;
|
||||
NS_IMETHOD Cancel() MOZ_OVERRIDE;
|
||||
NS_DECL_NSIINTERCEPTEDCHANNEL
|
||||
|
||||
virtual void NotifyController() MOZ_OVERRIDE;
|
||||
};
|
||||
|
@ -55,19 +55,19 @@ function make_channel(url, body, cb) {
|
||||
this.numChecks++;
|
||||
return true;
|
||||
},
|
||||
channelIntercepted: function(channel) {
|
||||
channelIntercepted: function(channel, stream) {
|
||||
channel.QueryInterface(Ci.nsIInterceptedChannel);
|
||||
if (body) {
|
||||
var synthesized = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
synthesized.data = body;
|
||||
|
||||
NetUtil.asyncCopy(synthesized, channel.responseBody, function() {
|
||||
NetUtil.asyncCopy(synthesized, stream, function() {
|
||||
channel.finishSynthesizedResponse();
|
||||
});
|
||||
}
|
||||
if (cb) {
|
||||
cb(channel);
|
||||
cb(channel, stream);
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -143,12 +143,12 @@ add_test(function() {
|
||||
|
||||
// ensure that the channel waits for a decision and synthesizes headers correctly
|
||||
add_test(function() {
|
||||
var chan = make_channel(URL + '/body', null, function(channel) {
|
||||
var chan = make_channel(URL + '/body', null, function(channel, stream) {
|
||||
do_timeout(100, function() {
|
||||
var synthesized = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
synthesized.data = NON_REMOTE_BODY;
|
||||
NetUtil.asyncCopy(synthesized, channel.responseBody, function() {
|
||||
NetUtil.asyncCopy(synthesized, stream, function() {
|
||||
channel.synthesizeHeader("Content-Length", NON_REMOTE_BODY.length);
|
||||
channel.finishSynthesizedResponse();
|
||||
});
|
||||
@ -169,12 +169,12 @@ add_test(function() {
|
||||
|
||||
// ensure that the intercepted channel supports suspend/resume
|
||||
add_test(function() {
|
||||
var chan = make_channel(URL + '/body', null, function(intercepted) {
|
||||
var chan = make_channel(URL + '/body', null, function(intercepted, stream) {
|
||||
var synthesized = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
synthesized.data = NON_REMOTE_BODY;
|
||||
|
||||
NetUtil.asyncCopy(synthesized, intercepted.responseBody, function() {
|
||||
NetUtil.asyncCopy(synthesized, stream, function() {
|
||||
// set the content-type to ensure that the stream converter doesn't hold up notifications
|
||||
// and cause the test to fail
|
||||
intercepted.synthesizeHeader("Content-Type", "text/plain");
|
||||
@ -185,65 +185,6 @@ add_test(function() {
|
||||
CL_ALLOW_UNKNOWN_CL | CL_SUSPEND | CL_EXPECT_3S_DELAY), null);
|
||||
});
|
||||
|
||||
// ensure that the intercepted channel can be cancelled
|
||||
add_test(function() {
|
||||
var chan = make_channel(URL + '/body', null, function(intercepted) {
|
||||
intercepted.cancel();
|
||||
});
|
||||
chan.asyncOpen(new ChannelListener(run_next_test, null,
|
||||
CL_EXPECT_FAILURE), null);
|
||||
});
|
||||
|
||||
// ensure that the channel can't be cancelled via nsIInterceptedChannel after making a decision
|
||||
add_test(function() {
|
||||
var chan = make_channel(URL + '/body', null, function(chan) {
|
||||
chan.resetInterception();
|
||||
do_timeout(0, function() {
|
||||
var gotexception = false;
|
||||
try {
|
||||
chan.cancel();
|
||||
} catch (x) {
|
||||
gotexception = true;
|
||||
}
|
||||
do_check_true(gotexception);
|
||||
});
|
||||
});
|
||||
chan.asyncOpen(new ChannelListener(handle_remote_response, null), null);
|
||||
});
|
||||
|
||||
// ensure that the intercepted channel can be canceled during the response
|
||||
add_test(function() {
|
||||
var chan = make_channel(URL + '/body', null, function(intercepted) {
|
||||
var synthesized = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
synthesized.data = NON_REMOTE_BODY;
|
||||
|
||||
NetUtil.asyncCopy(synthesized, intercepted.responseBody, function() {
|
||||
let channel = intercepted.channel;
|
||||
intercepted.finishSynthesizedResponse();
|
||||
channel.cancel(Cr.NS_BINDING_ABORTED);
|
||||
});
|
||||
});
|
||||
chan.asyncOpen(new ChannelListener(run_next_test, null,
|
||||
CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL), null);
|
||||
});
|
||||
|
||||
// ensure that the intercepted channel can be canceled before the response
|
||||
add_test(function() {
|
||||
var chan = make_channel(URL + '/body', null, function(intercepted) {
|
||||
var synthesized = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
synthesized.data = NON_REMOTE_BODY;
|
||||
|
||||
NetUtil.asyncCopy(synthesized, intercepted.responseBody, function() {
|
||||
intercepted.channel.cancel(Cr.NS_BINDING_ABORTED);
|
||||
intercepted.finishSynthesizedResponse();
|
||||
});
|
||||
});
|
||||
chan.asyncOpen(new ChannelListener(run_next_test, null,
|
||||
CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL), null);
|
||||
});
|
||||
|
||||
add_test(function() {
|
||||
httpServer.stop(run_next_test);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user