Bug 1193911 - Ensure synthetic Responses gets a valid channel info. r=ehsan

Right now, synthetic Responses did not have a valid channel info. When these
were saved in the Cache, and then restored, the restored Response did have
a ChannelInfo, but that ChannelInfo did not have a valid security info.
Passing this to respondWith() then caused the interception to fail.

This patch modifies Response::Constructor() to initialize its ChannelInfo from
the global. ChannelInfo can now initialize itself from a nsIDocument. All
workers now store their ChannelInfo on the WorkerLoadInfo.
This commit is contained in:
Nikhil Marathe 2015-08-17 15:08:58 -07:00
parent dd178eabb4
commit 08f05177fc
8 changed files with 61 additions and 7 deletions

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/ChannelInfo.h"
#include "nsCOMPtr.h"
#include "nsIChannel.h"
#include "nsIDocument.h"
#include "nsIHttpChannel.h"
#include "nsSerializationHelper.h"
#include "mozilla/net/HttpBaseChannel.h"
@ -18,6 +19,26 @@
using namespace mozilla;
using namespace mozilla::dom;
void
ChannelInfo::InitFromDocument(nsIDocument* aDoc)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
nsCOMPtr<nsISupports> securityInfo = aDoc->GetSecurityInfo();
if (securityInfo) {
SetSecurityInfo(securityInfo);
}
// mRedirected flag and mRedirectedURISpec are only important for maintaining
// the channel's redirected status. If the ChannelInfo is initialized from
// a document, that document has already asked the channel from which it was
// loaded about the current channel URI, so it won't matter if a future
// ResurrectInfoOnChannel() call misses whether the channel was redirected.
mRedirected = false;
mInited = true;
}
void
ChannelInfo::InitFromChannel(nsIChannel* aChannel)
{

View File

@ -11,6 +11,7 @@
#include "nsCOMPtr.h"
class nsIChannel;
class nsIDocument;
class nsIURI;
namespace mozilla {
@ -66,6 +67,7 @@ public:
return *this;
}
void InitFromDocument(nsIDocument* aDoc);
void InitFromChannel(nsIChannel* aChannel);
void InitFromIPCChannelInfo(const IPCChannelInfo& aChannelInfo);

View File

@ -159,6 +159,22 @@ Response::Constructor(const GlobalObject& aGlobal,
nsRefPtr<InternalResponse> internalResponse =
new InternalResponse(aInit.mStatus, statusText);
// Grab a valid channel info from the global so this response is 'valid' for
// interception.
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
MOZ_ASSERT(window);
nsIDocument* doc = window->GetExtantDoc();
MOZ_ASSERT(doc);
ChannelInfo info;
info.InitFromDocument(doc);
internalResponse->InitChannelInfo(info);
} else {
workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
internalResponse->InitChannelInfo(worker->GetChannelInfo());
}
nsRefPtr<Response> r = new Response(global, internalResponse);
if (aInit.mHeaders.WasPassed()) {

View File

@ -1033,9 +1033,7 @@ private:
mWorkerPrivate->SetBaseURI(finalURI);
// Store the channel info if needed.
if (mWorkerPrivate->IsServiceWorker()) {
mWorkerPrivate->InitChannelInfo(channel);
}
mWorkerPrivate->InitChannelInfo(channel);
// Now to figure out which principal to give this worker.
WorkerPrivate* parent = mWorkerPrivate->GetParent();

View File

@ -503,14 +503,12 @@ public:
const ChannelInfo&
GetChannelInfo() const
{
MOZ_ASSERT(IsServiceWorker());
return mLoadInfo.mChannelInfo;
}
void
SetChannelInfo(const ChannelInfo& aChannelInfo)
{
MOZ_ASSERT(IsServiceWorker());
AssertIsOnMainThread();
MOZ_ASSERT(!mLoadInfo.mChannelInfo.IsInitialized());
MOZ_ASSERT(aChannelInfo.IsInitialized());

View File

@ -1,12 +1,21 @@
self.addEventListener("install", function(event) {
event.waitUntil(caches.open("cache").then(function(cache) {
return cache.add("index.html");
var synth = new Response('<!DOCTYPE html><script>window.parent.postMessage({status: "done-synth-sw"}, "*");</script>',
{headers:{"Content-Type": "text/html"}});
return Promise.all([
cache.add("index.html"),
cache.put("synth-sw.html", synth),
]);
}));
});
self.addEventListener("fetch", function(event) {
if (event.request.url.indexOf("index.html") >= 0) {
event.respondWith(caches.match(event.request));
} else if (event.request.url.indexOf("synth-sw.html") >= 0) {
event.respondWith(caches.match(event.request));
} else if (event.request.url.indexOf("synth-window.html") >= 0) {
event.respondWith(caches.match(event.request));
} else if (event.request.url.indexOf("synth.html") >= 0) {
event.respondWith(new Response('<!DOCTYPE html><script>window.parent.postMessage({status: "done-synth"}, "*");</script>',
{headers:{"Content-Type": "text/html"}}));

View File

@ -9,6 +9,12 @@
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.ready.then(reg => {
return window.caches.open("cache").then(function(cache) {
var synth = new Response('<!DOCTYPE html><script>window.parent.postMessage({status: "done-synth-window"}, "*");</scri' + 'pt>',
{headers:{"Content-Type": "text/html"}});
return cache.put('synth-window.html', synth).then(_ => done(reg));
});
});
navigator.serviceWorker.register("https_test.js", {scope: "."});
</script>

View File

@ -31,6 +31,10 @@
ios.offline = true;
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/index.html";
} else if (e.data.status == "done") {
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/synth-sw.html";
} else if (e.data.status == "done-synth-sw") {
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/synth-window.html";
} else if (e.data.status == "done-synth-window") {
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/synth.html";
} else if (e.data.status == "done-synth") {
ios.offline = false;