mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1173811
- Part 1: Propagate the response URL to intercepted channels when necessary (non-e10s). r=mayhemer,bkelly
This commit is contained in:
parent
0e71734c14
commit
d3726427db
@ -109,16 +109,19 @@ class FinishResponse final : public nsRunnable
|
||||
RefPtr<InternalResponse> mInternalResponse;
|
||||
ChannelInfo mWorkerChannelInfo;
|
||||
const nsCString mScriptSpec;
|
||||
const nsCString mResponseURLSpec;
|
||||
|
||||
public:
|
||||
FinishResponse(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
InternalResponse* aInternalResponse,
|
||||
const ChannelInfo& aWorkerChannelInfo,
|
||||
const nsACString& aScriptSpec)
|
||||
const nsACString& aScriptSpec,
|
||||
const nsACString& aResponseURLSpec)
|
||||
: mChannel(aChannel)
|
||||
, mInternalResponse(aInternalResponse)
|
||||
, mWorkerChannelInfo(aWorkerChannelInfo)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mResponseURLSpec(aResponseURLSpec)
|
||||
{
|
||||
}
|
||||
|
||||
@ -154,7 +157,7 @@ public:
|
||||
mChannel->SynthesizeHeader(entries[i].mName, entries[i].mValue);
|
||||
}
|
||||
|
||||
rv = mChannel->FinishSynthesizedResponse();
|
||||
rv = mChannel->FinishSynthesizedResponse(mResponseURLSpec);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to finish synthesized response");
|
||||
return rv;
|
||||
}
|
||||
@ -232,15 +235,18 @@ struct RespondWithClosure
|
||||
RefPtr<InternalResponse> mInternalResponse;
|
||||
ChannelInfo mWorkerChannelInfo;
|
||||
const nsCString mScriptSpec;
|
||||
const nsCString mResponseURLSpec;
|
||||
|
||||
RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
InternalResponse* aInternalResponse,
|
||||
const ChannelInfo& aWorkerChannelInfo,
|
||||
const nsCString& aScriptSpec)
|
||||
const nsCString& aScriptSpec,
|
||||
const nsACString& aResponseURLSpec)
|
||||
: mInterceptedChannel(aChannel)
|
||||
, mInternalResponse(aInternalResponse)
|
||||
, mWorkerChannelInfo(aWorkerChannelInfo)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mResponseURLSpec(aResponseURLSpec)
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -253,7 +259,8 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
|
||||
event = new FinishResponse(data->mInterceptedChannel,
|
||||
data->mInternalResponse,
|
||||
data->mWorkerChannelInfo,
|
||||
data->mScriptSpec);
|
||||
data->mScriptSpec,
|
||||
data->mResponseURLSpec);
|
||||
} else {
|
||||
event = new CancelChannelRunnable(data->mInterceptedChannel,
|
||||
NS_ERROR_INTERCEPTION_FAILED);
|
||||
@ -356,9 +363,22 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
||||
return;
|
||||
}
|
||||
|
||||
// When an opaque response is encountered, we need the original channel's principal
|
||||
// to reflect the final URL. Non-opaque responses are either same-origin or CORS-enabled
|
||||
// cross-origin responses, which are treated as same-origin by consumers.
|
||||
nsCString responseURL;
|
||||
if (response->Type() == ResponseType::Opaque) {
|
||||
ir->GetUnfilteredUrl(responseURL);
|
||||
if (NS_WARN_IF(responseURL.IsEmpty())) {
|
||||
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTION_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, ir,
|
||||
worker->GetChannelInfo(),
|
||||
mScriptSpec));
|
||||
mScriptSpec,
|
||||
responseURL));
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
ir->GetUnfilteredBody(getter_AddRefs(body));
|
||||
// Errors and redirects may not have a body.
|
||||
|
@ -78,12 +78,18 @@ InterceptedJARChannel::SynthesizeHeader(const nsACString& aName,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedJARChannel::FinishSynthesizedResponse()
|
||||
InterceptedJARChannel::FinishSynthesizedResponse(const nsACString& aFinalURLSpec)
|
||||
{
|
||||
if (NS_WARN_IF(!mChannel)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!aFinalURLSpec.IsEmpty()) {
|
||||
// We don't support rewriting responses for JAR channels where the principal
|
||||
// needs to be modified.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
mChannel->OverrideWithSynthesizedResponse(mSynthesizedInput, mContentType);
|
||||
|
||||
mResponseBody = nullptr;
|
||||
|
@ -27,7 +27,7 @@ class ChannelInfo;
|
||||
* which do not implement nsIChannel.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(6be00c37-2e85-42ee-b53c-e6508ce4cef0)]
|
||||
[scriptable, uuid(afe6aae6-a80d-405b-856e-df36c19bf3c8)]
|
||||
interface nsIInterceptedChannel : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -51,9 +51,11 @@ interface nsIInterceptedChannel : nsISupports
|
||||
/**
|
||||
* Instruct a channel that has been intercepted that a response has been
|
||||
* synthesized and can now be read. No further header modification is allowed
|
||||
* after this point.
|
||||
* after this point. The caller may optionally pass a spec for a URL that
|
||||
* this response originates from; an empty string will cause the original
|
||||
* intercepted request's URL to be used instead.
|
||||
*/
|
||||
void finishSynthesizedResponse();
|
||||
void finishSynthesizedResponse(in ACString finalURLSpec);
|
||||
|
||||
/**
|
||||
* Cancel the pending intercepted request.
|
||||
|
@ -267,6 +267,21 @@ HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
bool synthesized = false;
|
||||
nsresult rv = GetResponseSynthesized(&synthesized);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If this channel is marked as awaiting a synthesized response,
|
||||
// modifying certain load flags can interfere with the implementation
|
||||
// of the network interception logic. This takes care of a couple
|
||||
// known cases that attempt to mark channels as anonymous due
|
||||
// to cross-origin redirects; since the response is entirely synthesized
|
||||
// this is an unnecessary precaution.
|
||||
// This should be removed when bug 1201683 is fixed.
|
||||
if (synthesized && aLoadFlags != mLoadFlags) {
|
||||
aLoadFlags &= ~LOAD_ANONYMOUS;
|
||||
}
|
||||
|
||||
mLoadFlags = aLoadFlags;
|
||||
mForceMainDocumentChannel = (aLoadFlags & LOAD_DOCUMENT_URI);
|
||||
return NS_OK;
|
||||
|
@ -2444,6 +2444,12 @@ HttpChannelChild::ForceIntercepted()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpChannelChild::ForceIntercepted(uint64_t aInterceptionID)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvIssueDeprecationWarning(const uint32_t& warning,
|
||||
const bool& asError)
|
||||
|
@ -88,6 +88,7 @@ public:
|
||||
NS_IMETHOD GetLocalPort(int32_t* port) override;
|
||||
NS_IMETHOD GetRemoteAddress(nsACString& addr) override;
|
||||
NS_IMETHOD GetRemotePort(int32_t* port) override;
|
||||
NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override;
|
||||
// nsISupportsPriority
|
||||
NS_IMETHOD SetPriority(int32_t value) override;
|
||||
// nsIClassOfService
|
||||
|
@ -203,7 +203,9 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mChannel->FinishSynthesizedResponse();
|
||||
// The URL passed as an argument here doesn't matter, since the child will
|
||||
// receive a redirection notification as a result of this synthesized response.
|
||||
mChannel->FinishSynthesizedResponse(EmptyCString());
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
@ -179,7 +179,7 @@ InterceptedChannelChrome::SynthesizeHeader(const nsACString& aName, const nsACSt
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelChrome::FinishSynthesizedResponse()
|
||||
InterceptedChannelChrome::FinishSynthesizedResponse(const nsACString& aFinalURLSpec)
|
||||
{
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
@ -208,23 +208,38 @@ InterceptedChannelChrome::FinishSynthesizedResponse()
|
||||
mSynthesizedResponseHead.ref(), securityInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
mChannel->GetURI(getter_AddRefs(uri));
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
mChannel->GetURI(getter_AddRefs(originalURI));
|
||||
|
||||
bool usingSSL = false;
|
||||
uri->SchemeIs("https", &usingSSL);
|
||||
|
||||
// Then we open a real cache entry to read the synthesized response from.
|
||||
rv = mChannel->OpenCacheEntry(usingSSL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSynthesizedCacheEntry = nullptr;
|
||||
|
||||
if (!mChannel->AwaitingCacheCallbacks()) {
|
||||
rv = mChannel->ContinueConnect();
|
||||
nsCOMPtr<nsIURI> responseURI;
|
||||
if (!aFinalURLSpec.IsEmpty()) {
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(responseURI), aFinalURLSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
responseURI = originalURI;
|
||||
}
|
||||
|
||||
bool equal = false;
|
||||
originalURI->Equals(responseURI, &equal);
|
||||
if (!equal) {
|
||||
nsresult rv =
|
||||
mChannel->StartRedirectChannelToURI(responseURI, nsIChannelEventSink::REDIRECT_INTERNAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
bool usingSSL = false;
|
||||
responseURI->SchemeIs("https", &usingSSL);
|
||||
|
||||
// Then we open a real cache entry to read the synthesized response from.
|
||||
rv = mChannel->OpenCacheEntry(usingSSL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mSynthesizedCacheEntry = nullptr;
|
||||
|
||||
if (!mChannel->AwaitingCacheCallbacks()) {
|
||||
rv = mChannel->ContinueConnect();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
mChannel = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -330,7 +345,7 @@ InterceptedChannelContent::SynthesizeHeader(const nsACString& aName, const nsACS
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InterceptedChannelContent::FinishSynthesizedResponse()
|
||||
InterceptedChannelContent::FinishSynthesizedResponse(const nsACString& aFinalURLSpec)
|
||||
{
|
||||
if (NS_WARN_IF(!mChannel)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
nsICacheEntry* aEntry);
|
||||
|
||||
NS_IMETHOD ResetInterception() override;
|
||||
NS_IMETHOD FinishSynthesizedResponse() override;
|
||||
NS_IMETHOD FinishSynthesizedResponse(const nsACString& aFinalURLSpec) override;
|
||||
NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
|
||||
NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override;
|
||||
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override;
|
||||
@ -100,7 +100,7 @@ public:
|
||||
nsIStreamListener* aListener);
|
||||
|
||||
NS_IMETHOD ResetInterception() override;
|
||||
NS_IMETHOD FinishSynthesizedResponse() override;
|
||||
NS_IMETHOD FinishSynthesizedResponse(const nsACString& aFinalURLSpec) override;
|
||||
NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
|
||||
NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override;
|
||||
NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override;
|
||||
|
@ -2010,12 +2010,19 @@ nsHttpChannel::StartRedirectChannelToURI(nsIURI *upgradedURI, uint32_t flags)
|
||||
if (!(flags & nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
|
||||
// Ensure that internally-redirected channels cannot be intercepted, which would look
|
||||
// like two separate requests to the nsINetworkInterceptController.
|
||||
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
|
||||
rv = mRedirectChannel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
|
||||
rv = mRedirectChannel->SetLoadFlags(loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mInterceptCache == INTERCEPTED) {
|
||||
nsCOMPtr<nsIHttpChannelInternal> httpRedirect = do_QueryInterface(mRedirectChannel);
|
||||
if (httpRedirect) {
|
||||
httpRedirect->ForceIntercepted(mInterceptionID);
|
||||
}
|
||||
} else {
|
||||
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
|
||||
rv = mRedirectChannel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
|
||||
rv = mRedirectChannel->SetLoadFlags(loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
PushRedirectAsyncFunc(
|
||||
@ -2993,11 +3000,10 @@ nsHttpChannel::OpenCacheEntry(bool isHttps)
|
||||
if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY)
|
||||
cacheEntryOpenFlags |= nsICacheStorage::OPEN_BYPASS_IF_BUSY;
|
||||
|
||||
if (mPostID) {
|
||||
extension.Append(nsPrintfCString("%d", mPostID));
|
||||
}
|
||||
if (PossiblyIntercepted()) {
|
||||
extension.Append(nsPrintfCString("u%lld", mInterceptionID));
|
||||
} else if (mPostID) {
|
||||
extension.Append(nsPrintfCString("%d", mPostID));
|
||||
}
|
||||
|
||||
// If this channel should be intercepted, we do not open a cache entry for this channel
|
||||
@ -4984,7 +4990,7 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (ShouldIntercept()) {
|
||||
if (mInterceptCache != INTERCEPTED && ShouldIntercept()) {
|
||||
mInterceptCache = MAYBE_INTERCEPT;
|
||||
SetCouldBeSynthesized();
|
||||
}
|
||||
@ -5344,6 +5350,21 @@ nsHttpChannel::SetupFallbackChannel(const char *aFallbackKey)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::ForceIntercepted(uint64_t aInterceptionID)
|
||||
{
|
||||
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
|
||||
|
||||
if (NS_WARN_IF(mLoadFlags & LOAD_BYPASS_SERVICE_WORKER)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
MarkIntercepted();
|
||||
mResponseCouldBeSynthesized = true;
|
||||
mInterceptionID = aInterceptionID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsISupportsPriority
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -134,6 +134,7 @@ public:
|
||||
NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
|
||||
// nsIHttpChannelInternal
|
||||
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
|
||||
NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override;
|
||||
// nsISupportsPriority
|
||||
NS_IMETHOD SetPriority(int32_t value) override;
|
||||
// nsIClassOfService
|
||||
@ -433,8 +434,9 @@ private:
|
||||
MAYBE_INTERCEPT, // interception in progress, but can be cancelled
|
||||
INTERCEPTED, // a synthesized response has been provided
|
||||
} mInterceptCache;
|
||||
// Unique ID of this channel for the interception purposes.
|
||||
const uint64_t mInterceptionID;
|
||||
// ID of this channel for the interception purposes. Unique unless this
|
||||
// channel is replacing an intercepted one via an redirection.
|
||||
uint64_t mInterceptionID;
|
||||
|
||||
bool PossiblyIntercepted() {
|
||||
return mInterceptCache != DO_NOT_INTERCEPT;
|
||||
|
@ -39,7 +39,7 @@ interface nsIHttpUpgradeListener : nsISupports
|
||||
* using any feature exposed by this interface, be aware that this interface
|
||||
* will change and you will be broken. You have been warned.
|
||||
*/
|
||||
[scriptable, uuid(99767aaf-937d-4f2f-8990-bc79bd7c0ece)]
|
||||
[scriptable, uuid(9eabaac6-cc7c-4ca1-9430-65f2daaa578f)]
|
||||
interface nsIHttpChannelInternal : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -222,6 +222,13 @@ interface nsIHttpChannelInternal : nsISupports
|
||||
|
||||
readonly attribute PRTime lastModifiedTime;
|
||||
|
||||
/**
|
||||
* Force a channel that has not been AsyncOpen'ed to skip any check for possible
|
||||
* interception and proceed immediately to open a previously-synthesized cache
|
||||
* entry using the provided ID.
|
||||
*/
|
||||
void forceIntercepted(in uint64_t aInterceptionID);
|
||||
|
||||
readonly attribute boolean responseSynthesized;
|
||||
|
||||
/**
|
||||
|
@ -63,7 +63,7 @@ function make_channel(url, body, cb) {
|
||||
synthesized.data = body;
|
||||
|
||||
NetUtil.asyncCopy(synthesized, channel.responseBody, function() {
|
||||
channel.finishSynthesizedResponse();
|
||||
channel.finishSynthesizedResponse('');
|
||||
});
|
||||
}
|
||||
if (cb) {
|
||||
@ -150,7 +150,7 @@ add_test(function() {
|
||||
synthesized.data = NON_REMOTE_BODY;
|
||||
NetUtil.asyncCopy(synthesized, channel.responseBody, function() {
|
||||
channel.synthesizeHeader("Content-Length", NON_REMOTE_BODY.length);
|
||||
channel.finishSynthesizedResponse();
|
||||
channel.finishSynthesizedResponse('');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -178,7 +178,7 @@ add_test(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");
|
||||
intercepted.finishSynthesizedResponse();
|
||||
intercepted.finishSynthesizedResponse('');
|
||||
});
|
||||
});
|
||||
chan.asyncOpen(new ChannelListener(handle_synthesized_response, null,
|
||||
@ -220,7 +220,7 @@ add_test(function() {
|
||||
|
||||
NetUtil.asyncCopy(synthesized, intercepted.responseBody, function() {
|
||||
let channel = intercepted.channel;
|
||||
intercepted.finishSynthesizedResponse();
|
||||
intercepted.finishSynthesizedResponse('');
|
||||
channel.cancel(Cr.NS_BINDING_ABORTED);
|
||||
});
|
||||
});
|
||||
@ -237,7 +237,7 @@ add_test(function() {
|
||||
|
||||
NetUtil.asyncCopy(synthesized, intercepted.responseBody, function() {
|
||||
intercepted.channel.cancel(Cr.NS_BINDING_ABORTED);
|
||||
intercepted.finishSynthesizedResponse();
|
||||
intercepted.finishSynthesizedResponse('');
|
||||
});
|
||||
});
|
||||
chan.asyncOpen(new ChannelListener(run_next_test, null,
|
||||
|
@ -106,6 +106,12 @@
|
||||
"url": "/_mozilla/service-workers/service-worker/extendable-event-waituntil.https.html"
|
||||
}
|
||||
],
|
||||
"service-workers/service-worker/fetch-canvas-tainting-cache.https.html": [
|
||||
{
|
||||
"path": "service-workers/service-worker/fetch-canvas-tainting-cache.https.html",
|
||||
"url": "/_mozilla/service-workers/service-worker/fetch-canvas-tainting-cache.https.html"
|
||||
}
|
||||
],
|
||||
"service-workers/service-worker/fetch-canvas-tainting.https.html": [
|
||||
{
|
||||
"path": "service-workers/service-worker/fetch-canvas-tainting.https.html",
|
||||
|
@ -0,0 +1,5 @@
|
||||
[fetch-request-css-base-url.https.html]
|
||||
type: testharness
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1201160
|
||||
[CSS's base URL must be the request URL even when fetched from other URL.]
|
||||
expected: FAIL
|
@ -0,0 +1,3 @@
|
||||
[worker-interception-iframe.https.html]
|
||||
type: testharness
|
||||
disabled: not a test
|
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Service Worker: canvas tainting of the fetched image using cached responses</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/get-host-info.sub.js"></script>
|
||||
<script src="resources/test-helpers.sub.js?pipe=sub"></script>
|
||||
<body>
|
||||
<script>
|
||||
async_test(function(t) {
|
||||
var SCOPE = 'resources/fetch-canvas-tainting-iframe.html?cache';
|
||||
var SCRIPT = 'resources/fetch-rewrite-worker.js';
|
||||
var host_info = get_host_info();
|
||||
|
||||
login_https(t)
|
||||
.then(function() {
|
||||
return service_worker_unregister_and_register(t, SCRIPT, SCOPE);
|
||||
})
|
||||
.then(function(registration) {
|
||||
return wait_for_state(t, registration.installing, 'activated');
|
||||
})
|
||||
.then(function() { return with_iframe(SCOPE); })
|
||||
.then(function(frame) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var channel = new MessageChannel();
|
||||
channel.port1.onmessage = t.step_func(function(e) {
|
||||
assert_equals(e.data.results, 'finish');
|
||||
frame.remove();
|
||||
service_worker_unregister_and_done(t, SCOPE);
|
||||
});
|
||||
frame.contentWindow.postMessage({},
|
||||
host_info['HTTPS_ORIGIN'],
|
||||
[channel.port2]);
|
||||
});
|
||||
})
|
||||
.catch(unreached_rejection(t));
|
||||
}, 'Verify canvas tainting of fetched image in a Service Worker');
|
||||
</script>
|
||||
</body>
|
@ -65,7 +65,8 @@ function redirect_fetch_test(t, test) {
|
||||
};
|
||||
frame.contentWindow.postMessage({
|
||||
url: url,
|
||||
request_init: test.request_init
|
||||
request_init: test.request_init,
|
||||
redirect_dest: test.redirect_dest,
|
||||
}, '*', [channel.port2]);
|
||||
});
|
||||
|
||||
|
@ -3,11 +3,26 @@
|
||||
<script>
|
||||
var image_path = base_path() + 'fetch-access-control.py?PNGIMAGE';
|
||||
var host_info = get_host_info();
|
||||
var params = get_query_params(location.href);
|
||||
|
||||
var NOT_TAINTED = 'NOT_TAINTED';
|
||||
var TAINTED = 'TAINTED';
|
||||
var LOAD_ERROR = 'LOAD_ERROR';
|
||||
|
||||
function get_query_params(url) {
|
||||
var search = (new URL(url)).search;
|
||||
if (!search) {
|
||||
return {};
|
||||
}
|
||||
var ret = {};
|
||||
var params = search.substring(1).split('&');
|
||||
params.forEach(function(param) {
|
||||
var element = param.split('=');
|
||||
ret[decodeURIComponent(element[0])] = decodeURIComponent(element[1]);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
function create_test_case_promise(url, cross_origin) {
|
||||
return new Promise(function(resolve) {
|
||||
var img = new Image();
|
||||
@ -35,6 +50,10 @@ function create_test_case_promise(url, cross_origin) {
|
||||
}
|
||||
|
||||
function create_test_promise(url, cross_origin, expected_result) {
|
||||
if (params['cache']) {
|
||||
url += "&cache";
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
create_test_case_promise(url, cross_origin)
|
||||
.then(function(result) {
|
||||
@ -140,7 +159,7 @@ window.addEventListener('message', function(evt) {
|
||||
remote_image_url +
|
||||
'&mode=same-origin&url=' + encodeURIComponent(image_url),
|
||||
'',
|
||||
NOT_TAINTED),
|
||||
TAINTED),
|
||||
create_test_promise(
|
||||
remote_image_url +
|
||||
'&mode=same-origin&url=' + encodeURIComponent(image_url),
|
||||
@ -191,9 +210,7 @@ window.addEventListener('message', function(evt) {
|
||||
encodeURIComponent(remote_image_url +
|
||||
'&ACAOrigin=' + host_info['HTTPS_ORIGIN']),
|
||||
'',
|
||||
TAINTED), // We expect TAINTED since the default origin behavior here
|
||||
// is taint, and it doesn't matter what kind of fetch the
|
||||
// SW performs.
|
||||
NOT_TAINTED),
|
||||
create_test_promise(
|
||||
image_url +
|
||||
'&mode=cors&url=' +
|
||||
|
@ -3,6 +3,13 @@ window.addEventListener('message', function(evt) {
|
||||
var port = evt.ports[0];
|
||||
var data = evt.data;
|
||||
fetch(new Request(data.url, data.request_init)).then(function(response) {
|
||||
if (data.request_init.mode === 'no-cors' && data.redirect_dest != 'same-origin') {
|
||||
if (response.type === 'opaque') {
|
||||
return {result: 'success', detail: ''};
|
||||
} else {
|
||||
return {result: 'failure', detail: 'expected opaque response'};
|
||||
}
|
||||
}
|
||||
return response.json();
|
||||
}).then(function(body) {
|
||||
port.postMessage({result: body.result, detail: body.detail});
|
||||
|
@ -80,7 +80,25 @@ self.addEventListener('fetch', function(event) {
|
||||
expectedType
|
||||
})));
|
||||
}
|
||||
resolve(response);
|
||||
|
||||
if (params['cache']) {
|
||||
var cacheName = "cached-fetches-" + Date.now();
|
||||
var cache;
|
||||
var cachedResponse;
|
||||
return self.caches.open(cacheName).then(function(opened) {
|
||||
cache = opened;
|
||||
return cache.put(request, response);
|
||||
}).then(function() {
|
||||
return cache.match(request);
|
||||
}).then(function(cached) {
|
||||
cachedResponse = cached;
|
||||
return self.caches.delete(cacheName);
|
||||
}).then(function() {
|
||||
resolve(cachedResponse);
|
||||
});
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
}, reject)
|
||||
}));
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user