mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:34:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- partial of Bug 1153658 - browser_compartments.js logspam. r=yoric (8e2c21aa5) - Bug 1178653 - Refactor construction code to use an interface consistent with the spec, with the one exception using an out-of-the-way, differently-named method. r=efaust (d316259d7) - Bug 1175098 - PerformanceStats for e10s. r=felipe, r=mconley (515acb8d7) - Bug 1147664 - Detailed mode for PerformanceStats (low-level). r=jandem (dda8d84de) - Bug 1147664 - Detailed mode for PerformanceStats (high-level). r=mossop (b86076568) - Bug 1164304 - Run all fetch tests in the service worker context as well; r=nsm (e20fa8bfd) - Bug 1143981 - Reroute all fetch tests through a transparent service worker; r=nsm (5196acc57) - Bug 1122161 - Redirected channels should respect skip service worker flag. r=nsm (f4288392e) - Bug 1170937 - Set the URL on the Response object created from a fetch() properly if the underlying channel gets redirected; r=baku (45febabb3) - Bug 1173029 - Remove mFinalURL from InternalResponse; r=baku a=KWierso (6bdc1083b) - Bug 1137683 - Use a loadgroup derived from the document's when updating a ServiceWorker; r=bkelly (fabaa2602) - Bug 1164397 - Part 1: Use the original channel URI for constructing the cache entry key when we're dealing with an intercepted channel; r=mcmanus (b20ab36c7) - Bug 1164397 - Part 2: Add an API for overriding the original URI on HttpChannelBase; r=mcmanus (20021722f) - Bug 1164397 - Part 3: Add an API for overriding the original URI on nsJARChannel; r=jdm (492b6fd6f) - Bug 1164397 - Part 4: Add infromation about whether a channel was redirected to ChannelInfo; r=jdm (e2ce84660) - Bug 1164397 - Part 5: Save the redirected flag and the redirected URI in the DOM cache; r=bkelly (7d2d1fc92) - Bug 1162018 - Add an automated test to ensure that a redirected Request won't be visible to a service worker if it had triggered the original fetch(); r=jdm (0397a073f) - Bug 1164397 - Part 6: Add a test case for the service worker responding with a redirected Response; r=jdm (e83e0bee4) - Bug 1164397 - Part 7: Add a test case for the redirected Response object being stored in the DOM Cache; r=jdm (7a82916d8) - Bug 1169296 - Intercepting top-level document loads is not working with JAR channels. Tests. r=jdm (fe8f128c5) - Bug 1171285 - Part 1: Add a script for regenerating the application.zip used by test_app_protocol.html; r=jdm (ec303b3b2) - Bug 1171285 - Part 2: Fix test_app_protocol.html to finish both index.html and controlled.html tests; r=jdm (2e68e6665) - Bug 1169613 - Use content type of synthesized response for JAR channel requests if available. Tests. r=jdm (b0095fc3b) - Bug 1164397 - Part 8: Add a test case for the service worker for an app:// URI responding with a redirected Response; r=jdm (460e834c9) - Bug 1169044 - Patch 3 - Store and set principal with script URI on ServiceWorkers. r=ehsan (6e0b0102a) - Bug 1164397 - Part 9: Add a test case for the service worker for an app:// URI responding with a redirected HTTPS response; r=jdm (1be195f5a) - Bug 1164397 - Part 10: Add a test case for the service worker for an app:// URI responding with cached HTTP and HTTPS responses; r=jdm# Please enter the commit message for your changes. Lines starting (56432b7b5) - Bug 1164397 - Part 11: Add a test case for the service worker responding to HTTPS normal and cached Responses; r=jdm (6ec238455) - Bug 1164397 - Part 12: Add a test case for the service worker responding to normal and cached HTTP->HTTPS responses; r=jdm (925a1970f) - Bug 1190074 - PerformanceGroup now uses mozilla::RefPtr;r=jandem (53dc0a640) - Bug 1169086 followup: Add missing 'override' annotation to VerifyTraceProtoAndIfaceCacheCalledTracer::trace() method decl. rs=ehsan (cdedce447) - Bug 1172824: Initialize a few members in CompartmentCheckTracer (CID 1304705); r=terrence (3db40160c) - missing bit of 1166678 (9fb0cceeb) - Bug 1139473: File some metadata for the js/src/ subdirectory; r=jorendorff (9dc4a29a7) - Bug 1173889 - Strongly type the CallbackTracer dispatch function; r=jonco, r=mccr8 (19b47dc70)
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -96,6 +96,7 @@ http://example.net:80 privileged
|
||||
http://prefixexample.com:80
|
||||
|
||||
https://example.com:443 privileged
|
||||
https://example.org:443 privileged
|
||||
https://test1.example.com:443 privileged
|
||||
https://test2.example.com:443 privileged
|
||||
https://sub1.test1.example.com:443 privileged
|
||||
|
||||
@@ -115,6 +115,23 @@ OriginAttributes::PopulateFromSuffix(const nsACString& aStr)
|
||||
return params->ForEach(iterator);
|
||||
}
|
||||
|
||||
bool
|
||||
OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,
|
||||
nsACString& aOriginNoSuffix)
|
||||
{
|
||||
// RFindChar is only available on nsCString.
|
||||
nsCString origin(aOrigin);
|
||||
int32_t pos = origin.RFindChar('!');
|
||||
|
||||
if (pos == kNotFound) {
|
||||
aOriginNoSuffix = origin;
|
||||
return true;
|
||||
}
|
||||
|
||||
aOriginNoSuffix = Substring(origin, 0, pos);
|
||||
return PopulateFromSuffix(Substring(origin, pos));
|
||||
}
|
||||
|
||||
void
|
||||
OriginAttributes::CookieJar(nsACString& aStr)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,11 @@ public:
|
||||
bool PopulateFromSuffix(const nsACString& aStr);
|
||||
|
||||
void CookieJar(nsACString& aStr);
|
||||
|
||||
// Populates the attributes from a string like
|
||||
// |uri!key1=value1&key2=value2| and returns the uri without the suffix.
|
||||
bool PopulateFromOrigin(const nsACString& aOrigin,
|
||||
nsACString& aOriginNoSuffix);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -523,7 +523,7 @@ struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
|
||||
: JS::CallbackTracer(rt), ok(false)
|
||||
{}
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) {
|
||||
void onChild(const JS::GCCellPtr&) override {
|
||||
// We don't do anything here, we only want to verify that
|
||||
// TraceProtoAndIfaceCache was called.
|
||||
}
|
||||
|
||||
Vendored
+2
@@ -7,6 +7,7 @@ include protocol PCachePushStream;
|
||||
include protocol PCacheStreamControl;
|
||||
include InputStreamParams;
|
||||
include ChannelInfo;
|
||||
include PBackgroundSharedTypes;
|
||||
|
||||
using HeadersGuardEnum from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestCredentials from "mozilla/dom/cache/IPCUtils.h";
|
||||
@@ -83,6 +84,7 @@ struct CacheResponse
|
||||
HeadersGuardEnum headersGuard;
|
||||
CacheReadStreamOrVoid body;
|
||||
IPCChannelInfo channelInfo;
|
||||
OptionalPrincipalInfo principalInfo;
|
||||
};
|
||||
|
||||
union CacheResponseOrVoid
|
||||
|
||||
Vendored
+73
-3
@@ -19,6 +19,7 @@
|
||||
#include "nsCRT.h"
|
||||
#include "nsHttp.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/dom/HeadersBinding.h"
|
||||
#include "mozilla/dom/RequestBinding.h"
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
@@ -29,11 +30,11 @@ namespace dom {
|
||||
namespace cache {
|
||||
namespace db {
|
||||
|
||||
const int32_t kMaxWipeSchemaVersion = 10;
|
||||
const int32_t kMaxWipeSchemaVersion = 11;
|
||||
|
||||
namespace {
|
||||
|
||||
const int32_t kLatestSchemaVersion = 10;
|
||||
const int32_t kLatestSchemaVersion = 11;
|
||||
const int32_t kMaxEntriesPerStatement = 255;
|
||||
|
||||
const uint32_t kPageSize = 4 * 1024;
|
||||
@@ -301,6 +302,11 @@ CreateSchema(mozIStorageConnection* aConn)
|
||||
"response_headers_guard INTEGER NOT NULL, "
|
||||
"response_body_id TEXT NULL, "
|
||||
"response_security_info_id INTEGER NULL REFERENCES security_info(id), "
|
||||
"response_principal_info TEXT NOT NULL, "
|
||||
"response_redirected INTEGER NOT NULL, "
|
||||
// Note that response_redirected_url is either going to be empty, or
|
||||
// it's going to be a URL different than response_url.
|
||||
"response_redirected_url TEXT NOT NULL, "
|
||||
"cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE"
|
||||
");"
|
||||
));
|
||||
@@ -1524,6 +1530,9 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
"response_headers_guard, "
|
||||
"response_body_id, "
|
||||
"response_security_info_id, "
|
||||
"response_principal_info, "
|
||||
"response_redirected, "
|
||||
"response_redirected_url, "
|
||||
"cache_id "
|
||||
") VALUES ("
|
||||
":request_method, "
|
||||
@@ -1544,6 +1553,9 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
":response_headers_guard, "
|
||||
":response_body_id, "
|
||||
":response_security_info_id, "
|
||||
":response_principal_info, "
|
||||
":response_redirected, "
|
||||
":response_redirected_url, "
|
||||
":cache_id "
|
||||
");"
|
||||
), getter_AddRefs(state));
|
||||
@@ -1623,6 +1635,36 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
nsAutoCString serializedInfo;
|
||||
// We only allow content serviceworkers right now.
|
||||
if (aResponse.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
|
||||
const mozilla::ipc::PrincipalInfo& principalInfo =
|
||||
aResponse.principalInfo().get_PrincipalInfo();
|
||||
MOZ_ASSERT(principalInfo.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
|
||||
const mozilla::ipc::ContentPrincipalInfo& cInfo =
|
||||
principalInfo.get_ContentPrincipalInfo();
|
||||
|
||||
serializedInfo.Append(cInfo.spec());
|
||||
|
||||
MOZ_ASSERT(cInfo.appId() != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
||||
OriginAttributes attrs(cInfo.appId(), cInfo.isInBrowserElement());
|
||||
nsAutoCString suffix;
|
||||
attrs.CreateSuffix(suffix);
|
||||
serializedInfo.Append(suffix);
|
||||
}
|
||||
|
||||
rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("response_principal_info"),
|
||||
serializedInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("response_redirected"),
|
||||
aResponse.channelInfo().redirected() ? 1 : 0);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("response_redirected_url"),
|
||||
aResponse.channelInfo().redirectedURI());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = state->BindInt64ByName(NS_LITERAL_CSTRING("cache_id"), aCacheId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
@@ -1714,6 +1756,9 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
"entries.response_status_text, "
|
||||
"entries.response_headers_guard, "
|
||||
"entries.response_body_id, "
|
||||
"entries.response_principal_info, "
|
||||
"entries.response_redirected, "
|
||||
"entries.response_redirected_url, "
|
||||
"security_info.data "
|
||||
"FROM entries "
|
||||
"LEFT OUTER JOIN security_info "
|
||||
@@ -1761,7 +1806,32 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
}
|
||||
|
||||
rv = state->GetBlobAsUTF8String(6, aSavedResponseOut->mValue.channelInfo().securityInfo());
|
||||
nsAutoCString serializedInfo;
|
||||
rv = state->GetUTF8String(6, serializedInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
aSavedResponseOut->mValue.principalInfo() = void_t();
|
||||
if (!serializedInfo.IsEmpty()) {
|
||||
nsAutoCString originNoSuffix;
|
||||
OriginAttributes attrs;
|
||||
fprintf(stderr, "\n%s\n", serializedInfo.get());
|
||||
if (!attrs.PopulateFromOrigin(serializedInfo, originNoSuffix)) {
|
||||
NS_WARNING("Something went wrong parsing a serialized principal!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aSavedResponseOut->mValue.principalInfo() =
|
||||
mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, originNoSuffix);
|
||||
}
|
||||
|
||||
int32_t redirected;
|
||||
rv = state->GetInt32(7, &redirected);
|
||||
aSavedResponseOut->mValue.channelInfo().redirected() = !!redirected;
|
||||
|
||||
rv = state->GetUTF8String(8, aSavedResponseOut->mValue.channelInfo().redirectedURI());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = state->GetBlobAsUTF8String(9, aSavedResponseOut->mValue.channelInfo().securityInfo());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
|
||||
Vendored
+9
@@ -225,6 +225,11 @@ TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
|
||||
ToHeadersEntryList(aOut.headers(), headers);
|
||||
aOut.headersGuard() = headers->Guard();
|
||||
aOut.channelInfo() = aIn.GetChannelInfo().AsIPCChannelInfo();
|
||||
if (aIn.GetPrincipalInfo()) {
|
||||
aOut.principalInfo() = *aIn.GetPrincipalInfo();
|
||||
} else {
|
||||
aOut.principalInfo() = void_t();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -291,6 +296,10 @@ TypeUtils::ToResponse(const CacheResponse& aIn)
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
|
||||
ir->InitChannelInfo(aIn.channelInfo());
|
||||
if (aIn.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
|
||||
UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(aIn.principalInfo().get_PrincipalInfo()));
|
||||
ir->SetPrincipalInfo(Move(info));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
|
||||
ir->SetBody(stream);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mozilla/ipc/ChannelInfo.h"
|
||||
#include "nsIJARChannel.h"
|
||||
#include "nsJARChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@@ -20,6 +21,7 @@ using namespace mozilla::dom;
|
||||
void
|
||||
ChannelInfo::InitFromChannel(nsIChannel* aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
|
||||
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
@@ -28,6 +30,20 @@ ChannelInfo::InitFromChannel(nsIChannel* aChannel)
|
||||
SetSecurityInfo(securityInfo);
|
||||
}
|
||||
|
||||
nsLoadFlags loadFlags = 0;
|
||||
aChannel->GetLoadFlags(&loadFlags);
|
||||
mRedirected = (loadFlags & nsIChannel::LOAD_REPLACE);
|
||||
if (mRedirected) {
|
||||
// Save the spec and not the nsIURI object itself, since those objects are
|
||||
// not thread-safe, and releasing them somewhere other than the main thread
|
||||
// is not possible.
|
||||
nsCOMPtr<nsIURI> redirectedURI;
|
||||
aChannel->GetURI(getter_AddRefs(redirectedURI));
|
||||
if (redirectedURI) {
|
||||
redirectedURI->GetSpec(mRedirectedURISpec);
|
||||
}
|
||||
}
|
||||
|
||||
mInited = true;
|
||||
}
|
||||
|
||||
@@ -37,6 +53,8 @@ ChannelInfo::InitFromIPCChannelInfo(const ipc::IPCChannelInfo& aChannelInfo)
|
||||
MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
|
||||
|
||||
mSecurityInfo = aChannelInfo.securityInfo();
|
||||
mRedirectedURISpec = aChannelInfo.redirectedURI();
|
||||
mRedirected = aChannelInfo.redirected();
|
||||
|
||||
mInited = true;
|
||||
}
|
||||
@@ -56,16 +74,22 @@ ChannelInfo::SetSecurityInfo(nsISupports* aSecurityInfo)
|
||||
nsresult
|
||||
ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mInited);
|
||||
|
||||
// These pointers may be null at this point. They must be checked before
|
||||
// being dereferenced.
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
nsCOMPtr<nsIJARChannel> jarChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
|
||||
if (!mSecurityInfo.IsEmpty()) {
|
||||
nsCOMPtr<nsISupports> infoObj;
|
||||
nsresult rv = NS_DeserializeObject(mSecurityInfo, getter_AddRefs(infoObj));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (httpChannel) {
|
||||
net::HttpBaseChannel* httpBaseChannel =
|
||||
static_cast<net::HttpBaseChannel*>(httpChannel.get());
|
||||
@@ -74,8 +98,6 @@ ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIJARChannel> jarChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (NS_WARN_IF(!jarChannel)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -84,6 +106,30 @@ ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
if (mRedirected) {
|
||||
nsLoadFlags flags = 0;
|
||||
aChannel->GetLoadFlags(&flags);
|
||||
flags |= nsIChannel::LOAD_REPLACE;
|
||||
aChannel->SetLoadFlags(flags);
|
||||
|
||||
nsCOMPtr<nsIURI> redirectedURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(redirectedURI),
|
||||
mRedirectedURISpec);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (httpChannel) {
|
||||
net::HttpBaseChannel* httpBaseChannel =
|
||||
static_cast<net::HttpBaseChannel*>(httpChannel.get());
|
||||
httpBaseChannel->OverrideURI(redirectedURI);
|
||||
} else {
|
||||
if (NS_WARN_IF(!jarChannel)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
static_cast<nsJARChannel*>(jarChannel.get())->OverrideURI(redirectedURI);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -98,6 +144,8 @@ ChannelInfo::AsIPCChannelInfo() const
|
||||
IPCChannelInfo ipcInfo;
|
||||
|
||||
ipcInfo.securityInfo() = mSecurityInfo;
|
||||
ipcInfo.redirectedURI() = mRedirectedURISpec;
|
||||
ipcInfo.redirected() = mRedirected;
|
||||
|
||||
return ipcInfo;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#define mozilla_dom_ChannelInfo_h
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
@@ -42,12 +44,15 @@ public:
|
||||
|
||||
ChannelInfo()
|
||||
: mInited(false)
|
||||
, mRedirected(false)
|
||||
{
|
||||
}
|
||||
|
||||
ChannelInfo(const ChannelInfo& aRHS)
|
||||
: mSecurityInfo(aRHS.mSecurityInfo)
|
||||
, mRedirectedURISpec(aRHS.mRedirectedURISpec)
|
||||
, mInited(aRHS.mInited)
|
||||
, mRedirected(aRHS.mRedirected)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,7 +60,9 @@ public:
|
||||
operator=(const ChannelInfo& aRHS)
|
||||
{
|
||||
mSecurityInfo = aRHS.mSecurityInfo;
|
||||
mRedirectedURISpec = aRHS.mRedirectedURISpec;
|
||||
mInited = aRHS.mInited;
|
||||
mRedirected = aRHS.mRedirected;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -78,7 +85,9 @@ private:
|
||||
|
||||
private:
|
||||
nsCString mSecurityInfo;
|
||||
nsCString mRedirectedURISpec;
|
||||
bool mInited;
|
||||
bool mRedirected;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace ipc {
|
||||
struct IPCChannelInfo
|
||||
{
|
||||
nsCString securityInfo;
|
||||
nsCString redirectedURI;
|
||||
bool redirected;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
+21
-11
@@ -433,18 +433,18 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
|
||||
// "If request's referrer is a URL, let referrerSource be request's
|
||||
// referrer."
|
||||
//
|
||||
// This allows ServiceWorkers to function transparently when the referrer
|
||||
// of the intercepted request is already set.
|
||||
// XXXnsm - We never actually hit this from a fetch() call since both
|
||||
// fetch and Request() create a new internal request whose referrer is
|
||||
// always set to about:client. Should we just crash here instead until
|
||||
// someone tries to use FetchDriver for non-fetch() APIs?
|
||||
nsCOMPtr<nsIURI> referrerURI;
|
||||
rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return FailWithNetworkError();
|
||||
}
|
||||
|
||||
// FIXME(nsm): Can we assert that this case can only happen in
|
||||
// ServiceWorkers and assume null mDocument?
|
||||
rv =
|
||||
httpChan->SetReferrerWithPolicy(nullptr,
|
||||
httpChan->SetReferrerWithPolicy(referrerURI,
|
||||
mDocument ? mDocument->GetReferrerPolicy() :
|
||||
net::RP_Default);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@@ -564,14 +564,16 @@ FetchDriver::ContinueHttpFetchAfterNetworkFetch()
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse)
|
||||
FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI)
|
||||
{
|
||||
MOZ_ASSERT(aResponse);
|
||||
if (!aResponse->FinalURL()) {
|
||||
nsAutoCString reqURL;
|
||||
nsAutoCString reqURL;
|
||||
if (aFinalURI) {
|
||||
aFinalURI->GetSpec(reqURL);
|
||||
} else {
|
||||
mRequest->GetURL(reqURL);
|
||||
aResponse->SetUrl(reqURL);
|
||||
}
|
||||
aResponse->SetUrl(reqURL);
|
||||
|
||||
// FIXME(nsm): Handle mixed content check, step 7 of fetch.
|
||||
|
||||
@@ -600,7 +602,7 @@ FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse)
|
||||
void
|
||||
FetchDriver::BeginResponse(InternalResponse* aResponse)
|
||||
{
|
||||
nsRefPtr<InternalResponse> r = BeginAndGetFilteredResponse(aResponse);
|
||||
nsRefPtr<InternalResponse> r = BeginAndGetFilteredResponse(aResponse, nullptr);
|
||||
// Release the ref.
|
||||
}
|
||||
|
||||
@@ -723,9 +725,17 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
||||
response->InitChannelInfo(channel);
|
||||
|
||||
nsCOMPtr<nsIURI> channelURI;
|
||||
rv = channel->GetURI(getter_AddRefs(channelURI));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
FailWithNetworkError();
|
||||
// Cancel request.
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Resolves fetch() promise which may trigger code running in a worker. Make
|
||||
// sure the Response is fully initialized before calling this.
|
||||
mResponse = BeginAndGetFilteredResponse(response);
|
||||
mResponse = BeginAndGetFilteredResponse(response, channelURI);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
||||
@@ -88,8 +88,9 @@ private:
|
||||
nsresult HttpFetch(bool aCORSFlag = false, bool aCORSPreflightFlag = false, bool aAuthenticationFlag = false);
|
||||
nsresult ContinueHttpFetchAfterNetworkFetch();
|
||||
// Returns the filtered response sent to the observer.
|
||||
// Callers who don't have access to a channel can pass null for aFinalURI.
|
||||
already_AddRefed<InternalResponse>
|
||||
BeginAndGetFilteredResponse(InternalResponse* aResponse);
|
||||
BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI);
|
||||
// Utility since not all cases need to do any post processing of the filtered
|
||||
// response.
|
||||
void BeginResponse(InternalResponse* aResponse);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "InternalResponse.h"
|
||||
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -14,13 +16,16 @@ namespace dom {
|
||||
|
||||
InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText)
|
||||
: mType(ResponseType::Default)
|
||||
, mFinalURL(false)
|
||||
, mStatus(aStatus)
|
||||
, mStatusText(aStatusText)
|
||||
, mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
|
||||
{
|
||||
}
|
||||
|
||||
InternalResponse::~InternalResponse()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
InternalResponse::Clone()
|
||||
{
|
||||
@@ -74,5 +79,41 @@ InternalResponse::CORSResponse()
|
||||
return cors.forget();
|
||||
}
|
||||
|
||||
void
|
||||
InternalResponse::SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo)
|
||||
{
|
||||
mPrincipalInfo = Move(aPrincipalInfo);
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
InternalResponse::OpaqueResponse()
|
||||
{
|
||||
MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
|
||||
nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
|
||||
response->mType = ResponseType::Opaque;
|
||||
response->mTerminationReason = mTerminationReason;
|
||||
response->mURL = mURL;
|
||||
response->mChannelInfo = mChannelInfo;
|
||||
if (mPrincipalInfo) {
|
||||
response->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
|
||||
}
|
||||
response->mWrappedResponse = this;
|
||||
return response.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
InternalResponse::CreateIncompleteCopy()
|
||||
{
|
||||
nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
|
||||
copy->mType = mType;
|
||||
copy->mTerminationReason = mTerminationReason;
|
||||
copy->mURL = mURL;
|
||||
copy->mChannelInfo = mChannelInfo;
|
||||
if (mPrincipalInfo) {
|
||||
copy->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
|
||||
}
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -12,8 +12,13 @@
|
||||
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
#include "mozilla/dom/ChannelInfo.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class InternalHeaders;
|
||||
@@ -41,18 +46,7 @@ public:
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
OpaqueResponse()
|
||||
{
|
||||
MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
|
||||
nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
|
||||
response->mType = ResponseType::Opaque;
|
||||
response->mTerminationReason = mTerminationReason;
|
||||
response->mURL = mURL;
|
||||
response->mFinalURL = mFinalURL;
|
||||
response->mChannelInfo = mChannelInfo;
|
||||
response->mWrappedResponse = this;
|
||||
return response.forget();
|
||||
}
|
||||
OpaqueResponse();
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
BasicResponse();
|
||||
@@ -90,18 +84,6 @@ public:
|
||||
mURL.Assign(aURL);
|
||||
}
|
||||
|
||||
bool
|
||||
FinalURL() const
|
||||
{
|
||||
return mFinalURL;
|
||||
}
|
||||
|
||||
void
|
||||
SetFinalURL(bool aFinalURL)
|
||||
{
|
||||
mFinalURL = aFinalURL;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
GetStatus() const
|
||||
{
|
||||
@@ -181,9 +163,18 @@ public:
|
||||
return mChannelInfo;
|
||||
}
|
||||
|
||||
const UniquePtr<mozilla::ipc::PrincipalInfo>&
|
||||
GetPrincipalInfo() const
|
||||
{
|
||||
return mPrincipalInfo;
|
||||
}
|
||||
|
||||
// Takes ownership of the principal info.
|
||||
void
|
||||
SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo);
|
||||
|
||||
private:
|
||||
~InternalResponse()
|
||||
{ }
|
||||
~InternalResponse();
|
||||
|
||||
explicit InternalResponse(const InternalResponse& aOther) = delete;
|
||||
InternalResponse& operator=(const InternalResponse&) = delete;
|
||||
@@ -191,26 +182,17 @@ private:
|
||||
// Returns an instance of InternalResponse which is a copy of this
|
||||
// InternalResponse, except headers, body and wrapped response (if any) which
|
||||
// are left uninitialized. Used for cloning and filtering.
|
||||
already_AddRefed<InternalResponse> CreateIncompleteCopy()
|
||||
{
|
||||
nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
|
||||
copy->mType = mType;
|
||||
copy->mTerminationReason = mTerminationReason;
|
||||
copy->mURL = mURL;
|
||||
copy->mFinalURL = mFinalURL;
|
||||
copy->mChannelInfo = mChannelInfo;
|
||||
return copy.forget();
|
||||
}
|
||||
already_AddRefed<InternalResponse> CreateIncompleteCopy();
|
||||
|
||||
ResponseType mType;
|
||||
nsCString mTerminationReason;
|
||||
nsCString mURL;
|
||||
bool mFinalURL;
|
||||
const uint16_t mStatus;
|
||||
const nsCString mStatusText;
|
||||
nsRefPtr<InternalHeaders> mHeaders;
|
||||
nsCOMPtr<nsIInputStream> mBody;
|
||||
ChannelInfo mChannelInfo;
|
||||
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
|
||||
// For filtered responses.
|
||||
// Cache, and SW interception should always serialize/access the underlying
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#include "InternalResponse.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Headers;
|
||||
@@ -90,6 +94,12 @@ public:
|
||||
return mInternalResponse->GetChannelInfo();
|
||||
}
|
||||
|
||||
const UniquePtr<mozilla::ipc::PrincipalInfo>&
|
||||
GetPrincipalInfo() const
|
||||
{
|
||||
return mInternalResponse->GetPrincipalInfo();
|
||||
}
|
||||
|
||||
Headers* Headers_();
|
||||
|
||||
void
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
function testScript(script) {
|
||||
function setupPrefs() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true]]
|
||||
}, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function workerTest() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var worker = new Worker("worker_wrapper.js");
|
||||
worker.onmessage = function(event) {
|
||||
if (event.data.context != "Worker") {
|
||||
return;
|
||||
}
|
||||
if (event.data.type == 'finish') {
|
||||
resolve();
|
||||
} else if (event.data.type == 'status') {
|
||||
ok(event.data.status, "Worker fetch test: " + event.data.msg);
|
||||
ok(event.data.status, event.data.context + ": " + event.data.msg);
|
||||
}
|
||||
}
|
||||
worker.onerror = function(event) {
|
||||
@@ -17,6 +30,60 @@ function testScript(script) {
|
||||
});
|
||||
}
|
||||
|
||||
function serviceWorkerTest() {
|
||||
var isB2G = !navigator.userAgent.includes("Android") &&
|
||||
/Mobile|Tablet/.test(navigator.userAgent);
|
||||
if (isB2G) {
|
||||
// TODO B2G doesn't support running service workers for now due to bug 1137683.
|
||||
dump("Skipping running the test in SW until bug 1137683 gets fixed.\n");
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise(function(resolve, reject) {
|
||||
function setupSW(registration) {
|
||||
var worker = registration.waiting ||
|
||||
registration.active;
|
||||
|
||||
window.addEventListener("message",function onMessage(event) {
|
||||
if (event.data.context != "ServiceWorker") {
|
||||
return;
|
||||
}
|
||||
if (event.data.type == 'finish') {
|
||||
window.removeEventListener("message", onMessage);
|
||||
registration.unregister()
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
} else if (event.data.type == 'status') {
|
||||
ok(event.data.status, event.data.context + ": " + event.data.msg);
|
||||
}
|
||||
}, false);
|
||||
|
||||
worker.onerror = reject;
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "message_receiver.html";
|
||||
iframe.onload = function() {
|
||||
worker.postMessage({ script: script });
|
||||
};
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
navigator.serviceWorker.register("worker_wrapper.js", {scope: "."})
|
||||
.then(function(registration) {
|
||||
if (registration.installing) {
|
||||
var done = false;
|
||||
registration.installing.onstatechange = function() {
|
||||
if (!done) {
|
||||
done = true;
|
||||
setupSW(registration);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
setupSW(registration);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function windowTest() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var scriptEl = document.createElement("script");
|
||||
@@ -29,13 +96,19 @@ function testScript(script) {
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// We have to run the window and worker tests sequentially since some tests
|
||||
// set and compare cookies and running in parallel can lead to conflicting
|
||||
// values.
|
||||
windowTest()
|
||||
// We have to run the window, worker and service worker tests sequentially
|
||||
// since some tests set and compare cookies and running in parallel can lead
|
||||
// to conflicting values.
|
||||
setupPrefs()
|
||||
.then(function() {
|
||||
return windowTest();
|
||||
})
|
||||
.then(function() {
|
||||
return workerTest();
|
||||
})
|
||||
.then(function() {
|
||||
return serviceWorkerTest();
|
||||
})
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed in " + script);
|
||||
info(e);
|
||||
@@ -43,7 +116,11 @@ function testScript(script) {
|
||||
return Promise.resolve();
|
||||
})
|
||||
.then(function() {
|
||||
SimpleTest.finish();
|
||||
if (parent && parent.finishTest) {
|
||||
parent.finishTest();
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.onmessage = function(e) {
|
||||
window.parent.postMessage(e.data, "*");
|
||||
};
|
||||
</script>
|
||||
@@ -11,13 +11,32 @@ support-files =
|
||||
test_response.js
|
||||
utils.js
|
||||
worker_wrapper.js
|
||||
message_receiver.html
|
||||
reroute.html
|
||||
reroute.js
|
||||
reroute.js^headers^
|
||||
sw_reroute.js
|
||||
|
||||
[test_headers.html]
|
||||
[test_headers_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
[test_headers_mainthread.html]
|
||||
[test_fetch_app_protocol.html]
|
||||
[test_fetch_basic.html]
|
||||
[test_fetch_basic_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
[test_fetch_basic_http.html]
|
||||
[test_fetch_basic_http_sw_reroute.html]
|
||||
skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g
|
||||
[test_fetch_cors.html]
|
||||
[test_fetch_cors_sw_reroute.html]
|
||||
skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g
|
||||
[test_formdataparsing.html]
|
||||
[test_formdataparsing_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
[test_request.html]
|
||||
[test_request_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
[test_response.html]
|
||||
[test_response_sw_reroute.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1137683
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
["SimpleTest", "ok", "info", "is", "$"]
|
||||
.forEach((v) => window[v] = window.parent[v]);
|
||||
</script>
|
||||
<script type="text/javascript" src="utils.js"> </script>
|
||||
<script type="text/javascript" src="fetch_test_framework.js"> </script>
|
||||
<script>
|
||||
testScript(location.search.substring(1) + ".js");
|
||||
</script>
|
||||
@@ -0,0 +1,3 @@
|
||||
onfetch = function(e) {
|
||||
e.respondWith(fetch(e.request));
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
Service-Worker-Allowed: /
|
||||
@@ -0,0 +1,29 @@
|
||||
var gRegistration;
|
||||
|
||||
function testScript(script) {
|
||||
function setupSW(registration) {
|
||||
gRegistration = registration;
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = "reroute.html?" + script.replace(".js", "");
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true]]
|
||||
}, function() {
|
||||
navigator.serviceWorker.ready.then(setupSW);
|
||||
navigator.serviceWorker.register("reroute.js", {scope: "/"});
|
||||
});
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
gRegistration.unregister().then(SimpleTest.finish, function(e) {
|
||||
dump("unregistration failed: " + e + "\n");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1039846 - Test fetch() http fetching in worker</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 type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_fetch_basic_http.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1039846 - Test fetch() function in worker</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 type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_fetch_basic.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1039846 - Test fetch() CORS mode</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 type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_fetch_cors.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1109751 - Test FormData parsing</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 type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_formdataparsing.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Fetch Headers - Basic</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_headers_common.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,7 +5,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug XXXXXX - Test Request object in worker</title>
|
||||
<title>Test Request object in worker</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Request object in worker</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 type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_request.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1039846 - Test Response object in worker</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 type="text/javascript" src="sw_reroute.js"> </script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
testScript("test_response.js");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,31 +1,58 @@
|
||||
importScripts("utils.js");
|
||||
var client;
|
||||
var context;
|
||||
|
||||
function ok(a, msg) {
|
||||
postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
|
||||
client.postMessage({type: 'status', status: !!a,
|
||||
msg: a + ": " + msg, context: context});
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
|
||||
client.postMessage({type: 'status', status: a === b,
|
||||
msg: a + " === " + b + ": " + msg, context: context});
|
||||
}
|
||||
|
||||
addEventListener('message', function workerWrapperOnMessage(e) {
|
||||
removeEventListener('message', workerWrapperOnMessage);
|
||||
var data = e.data;
|
||||
|
||||
var done = function() {
|
||||
postMessage({ type: 'finish' });
|
||||
function loadTest() {
|
||||
var done = function() {
|
||||
client.postMessage({ type: 'finish', context: context });
|
||||
}
|
||||
|
||||
try {
|
||||
importScripts(data.script);
|
||||
// runTest() is provided by the test.
|
||||
runTest().then(done, done);
|
||||
} catch(e) {
|
||||
client.postMessage({
|
||||
type: 'status',
|
||||
status: false,
|
||||
msg: 'worker failed to import ' + data.script + "; error: " + e.message,
|
||||
context: context
|
||||
});
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
importScripts(data.script);
|
||||
// runTest() is provided by the test.
|
||||
runTest().then(done, done);
|
||||
} catch(e) {
|
||||
postMessage({
|
||||
type: 'status',
|
||||
status: false,
|
||||
msg: 'worker failed to import ' + data.script + "; error: " + e.message
|
||||
if ("ServiceWorker" in self) {
|
||||
self.clients.matchAll().then(function(clients) {
|
||||
for (var i = 0; i < clients.length; ++i) {
|
||||
if (clients[i].url.indexOf("message_receiver.html") > -1) {
|
||||
client = clients[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!client) {
|
||||
dump("We couldn't find the message_receiver window, the test will fail\n");
|
||||
}
|
||||
context = "ServiceWorker";
|
||||
loadTest();
|
||||
});
|
||||
done();
|
||||
} else {
|
||||
client = self;
|
||||
context = "Worker";
|
||||
loadTest();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "mozilla/LoadContext.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/dom/CacheBinding.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/Cache.h"
|
||||
#include "mozilla/dom/cache/CacheStorage.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
@@ -422,6 +423,7 @@ private:
|
||||
nsCOMPtr<nsIInputStreamPump> mPump;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
ChannelInfo mChannelInfo;
|
||||
UniquePtr<PrincipalInfo> mPrincipalInfo;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CacheScriptLoader, nsIStreamLoaderObserver)
|
||||
@@ -592,6 +594,27 @@ private:
|
||||
// saved in the cache.
|
||||
ir->InitChannelInfo(channel);
|
||||
|
||||
// Save the principal of the channel since its URI encodes the script URI
|
||||
// rather than the ServiceWorkerRegistrationInfo URI.
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
NS_ASSERTION(ssm, "Should never be null!");
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
nsresult rv = ssm->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
channel->Cancel(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
UniquePtr<PrincipalInfo> principalInfo(new PrincipalInfo());
|
||||
rv = PrincipalToPrincipalInfo(channelPrincipal, principalInfo.get());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
channel->Cancel(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
ir->SetPrincipalInfo(Move(principalInfo));
|
||||
|
||||
nsRefPtr<Response> response = new Response(mCacheCreator->Global(), ir);
|
||||
|
||||
RequestOrUSVString request;
|
||||
@@ -1046,7 +1069,8 @@ private:
|
||||
void
|
||||
DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString,
|
||||
uint32_t aStringLen,
|
||||
const ChannelInfo& aChannelInfo)
|
||||
const ChannelInfo& aChannelInfo,
|
||||
UniquePtr<PrincipalInfo> aPrincipalInfo)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aIndex < mLoadInfos.Length());
|
||||
@@ -1074,10 +1098,15 @@ private:
|
||||
MOZ_ASSERT(principal);
|
||||
nsILoadGroup* loadGroup = mWorkerPrivate->GetLoadGroup();
|
||||
MOZ_ASSERT(loadGroup);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> responsePrincipal =
|
||||
PrincipalInfoToPrincipal(*aPrincipalInfo);
|
||||
DebugOnly<bool> equal = false;
|
||||
MOZ_ASSERT(responsePrincipal && NS_SUCCEEDED(responsePrincipal->Equals(principal, &equal)));
|
||||
MOZ_ASSERT(equal);
|
||||
|
||||
mWorkerPrivate->InitChannelInfo(aChannelInfo);
|
||||
// Needed to initialize the principal info. This is fine because
|
||||
// the cache principal cannot change, unlike the channel principal.
|
||||
mWorkerPrivate->SetPrincipal(principal, loadGroup);
|
||||
mWorkerPrivate->SetPrincipal(responsePrincipal, loadGroup);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@@ -1429,10 +1458,16 @@ CacheScriptLoader::ResolvedCallback(JSContext* aCx,
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
response->GetBody(getter_AddRefs(inputStream));
|
||||
mChannelInfo = response->GetChannelInfo();
|
||||
const UniquePtr<mozilla::ipc::PrincipalInfo>& pInfo =
|
||||
response->GetPrincipalInfo();
|
||||
if (pInfo) {
|
||||
mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*pInfo);
|
||||
}
|
||||
|
||||
if (!inputStream) {
|
||||
mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
|
||||
mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo);
|
||||
mRunnable->DataReceivedFromCache(mIndex, (uint8_t*)"", 0, mChannelInfo,
|
||||
Move(mPrincipalInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1488,7 +1523,9 @@ CacheScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aCont
|
||||
|
||||
mLoadInfo.mCacheStatus = ScriptLoadInfo::Cached;
|
||||
|
||||
mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo);
|
||||
MOZ_ASSERT(mPrincipalInfo);
|
||||
mRunnable->DataReceivedFromCache(mIndex, aString, aStringLen, mChannelInfo,
|
||||
Move(mPrincipalInfo));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -873,6 +873,7 @@ class ServiceWorkerRegisterJob final : public ServiceWorkerJob,
|
||||
nsRefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsRefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
~ServiceWorkerRegisterJob()
|
||||
{ }
|
||||
@@ -893,15 +894,19 @@ public:
|
||||
const nsCString& aScope,
|
||||
const nsCString& aScriptSpec,
|
||||
ServiceWorkerUpdateFinishCallback* aCallback,
|
||||
nsIPrincipal* aPrincipal)
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup)
|
||||
: ServiceWorkerJob(aQueue)
|
||||
, mScope(aScope)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mCallback(aCallback)
|
||||
, mPrincipal(aPrincipal)
|
||||
, mLoadGroup(aLoadGroup)
|
||||
, mJobType(REGISTER_JOB)
|
||||
, mCanceled(false)
|
||||
{ }
|
||||
{
|
||||
MOZ_ASSERT(mLoadGroup);
|
||||
}
|
||||
|
||||
// [[Update]]
|
||||
ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
|
||||
@@ -1223,7 +1228,7 @@ private:
|
||||
nsresult rv =
|
||||
serviceWorkerScriptCache::Compare(mRegistration->mPrincipal, cacheName,
|
||||
NS_ConvertUTF8toUTF16(mRegistration->mScriptSpec),
|
||||
this);
|
||||
this, mLoadGroup);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return Fail(rv);
|
||||
}
|
||||
@@ -1495,8 +1500,20 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
|
||||
nsRefPtr<ServiceWorkerResolveWindowPromiseOnUpdateCallback> cb =
|
||||
new ServiceWorkerResolveWindowPromiseOnUpdateCallback(window, promise);
|
||||
|
||||
nsCOMPtr<nsILoadGroup> docLoadGroup = doc->GetDocumentLoadGroup();
|
||||
nsRefPtr<WorkerLoadInfo::InterfaceRequestor> ir =
|
||||
new WorkerLoadInfo::InterfaceRequestor(documentPrincipal, docLoadGroup);
|
||||
ir->MaybeAddTabChild(docLoadGroup);
|
||||
|
||||
// Create a load group that is separate from, yet related to, the document's load group.
|
||||
// This allows checks for interfaces like nsILoadContext to yield the values used by the
|
||||
// the document, yet will not cancel the update job if the document's load group is cancelled.
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
|
||||
rv = loadGroup->SetNotificationCallbacks(ir);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
nsRefPtr<ServiceWorkerRegisterJob> job =
|
||||
new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb, documentPrincipal);
|
||||
new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb, documentPrincipal, loadGroup);
|
||||
queue->Append(job);
|
||||
|
||||
AssertIsOnMainThread();
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "mozilla/dom/CacheBinding.h"
|
||||
#include "mozilla/dom/cache/CacheStorage.h"
|
||||
#include "mozilla/dom/cache/Cache.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
|
||||
#include "nsIPrincipal.h"
|
||||
@@ -72,7 +74,7 @@ public:
|
||||
}
|
||||
|
||||
nsresult
|
||||
Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL)
|
||||
Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL, nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
AssertIsOnMainThread();
|
||||
@@ -83,10 +85,17 @@ public:
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), aPrincipal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = NS_NewChannel(getter_AddRefs(mChannel),
|
||||
uri, aPrincipal,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_SCRIPT); // FIXME(nsm): TYPE_SERVICEWORKER
|
||||
nsIContentPolicy::TYPE_SCRIPT, // FIXME(nsm): TYPE_SERVICEWORKER
|
||||
loadGroup);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@@ -275,7 +284,7 @@ public:
|
||||
|
||||
nsresult
|
||||
Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL,
|
||||
const nsAString& aCacheName)
|
||||
const nsAString& aCacheName, nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
@@ -292,7 +301,7 @@ public:
|
||||
}
|
||||
|
||||
mCN = new CompareNetwork(this);
|
||||
nsresult rv = mCN->Initialize(aPrincipal, aURL);
|
||||
nsresult rv = mCN->Initialize(aPrincipal, aURL, aLoadGroup);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@@ -445,6 +454,28 @@ public:
|
||||
mChannelInfo.InitFromChannel(aChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SetPrincipalInfo(nsIChannel* aChannel)
|
||||
{
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
NS_ASSERTION(ssm, "Should never be null!");
|
||||
|
||||
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
||||
nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo(new mozilla::ipc::PrincipalInfo());
|
||||
rv = PrincipalToPrincipalInfo(channelPrincipal, principalInfo.get());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mPrincipalInfo = Move(principalInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~CompareManager()
|
||||
{
|
||||
@@ -540,6 +571,9 @@ private:
|
||||
ir->SetBody(body);
|
||||
|
||||
ir->InitChannelInfo(mChannelInfo);
|
||||
if (mPrincipalInfo) {
|
||||
ir->SetPrincipalInfo(Move(mPrincipalInfo));
|
||||
}
|
||||
|
||||
nsRefPtr<Response> response = new Response(aCache->GetGlobalObject(), ir);
|
||||
|
||||
@@ -572,6 +606,8 @@ private:
|
||||
|
||||
ChannelInfo mChannelInfo;
|
||||
|
||||
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
|
||||
nsCString mMaxScope;
|
||||
|
||||
enum {
|
||||
@@ -600,6 +636,10 @@ CompareNetwork::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
#endif
|
||||
|
||||
mManager->InitChannelInfo(mChannel);
|
||||
nsresult rv = mManager->SetPrincipalInfo(mChannel);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -930,7 +970,8 @@ GenerateCacheName(nsAString& aName)
|
||||
|
||||
nsresult
|
||||
Compare(nsIPrincipal* aPrincipal, const nsAString& aCacheName,
|
||||
const nsAString& aURL, CompareCallback* aCallback)
|
||||
const nsAString& aURL, CompareCallback* aCallback,
|
||||
nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
@@ -939,7 +980,7 @@ Compare(nsIPrincipal* aPrincipal, const nsAString& aCacheName,
|
||||
|
||||
nsRefPtr<CompareManager> cm = new CompareManager(aCallback);
|
||||
|
||||
nsresult rv = cm->Initialize(aPrincipal, aURL, aCacheName);
|
||||
nsresult rv = cm->Initialize(aPrincipal, aURL, aCacheName, aLoadGroup);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
|
||||
nsresult
|
||||
Compare(nsIPrincipal* aPrincipal, const nsAString& aCacheName,
|
||||
const nsAString& aURL, CompareCallback* aCallback);
|
||||
const nsAString& aURL, CompareCallback* aCallback, nsILoadGroup* aLoadGroup);
|
||||
|
||||
} // namespace serviceWorkerScriptCache
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
application.zip contains foo.txt, index.html, sw.js and manifest.webapp.
|
||||
Any change to one of these three files should be added to application.zip as well.
|
||||
application.list contains a list of files that are in application.zip.
|
||||
|
||||
To update application.zip when changing one of those files, run makezip.sh.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
controlled.html
|
||||
foo.txt
|
||||
index.html
|
||||
manifest.webapp
|
||||
sw.js
|
||||
test.js
|
||||
test_doc_load_interception.js
|
||||
Binary file not shown.
@@ -3,12 +3,24 @@
|
||||
<head>
|
||||
<title>Test app for bug 1161684</title>
|
||||
<script src='test.js'></script>
|
||||
<script src='test_doc_load_interception.js'></script>
|
||||
<script type='application/javascript;version=1.7'>
|
||||
|
||||
function runTests() {
|
||||
return Promise.resolve()
|
||||
.then(navigator.serviceWorker.ready)
|
||||
.then(() => { return testFetchAppResource('swresponse'); })
|
||||
.then(() => {
|
||||
return testFetchAppResource('foo.txt',
|
||||
'swresponse', 'text/plain');
|
||||
})
|
||||
.then(() => {
|
||||
return testFetchAppResource('test_custom_content_type',
|
||||
'customContentType', 'text/html');
|
||||
})
|
||||
.then(testRedirectedResponse)
|
||||
.then(testRedirectedHttpsResponse)
|
||||
.then(testCachedRedirectedResponse)
|
||||
.then(testCachedRedirectedHttpsResponse)
|
||||
.then(done);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
function registerServiceWorker() {
|
||||
return new Promise((resolve, reject) => {
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
ready();
|
||||
resolve();
|
||||
});
|
||||
navigator.serviceWorker.register('sw.js', {scope: '.'})
|
||||
@@ -20,9 +19,10 @@ function registerServiceWorker() {
|
||||
|
||||
function runTests() {
|
||||
return Promise.resolve()
|
||||
.then(() => { return testFetchAppResource('networkresponse'); })
|
||||
.then(() => { return testFetchAppResource('foo.txt',
|
||||
'networkresponse'); })
|
||||
.then(registerServiceWorker)
|
||||
.then(done);
|
||||
.then(ready);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm application.zip
|
||||
zip application.zip `cat application.list`
|
||||
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE html>
|
||||
real index
|
||||
@@ -0,0 +1 @@
|
||||
Access-Control-Allow-Origin: *
|
||||
@@ -0,0 +1,5 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(null, 308, "Permanent Redirect");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/app-protocol/realindex.html", false);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(null, 308, "Permanent Redirect");
|
||||
response.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/app-protocol/realindex.html", false);
|
||||
}
|
||||
@@ -1,8 +1,63 @@
|
||||
const kHTTPRedirect = "http://example.com/tests/dom/workers/test/serviceworkers/app-protocol/redirect.sjs";
|
||||
const kHTTPSRedirect = "https://example.com/tests/dom/workers/test/serviceworkers/app-protocol/redirect-https.sjs";
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
self.caches.open("origin-app-cache")
|
||||
.then(c => {
|
||||
return Promise.all(
|
||||
[
|
||||
c.add(kHTTPRedirect),
|
||||
c.add(kHTTPSRedirect),
|
||||
]
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.url.indexOf('foo.txt') >= 0) {
|
||||
var body = 'swresponse';
|
||||
event.respondWith(new Response(body, {
|
||||
event.respondWith(new Response('swresponse', {
|
||||
headers: {'Content-Type': 'text/plain'}
|
||||
}));
|
||||
}
|
||||
|
||||
if (event.request.url.indexOf('test_doc_load_interception.js') >= 0 ) {
|
||||
var scriptContent = 'alert("OK: Script modified by service worker")';
|
||||
event.respondWith(new Response(scriptContent, {
|
||||
headers: {'Content-Type': 'application/javascript'}
|
||||
}));
|
||||
}
|
||||
|
||||
if (event.request.url.indexOf('test_custom_content_type') >= 0) {
|
||||
event.respondWith(new Response('customContentType', {
|
||||
headers: {'Content-Type': 'text/html'}
|
||||
}));
|
||||
}
|
||||
|
||||
if (event.request.url.indexOf('redirected.html') >= 0) {
|
||||
event.respondWith(fetch(kHTTPRedirect));
|
||||
}
|
||||
|
||||
if (event.request.url.indexOf('redirected-https.html') >= 0) {
|
||||
event.respondWith(fetch(kHTTPSRedirect));
|
||||
}
|
||||
|
||||
if (event.request.url.indexOf('redirected-cached.html') >= 0) {
|
||||
event.respondWith(
|
||||
self.caches.open("origin-app-cache")
|
||||
.then(c => {
|
||||
return c.match(kHTTPRedirect);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (event.request.url.indexOf('redirected-https-cached.html') >= 0) {
|
||||
event.respondWith(
|
||||
self.caches.open("origin-app-cache")
|
||||
.then(c => {
|
||||
return c.match(kHTTPSRedirect);
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,16 +14,59 @@ function done() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testFetchAppResource(aExpectedResponse) {
|
||||
return fetch('foo.txt').then(res => {
|
||||
function testFetchAppResource(aUrl,
|
||||
aExpectedResponse,
|
||||
aExpectedContentType) {
|
||||
return fetch(aUrl).then(res => {
|
||||
ok(true, 'fetch should resolve');
|
||||
if (res.type == 'error') {
|
||||
ok(false, 'fetch failed');
|
||||
}
|
||||
ok(res.status == 200, 'status should be 200');
|
||||
ok(res.statusText == 'OK', 'statusText should be OK');
|
||||
if (aExpectedContentType) {
|
||||
var headers = res.headers.getAll('Content-Type');
|
||||
ok(headers.length, "Headers length");
|
||||
var contentType = res.headers.get('Content-Type');
|
||||
ok(contentType == aExpectedContentType, ('content type ' +
|
||||
contentType + ' should match with ' + aExpectedContentType));
|
||||
}
|
||||
return res.text().then(body => {
|
||||
ok(body == aExpectedResponse, 'body should match');
|
||||
ok(body == aExpectedResponse, 'body ' + body +
|
||||
' should match with ' + aExpectedResponse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testRedirectedResponse() {
|
||||
return testRedirectedResponseWorker("redirected", "IFRAMELOADED");
|
||||
}
|
||||
|
||||
function testRedirectedHttpsResponse() {
|
||||
return testRedirectedResponseWorker("redirected-https", "HTTPSIFRAMELOADED");
|
||||
}
|
||||
|
||||
function testCachedRedirectedResponse() {
|
||||
return testRedirectedResponseWorker("redirected-cached", "IFRAMELOADED");
|
||||
}
|
||||
|
||||
function testCachedRedirectedHttpsResponse() {
|
||||
return testRedirectedResponseWorker("redirected-https-cached", "HTTPSIFRAMELOADED");
|
||||
}
|
||||
|
||||
function testRedirectedResponseWorker(aFrameId, aAlert) {
|
||||
// Because of the CSP policies applied to privileged apps, we cannot run
|
||||
// inline script inside realindex.html, and loading a script from the app://
|
||||
// URI is also not an option, so we let the parent iframe which has access
|
||||
// to the SpecialPowers API use those privileges to access the document.
|
||||
var iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
iframe.src = aFrameId + ".html";
|
||||
iframe.id = aFrameId;
|
||||
return new Promise(resolve => {
|
||||
iframe.addEventListener("load", event => {
|
||||
alert(aAlert);
|
||||
resolve();
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
alert('KO: Should not load this file, but the sw modified version instead');
|
||||
@@ -123,6 +123,25 @@ fetchXHR('http://example.com/tests/dom/base/test/file_CrossSiteXHR_server.sjs?st
|
||||
finish();
|
||||
});
|
||||
|
||||
// Test that when the page fetches a url the controlling SW forces a redirect to
|
||||
// another location. This other location fetch should also be intercepted by
|
||||
// the SW.
|
||||
fetchXHR('something.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "something else response body", "load should have something else");
|
||||
finish();
|
||||
});
|
||||
|
||||
// Test fetch will internally get it's SkipServiceWorker flag set. The request is
|
||||
// made from the SW through fetch(). fetch() fetches a server-side JavaScript
|
||||
// file that force a redirect. The redirect location fetch does not go through
|
||||
// the SW.
|
||||
fetchXHR('redirect_serviceworker.sjs', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "// empty worker, always succeed!\n", "load should have redirection content");
|
||||
finish();
|
||||
});
|
||||
|
||||
expectAsyncResult();
|
||||
fetch('http://example.com/tests/dom/base/test/file_CrossSiteXHR_server.sjs?status=200&allowOrigin=*')
|
||||
.then(function(res) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(null, 308, "Permanent Redirect");
|
||||
response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/https/realindex.html", false);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
var prefix = "/tests/dom/workers/test/serviceworkers/fetch/origin/https/";
|
||||
|
||||
self.addEventListener("install", function(event) {
|
||||
event.waitUntil(
|
||||
self.caches.open("origin-cache")
|
||||
.then(c => {
|
||||
return c.add(prefix + 'index-https.sjs');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", function(event) {
|
||||
if (event.request.url.indexOf("index-cached-https.sjs") >= 0) {
|
||||
event.respondWith(
|
||||
self.caches.open("origin-cache")
|
||||
.then(c => {
|
||||
return c.match(prefix + 'index-https.sjs');
|
||||
})
|
||||
);
|
||||
} else {
|
||||
event.respondWith(fetch(event.request));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
window.opener.postMessage({status: "domain", data: document.domain}, "*");
|
||||
window.opener.postMessage({status: "origin", data: location.origin}, "*");
|
||||
window.opener.postMessage({status: "done"}, "*");
|
||||
</script>
|
||||
@@ -0,0 +1 @@
|
||||
Access-Control-Allow-Origin: https://example.com
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
function ok(v, msg) {
|
||||
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
|
||||
}
|
||||
|
||||
function done(reg) {
|
||||
ok(reg.active, "The active worker should be available.");
|
||||
window.parent.postMessage({status: "registrationdone"}, "*");
|
||||
}
|
||||
|
||||
navigator.serviceWorker.ready.then(done);
|
||||
navigator.serviceWorker.register("origin_test.js", {scope: "."});
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.getRegistration(".").then(function(registration) {
|
||||
registration.unregister().then(function(success) {
|
||||
if (success) {
|
||||
window.parent.postMessage({status: "unregistrationdone"}, "*");
|
||||
}
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,4 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(null, 308, "Permanent Redirect");
|
||||
response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/realindex.html", false);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(null, 308, "Permanent Redirect");
|
||||
response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/realindex.html", false);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
var prefix = "/tests/dom/workers/test/serviceworkers/fetch/origin/";
|
||||
|
||||
self.addEventListener("install", function(event) {
|
||||
event.waitUntil(
|
||||
self.caches.open("origin-cache")
|
||||
.then(c => {
|
||||
return Promise.all(
|
||||
[
|
||||
c.add(prefix + 'index.sjs'),
|
||||
c.add(prefix + 'index-to-https.sjs'),
|
||||
]
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", function(event) {
|
||||
if (event.request.url.indexOf("index-cached.sjs") >= 0) {
|
||||
event.respondWith(
|
||||
self.caches.open("origin-cache")
|
||||
.then(c => {
|
||||
return c.match(prefix + 'index.sjs');
|
||||
})
|
||||
);
|
||||
} else if (event.request.url.indexOf("index-to-https-cached.sjs") >= 0) {
|
||||
event.respondWith(
|
||||
self.caches.open("origin-cache")
|
||||
.then(c => {
|
||||
return c.match(prefix + 'index-to-https.sjs');
|
||||
})
|
||||
);
|
||||
} else {
|
||||
event.respondWith(fetch(event.request));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
window.opener.postMessage({status: "domain", data: document.domain}, "*");
|
||||
window.opener.postMessage({status: "origin", data: location.origin}, "*");
|
||||
window.opener.postMessage({status: "done"}, "*");
|
||||
</script>
|
||||
@@ -0,0 +1 @@
|
||||
Access-Control-Allow-Origin: http://mochi.test:8888
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
function ok(v, msg) {
|
||||
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
|
||||
}
|
||||
|
||||
function done(reg) {
|
||||
ok(reg.active, "The active worker should be available.");
|
||||
window.parent.postMessage({status: "registrationdone"}, "*");
|
||||
}
|
||||
|
||||
navigator.serviceWorker.ready.then(done);
|
||||
navigator.serviceWorker.register("origin_test.js", {scope: "."});
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.getRegistration(".").then(function(registration) {
|
||||
registration.unregister().then(function(success) {
|
||||
if (success) {
|
||||
window.parent.postMessage({status: "unregistrationdone"}, "*");
|
||||
}
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.onmessage = window.onmessage = e => {
|
||||
window.parent.postMessage(e.data, "*");
|
||||
};
|
||||
</script>
|
||||
<iframe src="redirector.html"></iframe>
|
||||
@@ -0,0 +1,4 @@
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(null, 308, "Permanent Redirect");
|
||||
response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/fetch/requesturl/secret.html", false);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<!DOCTYPE html>
|
||||
<meta http-equiv="refresh" content="3;URL=/tests/dom/workers/test/serviceworkers/fetch/requesturl/redirect.sjs">
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
function ok(v, msg) {
|
||||
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
|
||||
}
|
||||
|
||||
function done(reg) {
|
||||
ok(reg.active, "The active worker should be available.");
|
||||
window.parent.postMessage({status: "registrationdone"}, "*");
|
||||
}
|
||||
|
||||
navigator.serviceWorker.ready.then(done);
|
||||
navigator.serviceWorker.register("requesturl_test.js", {scope: "."});
|
||||
</script>
|
||||
@@ -0,0 +1,17 @@
|
||||
addEventListener("fetch", event => {
|
||||
var url = event.request.url;
|
||||
var badURL = url.indexOf("secret.html") > -1;
|
||||
event.respondWith(
|
||||
new Promise(resolve => {
|
||||
clients.matchAll().then(clients => {
|
||||
for (var client of clients) {
|
||||
if (client.url.indexOf("index.html") > -1) {
|
||||
client.postMessage({status: "ok", result: !badURL, message: "Should not find a bad URL (" + url + ")"});
|
||||
break;
|
||||
}
|
||||
}
|
||||
resolve(fetch(event.request));
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
secret stuff
|
||||
<script>
|
||||
window.parent.postMessage({status: "done"}, "*");
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.getRegistration(".").then(function(registration) {
|
||||
registration.unregister().then(function(success) {
|
||||
if (success) {
|
||||
window.parent.postMessage({status: "unregistrationdone"}, "*");
|
||||
}
|
||||
}, function(e) {
|
||||
dump("Unregistering the SW failed with " + e + "\n");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -179,4 +179,20 @@ onfetch = function(ev) {
|
||||
return new Response(body + body);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes('something.txt')) {
|
||||
ev.respondWith(Response.redirect('fetch/somethingelse.txt'));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes('somethingelse.txt')) {
|
||||
ev.respondWith(new Response('something else response body', {}));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes('redirect_serviceworker.sjs')) {
|
||||
// The redirect_serviceworker.sjs server-side JavaScript file redirects to
|
||||
// 'http://mochi.test:8888/tests/dom/workers/test/serviceworkers/worker.js'
|
||||
// The redirected fetch should not go through the SW since the original
|
||||
// fetch was initiated from a SW.
|
||||
ev.respondWith(fetch('redirect_serviceworker.sjs'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,6 +46,26 @@ support-files =
|
||||
fetch/https/clonedresponse/register.html
|
||||
fetch/https/clonedresponse/unregister.html
|
||||
fetch/https/clonedresponse/https_test.js
|
||||
fetch/origin/index.sjs
|
||||
fetch/origin/index-to-https.sjs
|
||||
fetch/origin/realindex.html
|
||||
fetch/origin/realindex.html^headers^
|
||||
fetch/origin/register.html
|
||||
fetch/origin/unregister.html
|
||||
fetch/origin/origin_test.js
|
||||
fetch/origin/https/index-https.sjs
|
||||
fetch/origin/https/realindex.html
|
||||
fetch/origin/https/realindex.html^headers^
|
||||
fetch/origin/https/register.html
|
||||
fetch/origin/https/unregister.html
|
||||
fetch/origin/https/origin_test.js
|
||||
fetch/requesturl/index.html
|
||||
fetch/requesturl/redirect.sjs
|
||||
fetch/requesturl/redirector.html
|
||||
fetch/requesturl/register.html
|
||||
fetch/requesturl/requesturl_test.js
|
||||
fetch/requesturl/secret.html
|
||||
fetch/requesturl/unregister.html
|
||||
fetch/sandbox/index.html
|
||||
fetch/sandbox/intercepted_index.html
|
||||
fetch/sandbox/register.html
|
||||
@@ -150,3 +170,10 @@ support-files =
|
||||
[test_force_refresh.html]
|
||||
[test_skip_waiting.html]
|
||||
[test_strict_mode_error.html]
|
||||
[test_cross_origin_url_after_redirect.html]
|
||||
[test_origin_after_redirect.html]
|
||||
[test_origin_after_redirect_cached.html]
|
||||
[test_origin_after_redirect_to_https.html]
|
||||
[test_origin_after_redirect_to_https_cached.html]
|
||||
[test_https_origin_after_redirect.html]
|
||||
[test_https_origin_after_redirect_cached.html]
|
||||
|
||||
@@ -22,14 +22,14 @@ const appManifestURL =
|
||||
let gApp;
|
||||
|
||||
function setup() {
|
||||
info('Setting up');
|
||||
return new Promise((resolve, reject) => {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['dom.mozBrowserFramesEnabled', true],
|
||||
['dom.serviceWorkers.exemptFromPerDomainMax', true],
|
||||
['dom.serviceWorkers.enabled', true],
|
||||
['dom.serviceWorkers.testing.enabled', true]
|
||||
['dom.serviceWorkers.testing.enabled', true],
|
||||
['dom.caches.enabled', true],
|
||||
]}, () => {
|
||||
SpecialPowers.pushPermissions([
|
||||
{ 'type': 'webapps-manage', 'allow': 1, 'context': document },
|
||||
@@ -75,9 +75,15 @@ function launchApp() {
|
||||
iframe.setAttribute('mozapp', gApp.manifestURL);
|
||||
iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
|
||||
let message = e.detail.message;
|
||||
if (/READY/.exec(message)) {
|
||||
if (/OK/.exec(message)) {
|
||||
ok(true, "Message from app: " + message);
|
||||
} else if (/KO/.exec(message)) {
|
||||
ok(false, "Message from app: " + message);
|
||||
} else if (/READY/.exec(message)) {
|
||||
ok(true, "Message from app: " + message);
|
||||
resolve();
|
||||
} else {
|
||||
ok(false, "Unexpected message received: " + message);
|
||||
}
|
||||
}, false);
|
||||
let domParent = document.getElementById('container');
|
||||
@@ -88,31 +94,42 @@ function launchApp() {
|
||||
}
|
||||
|
||||
function loadControlled() {
|
||||
info("reloading");
|
||||
return new Promise((resolve, reject) => {
|
||||
let iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
iframe.setAttribute('mozapp', gApp.manifestURL);
|
||||
iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
|
||||
let message = e.detail.message;
|
||||
info(message);
|
||||
if (/OK/.exec(message)) {
|
||||
ok(true, "Message from app: " + message);
|
||||
} else if (/KO/.exec(message)) {
|
||||
ok(false, "Message from app: " + message);
|
||||
} else if (/HTTPSIFRAMELOADED/.exec(message)) {
|
||||
let doc = SpecialPowers.wrap(iframe).contentDocument;
|
||||
let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected-https").contentDocument);
|
||||
let innerLocation = innerDoc.defaultView.location;
|
||||
is(innerDoc.domain, "example.org", "Correct domain expected (https)");
|
||||
is(innerLocation.origin, "https://example.org", "Correct origin expected (https)");
|
||||
} else if (/IFRAMELOADED/.exec(message)) {
|
||||
let doc = SpecialPowers.wrap(iframe).contentDocument;
|
||||
let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected").contentDocument);
|
||||
let innerLocation = innerDoc.defaultView.location;
|
||||
is(innerDoc.domain, "example.org", "Correct domain expected");
|
||||
is(innerLocation.origin, "http://example.org", "Correct origin expected");
|
||||
} else if (/DONE/.exec(message)) {
|
||||
ok(true, "Messaging from app complete");
|
||||
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
|
||||
let domParent = document.getElementById('container');
|
||||
domParent.removeChild(iframe);
|
||||
resolve();
|
||||
} else {
|
||||
ok(false, "Unexpected message received: " + message);
|
||||
}
|
||||
}, false);
|
||||
let domParent = document.getElementById('container');
|
||||
domParent.appendChild(iframe);
|
||||
SpecialPowers.wrap(iframe.contentWindow).location =
|
||||
gApp.origin + '/controlled.html';
|
||||
info("reloaded");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test access to a cross origin Request.url property from a service worker for a redirected intercepted iframe</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/requesturl/register.html";
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/requesturl/index.html";
|
||||
} else if (e.data.status == "done") {
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/requesturl/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,56 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the origin of a redirected response from a service worker</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/register.html";
|
||||
var win;
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
win = window.open("https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/index-https.sjs", "mywindow", "width=100,height=100");
|
||||
} else if (e.data.status == "domain") {
|
||||
is(e.data.data, "example.org", "Correct domain expected");
|
||||
} else if (e.data.status == "origin") {
|
||||
is(e.data.data, "https://example.org", "Correct origin expected");
|
||||
} else if (e.data.status == "done") {
|
||||
win.close();
|
||||
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,56 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the origin of a redirected response from a service worker</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/register.html";
|
||||
var win;
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
win = window.open("https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/index-cached-https.sjs", "mywindow", "width=100,height=100");
|
||||
} else if (e.data.status == "domain") {
|
||||
is(e.data.data, "example.org", "Correct domain expected");
|
||||
} else if (e.data.status == "origin") {
|
||||
is(e.data.data, "https://example.org", "Correct origin expected");
|
||||
} else if (e.data.status == "done") {
|
||||
win.close();
|
||||
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the origin of a redirected response from a service worker</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
|
||||
var win;
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index.sjs", "mywindow", "width=100,height=100");
|
||||
} else if (e.data.status == "domain") {
|
||||
is(e.data.data, "example.org", "Correct domain expected");
|
||||
} else if (e.data.status == "origin") {
|
||||
is(e.data.data, "http://example.org", "Correct origin expected");
|
||||
} else if (e.data.status == "done") {
|
||||
win.close();
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the origin of a redirected response from a service worker</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
|
||||
var win;
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-cached.sjs", "mywindow", "width=100,height=100");
|
||||
} else if (e.data.status == "domain") {
|
||||
is(e.data.data, "example.org", "Correct domain expected");
|
||||
} else if (e.data.status == "origin") {
|
||||
is(e.data.data, "http://example.org", "Correct origin expected");
|
||||
} else if (e.data.status == "done") {
|
||||
win.close();
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the origin of a redirected response from a service worker</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
|
||||
var win;
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-to-https.sjs", "mywindow", "width=100,height=100");
|
||||
} else if (e.data.status == "domain") {
|
||||
is(e.data.data, "example.org", "Correct domain expected");
|
||||
} else if (e.data.status == "origin") {
|
||||
is(e.data.data, "https://example.org", "Correct origin expected");
|
||||
} else if (e.data.status == "done") {
|
||||
win.close();
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the origin of a redirected response from a service worker</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">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
|
||||
var win;
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-to-https-cached.sjs", "mywindow", "width=100,height=100");
|
||||
} else if (e.data.status == "domain") {
|
||||
is(e.data.data, "example.org", "Correct domain expected");
|
||||
} else if (e.data.status == "origin") {
|
||||
is(e.data.data, "https://example.org", "Correct origin expected");
|
||||
} else if (e.data.status == "done") {
|
||||
win.close();
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.caches.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
+4
-1
@@ -9,7 +9,9 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "js/TracingAPI.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/TraceKind.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
/* These values are private to the JS engine. */
|
||||
@@ -165,6 +167,7 @@ class JS_FRIEND_API(GCCellPtr)
|
||||
explicit GCCellPtr(JSFunction* fun) : ptr(checkedCast(fun, JS::TraceKind::Object)) { }
|
||||
explicit GCCellPtr(JSString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { }
|
||||
explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { }
|
||||
explicit GCCellPtr(JS::Symbol* sym) : ptr(checkedCast(sym, JS::TraceKind::Symbol)) { }
|
||||
explicit GCCellPtr(JSScript* script) : ptr(checkedCast(script, JS::TraceKind::Script)) { }
|
||||
explicit GCCellPtr(const Value& v);
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef js_TraceKind_h
|
||||
#define js_TraceKind_h
|
||||
|
||||
namespace JS {
|
||||
|
||||
// When tracing a thing, the GC needs to know about the layout of the object it
|
||||
// is looking at. There are a fixed number of different layouts that the GC
|
||||
// knows about. The "trace kind" is a static map which tells which layout a GC
|
||||
// thing has.
|
||||
//
|
||||
// Although this map is public, the details are completely hidden. Not all of
|
||||
// the matching C++ types are exposed, and those that are, are opaque.
|
||||
//
|
||||
// See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
|
||||
enum class TraceKind
|
||||
{
|
||||
// These trace kinds have a publicly exposed, although opaque, C++ type.
|
||||
// Note: The order here is determined by our Value packing. Other users
|
||||
// should sort alphabetically, for consistency.
|
||||
Object = 0x00,
|
||||
String = 0x01,
|
||||
Symbol = 0x02,
|
||||
Script = 0x03,
|
||||
|
||||
// Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
|
||||
Shape = 0x04,
|
||||
|
||||
// ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
|
||||
ObjectGroup = 0x05,
|
||||
|
||||
// The kind associated with a nullptr.
|
||||
Null = 0x06,
|
||||
|
||||
// The following kinds do not have an exposed C++ idiom.
|
||||
BaseShape = 0x0F,
|
||||
JitCode = 0x1F,
|
||||
LazyScript = 0x2F
|
||||
};
|
||||
const static uintptr_t OutOfLineTraceKindMask = 0x07;
|
||||
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
|
||||
static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
|
||||
static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif // js_TraceKind_h
|
||||
+53
-57
@@ -8,9 +8,10 @@
|
||||
#define js_TracingAPI_h
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/TraceKind.h"
|
||||
|
||||
class JS_PUBLIC_API(JSTracer);
|
||||
|
||||
@@ -19,66 +20,20 @@ class JS_PUBLIC_API(CallbackTracer);
|
||||
template <typename T> class Heap;
|
||||
template <typename T> class TenuredHeap;
|
||||
|
||||
// When tracing a thing, the GC needs to know about the layout of the object it
|
||||
// is looking at. There are a fixed number of different layouts that the GC
|
||||
// knows about. The "trace kind" is a static map which tells which layout a GC
|
||||
// thing has.
|
||||
//
|
||||
// Although this map is public, the details are completely hidden. Not all of
|
||||
// the matching C++ types are exposed, and those that are, are opaque.
|
||||
//
|
||||
// See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
|
||||
enum class TraceKind
|
||||
{
|
||||
// These trace kinds have a publicly exposed, although opaque, C++ type.
|
||||
// Note: The order here is determined by our Value packing. Other users
|
||||
// should sort alphabetically, for consistency.
|
||||
Object = 0x00,
|
||||
String = 0x01,
|
||||
Symbol = 0x02,
|
||||
Script = 0x03,
|
||||
|
||||
// Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
|
||||
Shape = 0x04,
|
||||
|
||||
// ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
|
||||
ObjectGroup = 0x05,
|
||||
|
||||
// The kind associated with a nullptr.
|
||||
Null = 0x06,
|
||||
|
||||
// The following kinds do not have an exposed C++ idiom.
|
||||
BaseShape = 0x0F,
|
||||
JitCode = 0x1F,
|
||||
LazyScript = 0x2F
|
||||
};
|
||||
const static uintptr_t OutOfLineTraceKindMask = 0x07;
|
||||
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
|
||||
static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
|
||||
static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
|
||||
|
||||
// Returns a static string equivalent of |kind|.
|
||||
JS_FRIEND_API(const char*)
|
||||
GCTraceKindToAscii(JS::TraceKind kind);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
// Tracer callback, called for each traceable thing directly referenced by a
|
||||
// particular object or runtime structure. It is the callback responsibility
|
||||
// to ensure the traversal of the full object graph via calling eventually
|
||||
// JS_TraceChildren on the passed thing. In this case the callback must be
|
||||
// prepared to deal with cycles in the traversal graph.
|
||||
//
|
||||
// kind argument is one of JS::TraceKind::Object, JS::TraceKind::String or a
|
||||
// tag denoting internal implementation-specific traversal kind. In the latter
|
||||
// case the only operations on thing that the callback can do is to call
|
||||
// JS_TraceChildren or JS_GetTraceThingInfo.
|
||||
//
|
||||
// If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all
|
||||
// of its mappings. This should be used in cases where the tracer
|
||||
// wants to use the existing liveness of entries.
|
||||
typedef void
|
||||
(* JSTraceCallback)(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind);
|
||||
namespace js {
|
||||
class BaseShape;
|
||||
class LazyScript;
|
||||
class ObjectGroup;
|
||||
namespace jit {
|
||||
class JitCode;
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
enum WeakMapTraceKind {
|
||||
DoNotTraceWeakMaps = 0,
|
||||
@@ -132,8 +87,34 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
|
||||
contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr)
|
||||
{}
|
||||
|
||||
// Override this method to receive notification when an edge is visited.
|
||||
virtual void trace(void** thing, JS::TraceKind kind) = 0;
|
||||
// Override these methods to receive notification when an edge is visited
|
||||
// with the type contained in the callback. The default implementation
|
||||
// dispatches to the fully-generic onChild implementation, so for cases that
|
||||
// do not care about boxing overhead and do not need the actual edges,
|
||||
// just override the generic onChild.
|
||||
virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
|
||||
virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
|
||||
virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
|
||||
virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
|
||||
virtual void onShapeEdge(js::Shape** shapep) {
|
||||
onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
|
||||
}
|
||||
virtual void onObjectGroupEdge(js::ObjectGroup** groupp) {
|
||||
onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup));
|
||||
}
|
||||
virtual void onBaseShapeEdge(js::BaseShape** basep) {
|
||||
onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape));
|
||||
}
|
||||
virtual void onJitCodeEdge(js::jit::JitCode** codep) {
|
||||
onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode));
|
||||
}
|
||||
virtual void onLazyScriptEdge(js::LazyScript** lazyp) {
|
||||
onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript));
|
||||
}
|
||||
|
||||
// Override this method to receive notification when a node in the GC
|
||||
// heap graph is visited.
|
||||
virtual void onChild(const JS::GCCellPtr& thing) = 0;
|
||||
|
||||
// Access to the tracing context:
|
||||
// When tracing with a JS::CallbackTracer, we invoke the callback with the
|
||||
@@ -185,6 +166,21 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
|
||||
virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; }
|
||||
#endif
|
||||
|
||||
// In C++, overriding a method hides all methods in the base class with
|
||||
// that name, not just methods with that signature. Thus, the typed edge
|
||||
// methods have to have distinct names to allow us to override them
|
||||
// individually, which is freqently useful if, for example, we only want to
|
||||
// process only one type of edge.
|
||||
void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
|
||||
void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
|
||||
void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
|
||||
void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
|
||||
void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
|
||||
void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }
|
||||
void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); }
|
||||
void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); }
|
||||
void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
|
||||
|
||||
private:
|
||||
friend class AutoTracingName;
|
||||
const char* contextName_;
|
||||
|
||||
+1
-1
@@ -331,7 +331,7 @@ class JS_FRIEND_API(Node) {
|
||||
// JS::ubi::Node are both essentially tagged references to other sorts of
|
||||
// objects, so letting conversions happen automatically is appropriate.
|
||||
MOZ_IMPLICIT Node(JS::HandleValue value);
|
||||
Node(JS::TraceKind kind, void* ptr);
|
||||
explicit Node(const JS::GCCellPtr& thing);
|
||||
|
||||
// copy construction and copy assignment just use memcpy, since we know
|
||||
// instances contain nothing but a vtable pointer and a data pointer.
|
||||
|
||||
@@ -24,8 +24,9 @@ using namespace js;
|
||||
* The elementTypes argument is not supported. The result list is
|
||||
* pushed to *args.
|
||||
*/
|
||||
template <class InvokeArgs>
|
||||
static bool
|
||||
InitArgsFromArrayLike(JSContext* cx, HandleValue v, InvokeArgs* args, bool construct)
|
||||
InitArgsFromArrayLike(JSContext* cx, HandleValue v, InvokeArgs* args)
|
||||
{
|
||||
// Step 3.
|
||||
RootedObject obj(cx, NonNullObject(cx, v));
|
||||
@@ -42,7 +43,7 @@ InitArgsFromArrayLike(JSContext* cx, HandleValue v, InvokeArgs* args, bool const
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
|
||||
return false;
|
||||
}
|
||||
if (!args->init(len, construct))
|
||||
if (!args->init(len))
|
||||
return false;
|
||||
|
||||
// Steps 6-8.
|
||||
@@ -71,7 +72,7 @@ Reflect_apply(JSContext* cx, unsigned argc, Value* vp)
|
||||
// Steps 2-3.
|
||||
FastInvokeGuard fig(cx, args.get(0));
|
||||
InvokeArgs& invokeArgs = fig.args();
|
||||
if (!InitArgsFromArrayLike(cx, args.get(2), &invokeArgs, false))
|
||||
if (!InitArgsFromArrayLike(cx, args.get(2), &invokeArgs))
|
||||
return false;
|
||||
invokeArgs.setCallee(args.get(0));
|
||||
invokeArgs.setThis(args.get(1));
|
||||
@@ -108,18 +109,12 @@ Reflect_construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
// Step 4-5.
|
||||
InvokeArgs invokeArgs(cx);
|
||||
if (!InitArgsFromArrayLike(cx, args.get(1), &invokeArgs, true))
|
||||
ConstructArgs constructArgs(cx);
|
||||
if (!InitArgsFromArrayLike(cx, args.get(1), &constructArgs))
|
||||
return false;
|
||||
invokeArgs.setCallee(args.get(0));
|
||||
invokeArgs.setThis(MagicValue(JS_THIS_POISON));
|
||||
invokeArgs.newTarget().set(newTarget);
|
||||
|
||||
// Step 6.
|
||||
if (!InvokeConstructor(cx, invokeArgs))
|
||||
return false;
|
||||
args.rval().set(invokeArgs.rval());
|
||||
return true;
|
||||
return Construct(cx, args.get(0), constructArgs, newTarget, args.rval());
|
||||
}
|
||||
|
||||
/* ES6 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) */
|
||||
|
||||
@@ -800,8 +800,8 @@ class HasChildTracer : public JS::CallbackTracer
|
||||
RootedValue child_;
|
||||
bool found_;
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) {
|
||||
if (*thingp == child_.toGCThing())
|
||||
void onChild(const JS::GCCellPtr& thing) override {
|
||||
if (thing.asCell() == child_.toGCThing())
|
||||
found_ = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,9 +138,15 @@ void
|
||||
CheckHashTablesAfterMovingGC(JSRuntime* rt);
|
||||
#endif
|
||||
|
||||
struct MovingTracer : JS::CallbackTracer {
|
||||
struct MovingTracer : JS::CallbackTracer
|
||||
{
|
||||
explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
|
||||
void onObjectEdge(JSObject** objp) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override {
|
||||
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
TracerKind getTracerKind() const override { return TracerKind::Moving; }
|
||||
#endif
|
||||
|
||||
+11
-11
@@ -2303,9 +2303,9 @@ TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name)
|
||||
#ifdef DEBUG
|
||||
struct AssertNonGrayTracer : public JS::CallbackTracer {
|
||||
explicit AssertNonGrayTracer(JSRuntime* rt) : JS::CallbackTracer(rt) {}
|
||||
void trace(void** thingp, JS::TraceKind kind) override {
|
||||
DebugOnly<Cell*> thing(static_cast<Cell*>(*thingp));
|
||||
MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY));
|
||||
void onChild(const JS::GCCellPtr& thing) override {
|
||||
MOZ_ASSERT_IF(thing.asCell()->isTenured(),
|
||||
!thing.asCell()->asTenured().isMarked(js::gc::GRAY));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -2330,7 +2330,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
|
||||
unmarkedAny(false)
|
||||
{}
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override;
|
||||
|
||||
/* True iff we are tracing the immediate children of a shape. */
|
||||
bool tracingShape;
|
||||
@@ -2373,7 +2373,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
|
||||
* containers.
|
||||
*/
|
||||
void
|
||||
UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing)
|
||||
{
|
||||
int stackDummy;
|
||||
if (!JS_CHECK_STACK_SIZE(runtime()->mainThread.nativeStackLimit[StackForSystemCode],
|
||||
@@ -2387,14 +2387,14 @@ UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
return;
|
||||
}
|
||||
|
||||
Cell* cell = static_cast<Cell*>(*thingp);
|
||||
Cell* cell = thing.asCell();
|
||||
|
||||
// Cells in the nursery cannot be gray, and therefore must necessarily point
|
||||
// to only black edges.
|
||||
if (!cell->isTenured()) {
|
||||
#ifdef DEBUG
|
||||
AssertNonGrayTracer nongray(runtime());
|
||||
TraceChildren(&nongray, cell, kind);
|
||||
TraceChildren(&nongray, cell, thing.kind());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@@ -2411,16 +2411,16 @@ UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
// The parent will later trace |tenured|. This is done to avoid increasing
|
||||
// the stack depth during shape tracing. It is safe to do because a shape
|
||||
// can only have one child that is a shape.
|
||||
UnmarkGrayTracer childTracer(this, kind == JS::TraceKind::Shape);
|
||||
UnmarkGrayTracer childTracer(this, thing.kind() == JS::TraceKind::Shape);
|
||||
|
||||
if (kind != JS::TraceKind::Shape) {
|
||||
TraceChildren(&childTracer, &tenured, kind);
|
||||
if (thing.kind() != JS::TraceKind::Shape) {
|
||||
TraceChildren(&childTracer, &tenured, thing.kind());
|
||||
MOZ_ASSERT(!childTracer.previousShape);
|
||||
unmarkedAny |= childTracer.unmarkedAny;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(kind == JS::TraceKind::Shape);
|
||||
MOZ_ASSERT(thing.kind() == JS::TraceKind::Shape);
|
||||
Shape* shape = static_cast<Shape*>(&tenured);
|
||||
if (tracingShape) {
|
||||
MOZ_ASSERT(!previousShape);
|
||||
|
||||
@@ -484,7 +484,7 @@ class BufferGrayRootsTracer : public JS::CallbackTracer
|
||||
// Set to false if we OOM while buffering gray roots.
|
||||
bool bufferingGrayRootsFailed;
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override;
|
||||
|
||||
public:
|
||||
explicit BufferGrayRootsTracer(JSRuntime* rt)
|
||||
@@ -537,24 +537,24 @@ struct SetMaybeAliveFunctor {
|
||||
};
|
||||
|
||||
void
|
||||
BufferGrayRootsTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
BufferGrayRootsTracer::onChild(const JS::GCCellPtr& thing)
|
||||
{
|
||||
MOZ_ASSERT(runtime()->isHeapBusy());
|
||||
|
||||
if (bufferingGrayRootsFailed)
|
||||
return;
|
||||
|
||||
gc::TenuredCell* thing = gc::TenuredCell::fromPointer(*thingp);
|
||||
gc::TenuredCell* tenured = gc::TenuredCell::fromPointer(thing.asCell());
|
||||
|
||||
Zone* zone = thing->zone();
|
||||
Zone* zone = tenured->zone();
|
||||
if (zone->isCollecting()) {
|
||||
// See the comment on SetMaybeAliveFlag to see why we only do this for
|
||||
// objects and scripts. We rely on gray root buffering for this to work,
|
||||
// but we only need to worry about uncollected dead compartments during
|
||||
// incremental GCs (when we do gray root buffering).
|
||||
CallTyped(SetMaybeAliveFunctor(), thing, kind);
|
||||
CallTyped(SetMaybeAliveFunctor(), tenured, thing.kind());
|
||||
|
||||
if (!zone->gcGrayRoots.append(thing))
|
||||
if (!zone->gcGrayRoots.append(tenured))
|
||||
bufferingGrayRootsFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +47,8 @@ T
|
||||
DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
CheckTracedThing(trc, *thingp);
|
||||
JS::TraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
|
||||
JS::AutoTracingName ctx(trc, name);
|
||||
trc->trace(reinterpret_cast<void**>(thingp), kind);
|
||||
trc->dispatchToOnEdge(thingp);
|
||||
return *thingp;
|
||||
}
|
||||
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \
|
||||
@@ -316,21 +315,19 @@ struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
|
||||
innerTracer(innerTracer)
|
||||
{}
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override;
|
||||
|
||||
JS::CallbackTracer* innerTracer;
|
||||
Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
|
||||
};
|
||||
|
||||
void
|
||||
ObjectGroupCycleCollectorTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing)
|
||||
{
|
||||
JS::GCCellPtr thing(*thingp, kind);
|
||||
|
||||
if (thing.isObject() || thing.isScript()) {
|
||||
// Invoke the inner cycle collector callback on this child. It will not
|
||||
// recurse back into TraceChildren.
|
||||
innerTracer->trace(thingp, kind);
|
||||
innerTracer->onChild(thing);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class js::VerifyPreTracer : public JS::CallbackTracer
|
||||
{
|
||||
JS::AutoDisableGenerationalGC noggc;
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override;
|
||||
|
||||
public:
|
||||
/* The gcNumber when the verification began. */
|
||||
@@ -111,9 +111,9 @@ class js::VerifyPreTracer : public JS::CallbackTracer
|
||||
* node.
|
||||
*/
|
||||
void
|
||||
VerifyPreTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
VerifyPreTracer::onChild(const JS::GCCellPtr& thing)
|
||||
{
|
||||
MOZ_ASSERT(!IsInsideNursery(*reinterpret_cast<Cell**>(thingp)));
|
||||
MOZ_ASSERT(!IsInsideNursery(thing.asCell()));
|
||||
|
||||
edgeptr += sizeof(EdgeValue);
|
||||
if (edgeptr >= term) {
|
||||
@@ -124,8 +124,8 @@ VerifyPreTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
VerifyNode* node = curnode;
|
||||
uint32_t i = node->count;
|
||||
|
||||
node->edges[i].thing = *thingp;
|
||||
node->edges[i].kind = kind;
|
||||
node->edges[i].thing = thing.asCell();
|
||||
node->edges[i].kind = thing.kind();
|
||||
node->edges[i].label = contextName();
|
||||
node->count++;
|
||||
}
|
||||
@@ -251,7 +251,7 @@ IsMarkedOrAllocated(TenuredCell* cell)
|
||||
struct CheckEdgeTracer : public JS::CallbackTracer {
|
||||
VerifyNode* node;
|
||||
explicit CheckEdgeTracer(JSRuntime* rt) : JS::CallbackTracer(rt), node(nullptr) {}
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override;
|
||||
};
|
||||
|
||||
static const uint32_t MAX_VERIFIER_EDGES = 1000;
|
||||
@@ -264,15 +264,15 @@ static const uint32_t MAX_VERIFIER_EDGES = 1000;
|
||||
* been modified) must point to marked objects.
|
||||
*/
|
||||
void
|
||||
CheckEdgeTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
CheckEdgeTracer::onChild(const JS::GCCellPtr& thing)
|
||||
{
|
||||
/* Avoid n^2 behavior. */
|
||||
if (node->count > MAX_VERIFIER_EDGES)
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < node->count; i++) {
|
||||
if (node->edges[i].thing == *thingp) {
|
||||
MOZ_ASSERT(node->edges[i].kind == kind);
|
||||
if (node->edges[i].thing == thing.asCell()) {
|
||||
MOZ_ASSERT(node->edges[i].kind == thing.kind());
|
||||
node->edges[i].thing = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ var t = gen.throw;
|
||||
try {
|
||||
new t;
|
||||
} catch (e) {
|
||||
actual = "" + e;
|
||||
actual = e;
|
||||
}
|
||||
assertEq(actual, "TypeError: t is not a constructor");
|
||||
assertEq(actual.name, "TypeError");
|
||||
assertEq(/is not a constructor/.test(actual.message), true);
|
||||
|
||||
@@ -8882,7 +8882,25 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
||||
}
|
||||
|
||||
if (op == JSOP_NEW) {
|
||||
if (!InvokeConstructor(cx, callee, argc, args, true, res))
|
||||
// Callees from the stack could have any old non-constructor callee.
|
||||
if (!IsConstructor(callee)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, callee, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstructArgs cargs(cx);
|
||||
if (!cargs.init(argc))
|
||||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < argc; i++)
|
||||
cargs[i].set(args[i]);
|
||||
|
||||
RootedValue newTarget(cx, args[argc]);
|
||||
MOZ_ASSERT(IsConstructor(newTarget),
|
||||
"either callee == newTarget, or the initial |new| checked "
|
||||
"that IsConstructor(newTarget)");
|
||||
|
||||
if (!Construct(cx, callee, cargs, newTarget, res))
|
||||
return false;
|
||||
} else if ((op == JSOP_EVAL || op == JSOP_STRICTEVAL) &&
|
||||
frame->scopeChain()->global().valueIsEval(callee))
|
||||
|
||||
@@ -63,16 +63,37 @@ InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc
|
||||
AutoArrayRooter argvRoot(cx, argc + 1 + constructing, argv);
|
||||
|
||||
// Data in the argument vector is arranged for a JIT -> JIT call.
|
||||
Value thisv = argv[0];
|
||||
RootedValue thisv(cx, argv[0]);
|
||||
Value* argvWithoutThis = argv + 1;
|
||||
|
||||
// For constructing functions, |this| is constructed at caller side and we can just call Invoke.
|
||||
// When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
|
||||
// we use InvokeConstructor that creates it at the callee side.
|
||||
if (thisv.isMagic(JS_IS_CONSTRUCTING))
|
||||
return InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, true, rval);
|
||||
RootedValue fval(cx, ObjectValue(*obj));
|
||||
if (constructing) {
|
||||
if (!IsConstructor(fval)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, rval);
|
||||
ConstructArgs cargs(cx);
|
||||
if (!cargs.init(argc))
|
||||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < argc; i++)
|
||||
cargs[i].set(argvWithoutThis[i]);
|
||||
|
||||
RootedValue newTarget(cx, argvWithoutThis[argc]);
|
||||
|
||||
// If |this| hasn't been created, we can use normal construction code.
|
||||
if (thisv.isMagic(JS_IS_CONSTRUCTING))
|
||||
return Construct(cx, fval, cargs, newTarget, rval);
|
||||
|
||||
// Otherwise the default |this| has already been created. We could
|
||||
// almost perform a *call* at this point, but we'd break |new.target|
|
||||
// in the function. So in this one weird case we call a one-off
|
||||
// construction path that *won't* set |this| to JS_IS_CONSTRUCTING.
|
||||
return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
|
||||
}
|
||||
|
||||
return Invoke(cx, thisv, fval, argc, argvWithoutThis, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
class CCWTestTracer : public JS::CallbackTracer {
|
||||
void trace(void** thingp, JS::TraceKind kind) {
|
||||
void onChild(const JS::GCCellPtr& thing) override {
|
||||
numberOfThingsTraced++;
|
||||
|
||||
printf("*thingp = %p\n", *thingp);
|
||||
printf("*thingp = %p\n", thing.asCell());
|
||||
printf("*expectedThingp = %p\n", *expectedThingp);
|
||||
|
||||
printf("kind = %d\n", static_cast<int>(kind));
|
||||
printf("kind = %d\n", static_cast<int>(thing.kind()));
|
||||
printf("expectedKind = %d\n", static_cast<int>(expectedKind));
|
||||
|
||||
if (*thingp != *expectedThingp || kind != expectedKind)
|
||||
if (thing.asCell() != *expectedThingp || thing.kind() != expectedKind)
|
||||
okay = false;
|
||||
}
|
||||
|
||||
|
||||
+75
-49
@@ -318,16 +318,21 @@ IterPerformanceStats(JSContext* cx,
|
||||
}
|
||||
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
|
||||
|
||||
// First report the shared groups
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
JSCompartment* compartment = c.get();
|
||||
if (!compartment->performanceMonitoring.isLinked()) {
|
||||
if (!c->principals()) {
|
||||
// Compartments without principals could show up here, but
|
||||
// reporting them doesn't really make sense.
|
||||
continue;
|
||||
}
|
||||
if (!c->performanceMonitoring.hasSharedGroup()) {
|
||||
// Don't report compartments that do not even have a PerformanceGroup.
|
||||
continue;
|
||||
}
|
||||
|
||||
js::AutoCompartment autoCompartment(cx, compartment);
|
||||
PerformanceGroup* group = compartment->performanceMonitoring.getGroup(cx);
|
||||
|
||||
PerformanceGroup* group = compartment->performanceMonitoring.getSharedGroup(cx);
|
||||
if (group->data.ticks == 0) {
|
||||
// Don't report compartments that have never been used.
|
||||
continue;
|
||||
@@ -339,7 +344,9 @@ IterPerformanceStats(JSContext* cx,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(*walker)(cx, group->data, group->uid, closure)) {
|
||||
if (!(*walker)(cx,
|
||||
group->data, group->uid, nullptr,
|
||||
closure)) {
|
||||
// Issue in callback
|
||||
return false;
|
||||
}
|
||||
@@ -348,7 +355,36 @@ IterPerformanceStats(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*processStats = rt->stopwatch.performance;
|
||||
|
||||
// Then report the own groups
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
|
||||
JSCompartment* compartment = c.get();
|
||||
if (!c->principals()) {
|
||||
// Compartments without principals could show up here, but
|
||||
// reporting them doesn't really make sense.
|
||||
continue;
|
||||
}
|
||||
if (!c->performanceMonitoring.hasOwnGroup()) {
|
||||
// Don't report compartments that do not even have a PerformanceGroup.
|
||||
continue;
|
||||
}
|
||||
js::AutoCompartment autoCompartment(cx, compartment);
|
||||
mozilla::RefPtr<PerformanceGroup> ownGroup = compartment->performanceMonitoring.getOwnGroup();
|
||||
if (ownGroup->data.ticks == 0) {
|
||||
// Don't report compartments that have never been used.
|
||||
continue;
|
||||
}
|
||||
mozilla::RefPtr<PerformanceGroup> sharedGroup = compartment->performanceMonitoring.getSharedGroup(cx);
|
||||
if (!(*walker)(cx,
|
||||
ownGroup->data, ownGroup->uid, &sharedGroup->uid,
|
||||
closure)) {
|
||||
// Issue in callback
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, report the process stats
|
||||
*processStats = rt->stopwatch.performance.getOwnGroup()->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4604,7 +4640,16 @@ JS::Construct(JSContext* cx, HandleValue fval, const JS::HandleValueArray& args,
|
||||
assertSameCompartment(cx, fval, args);
|
||||
AutoLastFrameCheck lfc(cx);
|
||||
|
||||
return InvokeConstructor(cx, fval, args.length(), args.begin(), false, rval);
|
||||
if (!IsConstructor(fval)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstructArgs cargs(cx);
|
||||
if (!FillArgumentsFromArraylike(cx, cargs, args))
|
||||
return false;
|
||||
|
||||
return js::Construct(cx, fval, cargs, fval, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
@@ -4616,26 +4661,22 @@ JS::Construct(JSContext* cx, HandleValue fval, HandleObject newTarget, const JS:
|
||||
assertSameCompartment(cx, fval, newTarget, args);
|
||||
AutoLastFrameCheck lfc(cx);
|
||||
|
||||
// Reflect.construct ensures that the supplied new.target value is a
|
||||
// constructor. Frankly, this makes good sense, so we reproduce the check.
|
||||
if (!newTarget->isConstructor()) {
|
||||
RootedValue val(cx, ObjectValue(*newTarget));
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, val, nullptr);
|
||||
if (!IsConstructor(fval)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is a littlesilly, but we need to convert from what's useful for our
|
||||
// consumers to what we can actually handle internally.
|
||||
AutoValueVector argv(cx);
|
||||
unsigned argc = args.length();
|
||||
if (!argv.reserve(argc + 1))
|
||||
RootedValue newTargetVal(cx, ObjectValue(*newTarget));
|
||||
if (!IsConstructor(newTargetVal)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, newTargetVal, nullptr);
|
||||
return false;
|
||||
for (unsigned i = 0; i < argc; i++) {
|
||||
argv.infallibleAppend(args[i]);
|
||||
}
|
||||
argv.infallibleAppend(ObjectValue(*newTarget));
|
||||
|
||||
return InvokeConstructor(cx, fval, argc, argv.begin(), true, rval);
|
||||
ConstructArgs cargs(cx);
|
||||
if (!FillArgumentsFromArraylike(cx, cargs, args))
|
||||
return false;
|
||||
|
||||
return js::Construct(cx, fval, cargs, newTargetVal, rval);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
@@ -4645,36 +4686,21 @@ JS_NewHelper(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& input
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, ctor, inputArgs);
|
||||
|
||||
// This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
|
||||
// is not a simple variation of JSOP_CALL. We have to determine what class
|
||||
// of object to create, create it, and clamp the return value to an object,
|
||||
// among other details. InvokeConstructor does the hard work.
|
||||
InvokeArgs args(cx);
|
||||
if (!args.init(inputArgs.length(), true))
|
||||
return nullptr;
|
||||
|
||||
args.setCallee(ObjectValue(*ctor));
|
||||
args.setThis(NullValue());
|
||||
PodCopy(args.array(), inputArgs.begin(), inputArgs.length());
|
||||
args.newTarget().setObject(*ctor);
|
||||
|
||||
if (!InvokeConstructor(cx, args))
|
||||
return nullptr;
|
||||
|
||||
if (!args.rval().isObject()) {
|
||||
/*
|
||||
* Although constructors may return primitives (via proxies), this
|
||||
* API is asking for an object, so we report an error.
|
||||
*/
|
||||
JSAutoByteString bytes;
|
||||
if (ValueToPrintable(cx, args.rval(), &bytes)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_NEW_RESULT,
|
||||
bytes.ptr());
|
||||
}
|
||||
RootedValue ctorVal(cx, ObjectValue(*ctor));
|
||||
if (!IsConstructor(ctorVal)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, ctorVal, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &args.rval().toObject();
|
||||
ConstructArgs args(cx);
|
||||
if (!FillArgumentsFromArraylike(cx, args, inputArgs))
|
||||
return nullptr;
|
||||
|
||||
RootedValue rval(cx);
|
||||
if (!js::Construct(cx, ctorVal, args, ctorVal, &rval))
|
||||
return nullptr;
|
||||
|
||||
return &rval.toObject();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
|
||||
+51
-33
@@ -13,6 +13,7 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
@@ -5428,7 +5429,7 @@ BuildStackString(JSContext *cx, HandleObject stack, MutableHandleString stringp)
|
||||
|
||||
namespace js {
|
||||
|
||||
struct AutoStopwatch;
|
||||
class AutoStopwatch;
|
||||
|
||||
// Container for performance data
|
||||
// All values are monotonic.
|
||||
@@ -5522,15 +5523,22 @@ struct PerformanceGroup {
|
||||
stopwatch_ = nullptr;
|
||||
}
|
||||
|
||||
explicit PerformanceGroup(JSContext* cx, void* key);
|
||||
~PerformanceGroup()
|
||||
{
|
||||
MOZ_ASSERT(refCount_ == 0);
|
||||
}
|
||||
private:
|
||||
// Refcounting. For use with mozilla::RefPtr.
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
// Construct a PerformanceGroup for a single compartment.
|
||||
explicit PerformanceGroup(JSRuntime* rt);
|
||||
|
||||
// Construct a PerformanceGroup for a group of compartments.
|
||||
explicit PerformanceGroup(JSContext* rt, void* key);
|
||||
|
||||
private:
|
||||
PerformanceGroup& operator=(const PerformanceGroup&) = delete;
|
||||
PerformanceGroup(const PerformanceGroup&) = delete;
|
||||
|
||||
JSRuntime* runtime_;
|
||||
|
||||
// The stopwatch currently monitoring the group,
|
||||
// or `nullptr` if none. Used ony for comparison.
|
||||
const AutoStopwatch* stopwatch_;
|
||||
@@ -5542,38 +5550,41 @@ struct PerformanceGroup {
|
||||
// The hash key for this PerformanceGroup.
|
||||
void* const key_;
|
||||
|
||||
// Increment/decrement the refcounter, return the updated value.
|
||||
uint64_t incRefCount() {
|
||||
MOZ_ASSERT(refCount_ + 1 > 0);
|
||||
return ++refCount_;
|
||||
}
|
||||
uint64_t decRefCount() {
|
||||
MOZ_ASSERT(refCount_ > 0);
|
||||
return --refCount_;
|
||||
}
|
||||
friend struct PerformanceGroupHolder;
|
||||
|
||||
private:
|
||||
// A reference counter. Maintained by PerformanceGroupHolder.
|
||||
// A reference counter.
|
||||
uint64_t refCount_;
|
||||
|
||||
|
||||
// `true` if this PerformanceGroup may be shared by several
|
||||
// compartments, `false` if it is dedicated to a single
|
||||
// compartment.
|
||||
const bool isSharedGroup_;
|
||||
};
|
||||
|
||||
//
|
||||
// Indirection towards a PerformanceGroup.
|
||||
// This structure handles reference counting for instances of PerformanceGroup.
|
||||
// Each PerformanceGroupHolder handles:
|
||||
// - a reference-counted indirection towards a PerformanceGroup shared
|
||||
// by several compartments
|
||||
// - a owned PerformanceGroup representing the performance of a single
|
||||
// compartment.
|
||||
//
|
||||
struct PerformanceGroupHolder {
|
||||
// Get the group.
|
||||
// Get the shared group.
|
||||
// On first call, this causes a single Hashtable lookup.
|
||||
// Successive calls do not require further lookups.
|
||||
js::PerformanceGroup* getGroup(JSContext*);
|
||||
js::PerformanceGroup* getSharedGroup(JSContext*);
|
||||
|
||||
// `true` if the this holder is currently associated to a
|
||||
// Get the own group.
|
||||
js::PerformanceGroup* getOwnGroup();
|
||||
|
||||
// `true` if the this holder is currently associated to a shared
|
||||
// PerformanceGroup, `false` otherwise. Use this method to avoid
|
||||
// instantiating a PerformanceGroup if you only need to get
|
||||
// available performance data.
|
||||
inline bool isLinked() const {
|
||||
return group_ != nullptr;
|
||||
inline bool hasSharedGroup() const {
|
||||
return sharedGroup_ != nullptr;
|
||||
}
|
||||
inline bool hasOwnGroup() const {
|
||||
return ownGroup_ != nullptr;
|
||||
}
|
||||
|
||||
// Remove the link to the PerformanceGroup. This method is designed
|
||||
@@ -5583,10 +5594,10 @@ struct PerformanceGroupHolder {
|
||||
|
||||
explicit PerformanceGroupHolder(JSRuntime* runtime)
|
||||
: runtime_(runtime)
|
||||
, group_(nullptr)
|
||||
{ }
|
||||
~PerformanceGroupHolder();
|
||||
private:
|
||||
|
||||
private:
|
||||
// Return the key representing this PerformanceGroup in
|
||||
// Runtime::Stopwatch.
|
||||
// Do not deallocate the key.
|
||||
@@ -5594,10 +5605,11 @@ private:
|
||||
|
||||
JSRuntime *runtime_;
|
||||
|
||||
// The PerformanceGroup held by this object.
|
||||
// Initially set to `nullptr` until the first cal to `getGroup`.
|
||||
// The PerformanceGroups held by this object.
|
||||
// Initially set to `nullptr` until the first call to `getGroup`.
|
||||
// May be reset to `nullptr` by a call to `unlink`.
|
||||
js::PerformanceGroup* group_;
|
||||
mozilla::RefPtr<js::PerformanceGroup> sharedGroup_;
|
||||
mozilla::RefPtr<js::PerformanceGroup> ownGroup_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -5623,6 +5635,10 @@ extern JS_PUBLIC_API(bool)
|
||||
SetStopwatchIsMonitoringJank(JSRuntime*, bool);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
GetStopwatchIsMonitoringJank(JSRuntime*);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
SetStopwatchIsMonitoringPerCompartment(JSRuntime*, bool);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
GetStopwatchIsMonitoringPerCompartment(JSRuntime*);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsStopwatchActive(JSRuntime*);
|
||||
@@ -5634,7 +5650,9 @@ extern JS_PUBLIC_API(PerformanceData*)
|
||||
GetPerformanceData(JSRuntime*);
|
||||
|
||||
typedef bool
|
||||
(PerformanceStatsWalker)(JSContext* cx, const PerformanceData& stats, uint64_t uid, void* closure);
|
||||
(PerformanceStatsWalker)(JSContext* cx,
|
||||
const PerformanceData& stats, uint64_t uid,
|
||||
const uint64_t* parentId, void* closure);
|
||||
|
||||
/**
|
||||
* Extract the performance statistics.
|
||||
|
||||
+8
-5
@@ -3152,13 +3152,16 @@ array_of(JSContext* cx, unsigned argc, Value* vp)
|
||||
// Step 4.
|
||||
RootedObject obj(cx);
|
||||
{
|
||||
ConstructArgs cargs(cx);
|
||||
if (!cargs.init(1))
|
||||
return false;
|
||||
cargs[0].setNumber(args.length());
|
||||
|
||||
RootedValue v(cx);
|
||||
Value argv[1] = {NumberValue(args.length())};
|
||||
if (!InvokeConstructor(cx, args.thisv(), 1, argv, false, &v))
|
||||
return false;
|
||||
obj = ToObject(cx, v);
|
||||
if (!obj)
|
||||
if (!Construct(cx, args.thisv(), cargs, args.thisv(), &v))
|
||||
return false;
|
||||
|
||||
obj = &v.toObject();
|
||||
}
|
||||
|
||||
// Step 8.
|
||||
|
||||
@@ -853,7 +853,7 @@ struct DumpHeapTracer : public JS::CallbackTracer, public WeakMapTracer
|
||||
map, key.asCell(), kdelegate, value.asCell());
|
||||
}
|
||||
|
||||
void trace(void** thingp, JS::TraceKind kind) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override;
|
||||
};
|
||||
|
||||
static char
|
||||
@@ -907,14 +907,14 @@ DumpHeapVisitCell(JSRuntime* rt, void* data, void* thing,
|
||||
}
|
||||
|
||||
void
|
||||
DumpHeapTracer::trace(void** thingp, JS::TraceKind kind)
|
||||
DumpHeapTracer::onChild(const JS::GCCellPtr& thing)
|
||||
{
|
||||
if (gc::IsInsideNursery((js::gc::Cell*)*thingp))
|
||||
if (gc::IsInsideNursery(thing.asCell()))
|
||||
return;
|
||||
|
||||
char buffer[1024];
|
||||
getTracingEdgeName(buffer, sizeof(buffer));
|
||||
fprintf(output, "%s%p %c %s\n", prefix, *thingp, MarkDescriptor(*thingp), buffer);
|
||||
fprintf(output, "%s%p %c %s\n", prefix, thing.asCell(), MarkDescriptor(thing.asCell()), buffer);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user