зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
a3ba8f387e
|
@ -985,6 +985,9 @@ HyperTextAccessible::NativeAttributes()
|
||||||
nsIAtom*
|
nsIAtom*
|
||||||
HyperTextAccessible::LandmarkRole() const
|
HyperTextAccessible::LandmarkRole() const
|
||||||
{
|
{
|
||||||
|
if (!HasOwnContent())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// For the html landmark elements we expose them like we do ARIA landmarks to
|
// For the html landmark elements we expose them like we do ARIA landmarks to
|
||||||
// make AT navigation schemes "just work".
|
// make AT navigation schemes "just work".
|
||||||
if (mContent->IsHTMLElement(nsGkAtoms::nav)) {
|
if (mContent->IsHTMLElement(nsGkAtoms::nav)) {
|
||||||
|
|
|
@ -477,7 +477,6 @@ var FullScreen = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track whether mouse is near the toolbox
|
// Track whether mouse is near the toolbox
|
||||||
this._isChromeCollapsed = false;
|
|
||||||
if (trackMouse && !this.useLionFullScreen) {
|
if (trackMouse && !this.useLionFullScreen) {
|
||||||
let rect = gBrowser.mPanelContainer.getBoundingClientRect();
|
let rect = gBrowser.mPanelContainer.getBoundingClientRect();
|
||||||
this._mouseTargetRect = {
|
this._mouseTargetRect = {
|
||||||
|
@ -488,6 +487,8 @@ var FullScreen = {
|
||||||
};
|
};
|
||||||
MousePosTracker.addListener(this);
|
MousePosTracker.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._isChromeCollapsed = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
hideNavToolbox: function (aAnimate = false) {
|
hideNavToolbox: function (aAnimate = false) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
|
||||||
{
|
{
|
||||||
MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
||||||
|
|
||||||
nsRefPtr<URLSearchParams> usp = new URLSearchParams();
|
nsRefPtr<URLSearchParams> usp = new URLSearchParams(nullptr);
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
|
|
||||||
if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
|
if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
|
||||||
|
@ -108,8 +108,8 @@ OriginAttributes::PopulateFromSuffix(const nsACString& aStr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<URLSearchParams> usp = new URLSearchParams();
|
nsRefPtr<URLSearchParams> usp = new URLSearchParams(nullptr);
|
||||||
usp->ParseInput(Substring(aStr, 1, aStr.Length() - 1), nullptr);
|
usp->ParseInput(Substring(aStr, 1, aStr.Length() - 1));
|
||||||
|
|
||||||
PopulateFromSuffixIterator iterator(this);
|
PopulateFromSuffixIterator iterator(this);
|
||||||
return usp->ForEach(iterator);
|
return usp->ForEach(iterator);
|
||||||
|
|
|
@ -193,7 +193,6 @@
|
||||||
#include "nsIWidget.h"
|
#include "nsIWidget.h"
|
||||||
#include "mozilla/dom/EncodingUtils.h"
|
#include "mozilla/dom/EncodingUtils.h"
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
#include "mozilla/dom/URLSearchParams.h"
|
|
||||||
#include "nsPerformance.h"
|
#include "nsPerformance.h"
|
||||||
|
|
||||||
#ifdef MOZ_TOOLKIT_SEARCH
|
#ifdef MOZ_TOOLKIT_SEARCH
|
||||||
|
@ -2022,24 +2021,6 @@ nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
|
||||||
mLSHE->GetIsSubFrame(&isSubFrame);
|
mLSHE->GetIsSubFrame(&isSubFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// nsDocShell owns a URLSearchParams that is used by
|
|
||||||
// window.location.searchParams to be in sync with the current location.
|
|
||||||
if (!mURLSearchParams) {
|
|
||||||
mURLSearchParams = new URLSearchParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString search;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURL> url(do_QueryInterface(mCurrentURI));
|
|
||||||
if (url) {
|
|
||||||
nsresult rv = url->GetQuery(search);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
NS_WARNING("Failed to get the query from a nsIURL.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mURLSearchParams->ParseInput(search, nullptr);
|
|
||||||
|
|
||||||
if (!isSubFrame && !isRoot) {
|
if (!isSubFrame && !isRoot) {
|
||||||
/*
|
/*
|
||||||
* We don't want to send OnLocationChange notifications when
|
* We don't want to send OnLocationChange notifications when
|
||||||
|
@ -5846,11 +5827,6 @@ nsDocShell::Destroy()
|
||||||
mParentWidget = nullptr;
|
mParentWidget = nullptr;
|
||||||
mCurrentURI = nullptr;
|
mCurrentURI = nullptr;
|
||||||
|
|
||||||
if (mURLSearchParams) {
|
|
||||||
mURLSearchParams->RemoveObservers();
|
|
||||||
mURLSearchParams = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mScriptGlobal) {
|
if (mScriptGlobal) {
|
||||||
mScriptGlobal->DetachFromDocShell();
|
mScriptGlobal->DetachFromDocShell();
|
||||||
mScriptGlobal = nullptr;
|
mScriptGlobal = nullptr;
|
||||||
|
@ -13931,12 +13907,6 @@ nsDocShell::GetOpener()
|
||||||
return opener;
|
return opener;
|
||||||
}
|
}
|
||||||
|
|
||||||
URLSearchParams*
|
|
||||||
nsDocShell::GetURLSearchParams()
|
|
||||||
{
|
|
||||||
return mURLSearchParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
class JavascriptTimelineMarker : public TimelineMarker
|
class JavascriptTimelineMarker : public TimelineMarker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -60,7 +60,6 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class EventTarget;
|
class EventTarget;
|
||||||
class URLSearchParams;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,9 +840,6 @@ protected:
|
||||||
nsCOMPtr<nsIChannel> mFailedChannel;
|
nsCOMPtr<nsIChannel> mFailedChannel;
|
||||||
uint32_t mFailedLoadType;
|
uint32_t mFailedLoadType;
|
||||||
|
|
||||||
// window.location.searchParams is updated in sync with this object.
|
|
||||||
nsRefPtr<mozilla::dom::URLSearchParams> mURLSearchParams;
|
|
||||||
|
|
||||||
// Set in DoURILoad when either the LOAD_RELOAD_ALLOW_MIXED_CONTENT flag or
|
// Set in DoURILoad when either the LOAD_RELOAD_ALLOW_MIXED_CONTENT flag or
|
||||||
// the LOAD_NORMAL_ALLOW_MIXED_CONTENT flag is set.
|
// the LOAD_NORMAL_ALLOW_MIXED_CONTENT flag is set.
|
||||||
// Checked in nsMixedContentBlocker, to see if the channels match.
|
// Checked in nsMixedContentBlocker, to see if the channels match.
|
||||||
|
|
|
@ -11,13 +11,6 @@
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
class nsIPresShell;
|
class nsIPresShell;
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
class URLSearchParams;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +19,6 @@ class URLSearchParams;
|
||||||
|
|
||||||
[ptr] native nsPresContext(nsPresContext);
|
[ptr] native nsPresContext(nsPresContext);
|
||||||
[ptr] native nsIPresShell(nsIPresShell);
|
[ptr] native nsIPresShell(nsIPresShell);
|
||||||
[ptr] native URLSearchParams(mozilla::dom::URLSearchParams);
|
|
||||||
|
|
||||||
interface nsIURI;
|
interface nsIURI;
|
||||||
interface nsIChannel;
|
interface nsIChannel;
|
||||||
|
@ -54,7 +46,7 @@ interface nsITabParent;
|
||||||
|
|
||||||
typedef unsigned long nsLoadFlags;
|
typedef unsigned long nsLoadFlags;
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(696b32a1-3cf1-4909-b501-474b25fc7954)]
|
[scriptable, builtinclass, uuid(b3137b7c-d589-48aa-b89b-e02aa451d42c)]
|
||||||
interface nsIDocShell : nsIDocShellTreeItem
|
interface nsIDocShell : nsIDocShellTreeItem
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -1031,9 +1023,6 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||||
[noscript,notxpcom,nostdcall] void setOpener(in nsITabParent aOpener);
|
[noscript,notxpcom,nostdcall] void setOpener(in nsITabParent aOpener);
|
||||||
[noscript,notxpcom,nostdcall] nsITabParent getOpener();
|
[noscript,notxpcom,nostdcall] nsITabParent getOpener();
|
||||||
|
|
||||||
// URLSearchParams for the window.location is owned by the docShell.
|
|
||||||
[noscript,notxpcom] URLSearchParams getURLSearchParams();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify DocShell when the browser is about to start executing JS, and after
|
* Notify DocShell when the browser is about to start executing JS, and after
|
||||||
* that execution has stopped. This only occurs when the Timeline devtool
|
* that execution has stopped. This only occurs when the Timeline devtool
|
||||||
|
|
|
@ -19,5 +19,14 @@ ChromeUtils::OriginAttributesToCookieJar(GlobalObject& aGlobal,
|
||||||
attrs.CookieJar(aCookieJar);
|
attrs.CookieJar(aCookieJar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||||
|
const dom::OriginAttributesDictionary& aAttrs,
|
||||||
|
nsCString& aSuffix)
|
||||||
|
|
||||||
|
{
|
||||||
|
OriginAttributes attrs(aAttrs);
|
||||||
|
attrs.CreateSuffix(aSuffix);
|
||||||
|
}
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -44,6 +44,11 @@ public:
|
||||||
OriginAttributesToCookieJar(dom::GlobalObject& aGlobal,
|
OriginAttributesToCookieJar(dom::GlobalObject& aGlobal,
|
||||||
const dom::OriginAttributesDictionary& aAttrs,
|
const dom::OriginAttributesDictionary& aAttrs,
|
||||||
nsCString& aCookieJar);
|
nsCString& aCookieJar);
|
||||||
|
|
||||||
|
static void
|
||||||
|
OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||||
|
const dom::OriginAttributesDictionary& aAttrs,
|
||||||
|
nsCString& aSuffix);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -578,21 +578,6 @@ Link::SearchParams()
|
||||||
return mSearchParams;
|
return mSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Link::SetSearchParams(URLSearchParams& aSearchParams)
|
|
||||||
{
|
|
||||||
if (mSearchParams) {
|
|
||||||
mSearchParams->RemoveObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
mSearchParams = &aSearchParams;
|
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
|
|
||||||
nsAutoString search;
|
|
||||||
mSearchParams->Serialize(search);
|
|
||||||
SetSearchInternal(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Link::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
|
Link::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
|
||||||
{
|
{
|
||||||
|
@ -621,15 +606,14 @@ Link::UpdateURLSearchParams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSearchParams->ParseInput(search, this);
|
mSearchParams->ParseInput(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Link::CreateSearchParamsIfNeeded()
|
Link::CreateSearchParamsIfNeeded()
|
||||||
{
|
{
|
||||||
if (!mSearchParams) {
|
if (!mSearchParams) {
|
||||||
mSearchParams = new URLSearchParams();
|
mSearchParams = new URLSearchParams(this);
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
UpdateURLSearchParams();
|
UpdateURLSearchParams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,7 +622,6 @@ void
|
||||||
Link::Unlink()
|
Link::Unlink()
|
||||||
{
|
{
|
||||||
if (mSearchParams) {
|
if (mSearchParams) {
|
||||||
mSearchParams->RemoveObserver(this);
|
|
||||||
mSearchParams = nullptr;
|
mSearchParams = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ public:
|
||||||
void SetHostname(const nsAString &aHostname, ErrorResult& aError);
|
void SetHostname(const nsAString &aHostname, ErrorResult& aError);
|
||||||
void SetPathname(const nsAString &aPathname, ErrorResult& aError);
|
void SetPathname(const nsAString &aPathname, ErrorResult& aError);
|
||||||
void SetSearch(const nsAString &aSearch, ErrorResult& aError);
|
void SetSearch(const nsAString &aSearch, ErrorResult& aError);
|
||||||
void SetSearchParams(mozilla::dom::URLSearchParams& aSearchParams);
|
|
||||||
void SetPort(const nsAString &aPort, ErrorResult& aError);
|
void SetPort(const nsAString &aPort, ErrorResult& aError);
|
||||||
void SetHash(const nsAString &aHash, ErrorResult& aError);
|
void SetHash(const nsAString &aHash, ErrorResult& aError);
|
||||||
void GetOrigin(nsAString &aOrigin, ErrorResult& aError);
|
void GetOrigin(nsAString &aOrigin, ErrorResult& aError);
|
||||||
|
|
|
@ -238,7 +238,13 @@ PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag,
|
||||||
uint64_t aExtraData,
|
uint64_t aExtraData,
|
||||||
void* aClosure)
|
void* aClosure)
|
||||||
{
|
{
|
||||||
// Nothing to do.
|
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
MOZ_ASSERT(!aContent);
|
||||||
|
|
||||||
|
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
|
||||||
|
MessagePort::ForceClose(scInfo->event->GetPortIdentifier(aExtraData));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
|
PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
|
||||||
|
|
|
@ -27,7 +27,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(URL)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
|
||||||
if (tmp->mSearchParams) {
|
if (tmp->mSearchParams) {
|
||||||
tmp->mSearchParams->RemoveObserver(tmp);
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
|
||||||
}
|
}
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
@ -374,7 +373,7 @@ URL::UpdateURLSearchParams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSearchParams->ParseInput(search, this);
|
mSearchParams->ParseInput(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -500,22 +499,6 @@ URL::SearchParams()
|
||||||
return mSearchParams;
|
return mSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
URL::SetSearchParams(URLSearchParams& aSearchParams)
|
|
||||||
{
|
|
||||||
if (mSearchParams) {
|
|
||||||
mSearchParams->RemoveObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the observer will be cleared using the cycle collector.
|
|
||||||
mSearchParams = &aSearchParams;
|
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
|
|
||||||
nsAutoString search;
|
|
||||||
mSearchParams->Serialize(search);
|
|
||||||
SetSearchInternal(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
|
URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
|
||||||
{
|
{
|
||||||
|
@ -550,8 +533,7 @@ void
|
||||||
URL::CreateSearchParamsIfNeeded()
|
URL::CreateSearchParamsIfNeeded()
|
||||||
{
|
{
|
||||||
if (!mSearchParams) {
|
if (!mSearchParams) {
|
||||||
mSearchParams = new URLSearchParams();
|
mSearchParams = new URLSearchParams(this);
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
UpdateURLSearchParams();
|
UpdateURLSearchParams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,8 +119,6 @@ public:
|
||||||
|
|
||||||
URLSearchParams* SearchParams();
|
URLSearchParams* SearchParams();
|
||||||
|
|
||||||
void SetSearchParams(URLSearchParams& aSearchParams);
|
|
||||||
|
|
||||||
void GetHash(nsAString& aRetval, ErrorResult& aRv) const;
|
void GetHash(nsAString& aRetval, ErrorResult& aRv) const;
|
||||||
|
|
||||||
void SetHash(const nsAString& aArg, ErrorResult& aRv);
|
void SetHash(const nsAString& aArg, ErrorResult& aRv);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObservers)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObserver)
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
URLSearchParams::URLSearchParams()
|
URLSearchParams::URLSearchParams(URLSearchParamsObserver* aObserver)
|
||||||
|
: mObserver(aObserver)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +42,8 @@ URLSearchParams::Constructor(const GlobalObject& aGlobal,
|
||||||
const nsAString& aInit,
|
const nsAString& aInit,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
nsRefPtr<URLSearchParams> sp = new URLSearchParams();
|
nsRefPtr<URLSearchParams> sp = new URLSearchParams(nullptr);
|
||||||
sp->ParseInput(NS_ConvertUTF16toUTF8(aInit), nullptr);
|
sp->ParseInput(NS_ConvertUTF16toUTF8(aInit));
|
||||||
return sp.forget();
|
return sp.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +52,13 @@ URLSearchParams::Constructor(const GlobalObject& aGlobal,
|
||||||
URLSearchParams& aInit,
|
URLSearchParams& aInit,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
nsRefPtr<URLSearchParams> sp = new URLSearchParams();
|
nsRefPtr<URLSearchParams> sp = new URLSearchParams(nullptr);
|
||||||
sp->mSearchParams = aInit.mSearchParams;
|
sp->mSearchParams = aInit.mSearchParams;
|
||||||
return sp.forget();
|
return sp.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
URLSearchParams::ParseInput(const nsACString& aInput,
|
URLSearchParams::ParseInput(const nsACString& aInput)
|
||||||
URLSearchParamsObserver* aObserver)
|
|
||||||
{
|
{
|
||||||
// Remove all the existing data before parsing a new input.
|
// Remove all the existing data before parsing a new input.
|
||||||
DeleteAll();
|
DeleteAll();
|
||||||
|
@ -108,8 +108,6 @@ URLSearchParams::ParseInput(const nsACString& aInput,
|
||||||
|
|
||||||
AppendInternal(decodedName, decodedValue);
|
AppendInternal(decodedName, decodedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotifyObservers(aObserver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -208,27 +206,6 @@ URLSearchParams::ConvertString(const nsACString& aInput, nsAString& aOutput)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aObserver);
|
|
||||||
MOZ_ASSERT(!mObservers.Contains(aObserver));
|
|
||||||
mObservers.AppendElement(aObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aObserver);
|
|
||||||
mObservers.RemoveElement(aObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
URLSearchParams::RemoveObservers()
|
|
||||||
{
|
|
||||||
mObservers.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
|
URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
|
||||||
{
|
{
|
||||||
|
@ -280,14 +257,14 @@ URLSearchParams::Set(const nsAString& aName, const nsAString& aValue)
|
||||||
|
|
||||||
param->mValue = aValue;
|
param->mValue = aValue;
|
||||||
|
|
||||||
NotifyObservers(nullptr);
|
NotifyObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
|
URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
|
||||||
{
|
{
|
||||||
AppendInternal(aName, aValue);
|
AppendInternal(aName, aValue);
|
||||||
NotifyObservers(nullptr);
|
NotifyObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -324,7 +301,7 @@ URLSearchParams::Delete(const nsAString& aName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
NotifyObservers(nullptr);
|
NotifyObserver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,12 +357,10 @@ URLSearchParams::Serialize(nsAString& aValue) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
URLSearchParams::NotifyObservers(URLSearchParamsObserver* aExceptObserver)
|
URLSearchParams::NotifyObserver()
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < mObservers.Length(); ++i) {
|
if (mObserver) {
|
||||||
if (mObservers[i] != aExceptObserver) {
|
mObserver->URLSearchParamsUpdated(this);
|
||||||
mObservers[i]->URLSearchParamsUpdated(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URLSearchParams)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URLSearchParams)
|
||||||
|
|
||||||
URLSearchParams();
|
explicit URLSearchParams(URLSearchParamsObserver* aObserver);
|
||||||
|
|
||||||
// WebIDL methods
|
// WebIDL methods
|
||||||
nsISupports* GetParentObject() const
|
nsISupports* GetParentObject() const
|
||||||
|
@ -59,12 +59,7 @@ public:
|
||||||
Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
|
Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void ParseInput(const nsACString& aInput,
|
void ParseInput(const nsACString& aInput);
|
||||||
URLSearchParamsObserver* aObserver);
|
|
||||||
|
|
||||||
void AddObserver(URLSearchParamsObserver* aObserver);
|
|
||||||
void RemoveObserver(URLSearchParamsObserver* aObserver);
|
|
||||||
void RemoveObservers();
|
|
||||||
|
|
||||||
void Serialize(nsAString& aValue) const;
|
void Serialize(nsAString& aValue) const;
|
||||||
|
|
||||||
|
@ -113,7 +108,7 @@ private:
|
||||||
void DecodeString(const nsACString& aInput, nsAString& aOutput);
|
void DecodeString(const nsACString& aInput, nsAString& aOutput);
|
||||||
void ConvertString(const nsACString& aInput, nsAString& aOutput);
|
void ConvertString(const nsACString& aInput, nsAString& aOutput);
|
||||||
|
|
||||||
void NotifyObservers(URLSearchParamsObserver* aExceptObserver);
|
void NotifyObserver();
|
||||||
|
|
||||||
struct Param
|
struct Param
|
||||||
{
|
{
|
||||||
|
@ -123,7 +118,7 @@ private:
|
||||||
|
|
||||||
nsTArray<Param> mSearchParams;
|
nsTArray<Param> mSearchParams;
|
||||||
|
|
||||||
nsTArray<nsRefPtr<URLSearchParamsObserver>> mObservers;
|
nsRefPtr<URLSearchParamsObserver> mObserver;
|
||||||
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ nsLocation::nsLocation(nsPIDOMWindow* aWindow, nsIDocShell *aDocShell)
|
||||||
|
|
||||||
nsLocation::~nsLocation()
|
nsLocation::~nsLocation()
|
||||||
{
|
{
|
||||||
RemoveURLSearchParams();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryInterface implementation for nsLocation
|
// QueryInterface implementation for nsLocation
|
||||||
|
@ -74,14 +73,11 @@ NS_INTERFACE_MAP_END
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsLocation)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsLocation)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsLocation)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsLocation)
|
||||||
tmp->RemoveURLSearchParams();
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInnerWindow);
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInnerWindow);
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsLocation)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsLocation)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInnerWindow)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInnerWindow)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
@ -1057,119 +1053,3 @@ nsLocation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||||
{
|
{
|
||||||
return LocationBinding::Wrap(aCx, this, aGivenProto);
|
return LocationBinding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
URLSearchParams*
|
|
||||||
nsLocation::GetDocShellSearchParams()
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
|
|
||||||
if (!docShell) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return docShell->GetURLSearchParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
URLSearchParams*
|
|
||||||
nsLocation::SearchParams()
|
|
||||||
{
|
|
||||||
if (!mSearchParams) {
|
|
||||||
// We must register this object to the URLSearchParams of the docshell in
|
|
||||||
// order to receive updates.
|
|
||||||
nsRefPtr<URLSearchParams> searchParams = GetDocShellSearchParams();
|
|
||||||
if (searchParams) {
|
|
||||||
searchParams->AddObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
mSearchParams = new URLSearchParams();
|
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
UpdateURLSearchParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
return mSearchParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsLocation::SetSearchParams(URLSearchParams& aSearchParams)
|
|
||||||
{
|
|
||||||
if (mSearchParams) {
|
|
||||||
mSearchParams->RemoveObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the observer will be cleared using the cycle collector.
|
|
||||||
mSearchParams = &aSearchParams;
|
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
|
|
||||||
nsAutoString search;
|
|
||||||
mSearchParams->Serialize(search);
|
|
||||||
SetSearchInternal(search);
|
|
||||||
|
|
||||||
// We don't need to inform the docShell about this new SearchParams because
|
|
||||||
// setting the new value the docShell will refresh its value automatically.
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsLocation::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mSearchParams);
|
|
||||||
|
|
||||||
// This change comes from content.
|
|
||||||
if (aSearchParams == mSearchParams) {
|
|
||||||
nsAutoString search;
|
|
||||||
mSearchParams->Serialize(search);
|
|
||||||
SetSearchInternal(search);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This change comes from the docShell.
|
|
||||||
#ifdef DEBUG
|
|
||||||
{
|
|
||||||
nsRefPtr<URLSearchParams> searchParams = GetDocShellSearchParams();
|
|
||||||
MOZ_ASSERT(searchParams);
|
|
||||||
MOZ_ASSERT(aSearchParams == searchParams);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nsAutoString search;
|
|
||||||
aSearchParams->Serialize(search);
|
|
||||||
mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(search), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsLocation::UpdateURLSearchParams()
|
|
||||||
{
|
|
||||||
if (!mSearchParams) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString search;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
nsresult rv = GetURI(getter_AddRefs(uri));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!uri)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
|
|
||||||
if (url) {
|
|
||||||
nsresult rv = url->GetQuery(search);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
NS_WARNING("Failed to get the query from a nsIURL.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mSearchParams->ParseInput(search, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nsLocation::RemoveURLSearchParams()
|
|
||||||
{
|
|
||||||
if (mSearchParams) {
|
|
||||||
mSearchParams->RemoveObserver(this);
|
|
||||||
mSearchParams = nullptr;
|
|
||||||
|
|
||||||
nsRefPtr<URLSearchParams> docShellSearchParams = GetDocShellSearchParams();
|
|
||||||
if (docShellSearchParams) {
|
|
||||||
docShellSearchParams->RemoveObserver(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/dom/URLSearchParams.h"
|
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
|
||||||
class nsIURI;
|
class nsIURI;
|
||||||
|
@ -27,7 +26,6 @@ class nsIDocShellLoadInfo;
|
||||||
|
|
||||||
class nsLocation final : public nsIDOMLocation
|
class nsLocation final : public nsIDOMLocation
|
||||||
, public nsWrapperCache
|
, public nsWrapperCache
|
||||||
, public mozilla::dom::URLSearchParamsObserver
|
|
||||||
{
|
{
|
||||||
typedef mozilla::ErrorResult ErrorResult;
|
typedef mozilla::ErrorResult ErrorResult;
|
||||||
|
|
||||||
|
@ -122,10 +120,6 @@ public:
|
||||||
aError = SetSearch(aSeach);
|
aError = SetSearch(aSeach);
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::dom::URLSearchParams* SearchParams();
|
|
||||||
|
|
||||||
void SetSearchParams(mozilla::dom::URLSearchParams& aSearchParams);
|
|
||||||
|
|
||||||
void GetHash(nsAString& aHash, ErrorResult& aError)
|
void GetHash(nsAString& aHash, ErrorResult& aError)
|
||||||
{
|
{
|
||||||
aError = GetHash(aHash);
|
aError = GetHash(aHash);
|
||||||
|
@ -144,17 +138,10 @@ public:
|
||||||
}
|
}
|
||||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
// URLSearchParamsObserver
|
|
||||||
void URLSearchParamsUpdated(mozilla::dom::URLSearchParams* aSearchParams) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsLocation();
|
virtual ~nsLocation();
|
||||||
|
|
||||||
nsresult SetSearchInternal(const nsAString& aSearch);
|
nsresult SetSearchInternal(const nsAString& aSearch);
|
||||||
void UpdateURLSearchParams();
|
|
||||||
void RemoveURLSearchParams();
|
|
||||||
|
|
||||||
mozilla::dom::URLSearchParams* GetDocShellSearchParams();
|
|
||||||
|
|
||||||
// In the case of jar: uris, we sometimes want the place the jar was
|
// In the case of jar: uris, we sometimes want the place the jar was
|
||||||
// fetched from as the URI instead of the jar: uri itself. Pass in
|
// fetched from as the URI instead of the jar: uri itself. Pass in
|
||||||
|
@ -173,9 +160,7 @@ protected:
|
||||||
|
|
||||||
nsString mCachedHash;
|
nsString mCachedHash;
|
||||||
nsCOMPtr<nsPIDOMWindow> mInnerWindow;
|
nsCOMPtr<nsPIDOMWindow> mInnerWindow;
|
||||||
nsRefPtr<mozilla::dom::URLSearchParams> mSearchParams;
|
|
||||||
nsWeakPtr mDocShell;
|
nsWeakPtr mDocShell;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsLocation_h__
|
#endif // nsLocation_h__
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=459470
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
<base href="http://example.org/">
|
<base href="http://example.org/">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body onload="startTest();">
|
||||||
<a target="_blank"
|
<a target="_blank"
|
||||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=459470">Mozilla Bug 459470</a><br />
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=459470">Mozilla Bug 459470</a><br />
|
||||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=859095">Mozilla Bug 859095</a>
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=859095">Mozilla Bug 859095</a>
|
||||||
|
@ -24,9 +24,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=459470
|
||||||
<script class="testbody" type="application/javascript;version=1.8">
|
<script class="testbody" type="application/javascript;version=1.8">
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
var gen;
|
||||||
|
|
||||||
gen = runTest();
|
function startTest() {
|
||||||
gen.next();
|
// The test uses history API, so don't do anything before load event has been
|
||||||
|
// handled.
|
||||||
|
SimpleTest.executeSoon(function() {
|
||||||
|
gen = runTest();
|
||||||
|
gen.next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function testXMLDocURI(aDoc, aExpects) {
|
function testXMLDocURI(aDoc, aExpects) {
|
||||||
is(aDoc.documentURI, aExpects.documentURI, "wrong url");
|
is(aDoc.documentURI, aExpects.documentURI, "wrong url");
|
||||||
|
|
|
@ -124,28 +124,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
|
||||||
url.searchParams.set('e', 'f');
|
url.searchParams.set('e', 'f');
|
||||||
ok(url.href.indexOf('e=f') != 1, 'URL right');
|
ok(url.href.indexOf('e=f') != 1, 'URL right');
|
||||||
|
|
||||||
var u = new URLSearchParams();
|
|
||||||
u.append('foo', 'bar');
|
|
||||||
url.searchParams = u;
|
|
||||||
is(url.searchParams, u, "URL.searchParams is the same object");
|
|
||||||
is(url.searchParams.get('foo'), 'bar', "URL.searchParams.get('foo')");
|
|
||||||
is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
|
|
||||||
|
|
||||||
try {
|
|
||||||
url.searchParams = null;
|
|
||||||
ok(false, "URLSearchParams is not nullable");
|
|
||||||
} catch(e) {
|
|
||||||
ok(true, "URLSearchParams is not nullable");
|
|
||||||
}
|
|
||||||
|
|
||||||
var url2 = new URL('http://www.example.net?e=f');
|
|
||||||
url.searchParams = url2.searchParams;
|
|
||||||
is(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
|
|
||||||
is(url.searchParams.get('e'), 'f', "URL.searchParams.get('e')");
|
|
||||||
|
|
||||||
url.href = "http://www.example.net?bar=foo";
|
|
||||||
is(url.searchParams.get('bar'), 'foo', "URL.searchParams.get('bar')");
|
|
||||||
|
|
||||||
runTest();
|
runTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,31 +138,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
|
||||||
e.searchParams.set('e', 'f');
|
e.searchParams.set('e', 'f');
|
||||||
ok(e.href.indexOf('e=f') != 1, 'e is right');
|
ok(e.href.indexOf('e=f') != 1, 'e is right');
|
||||||
|
|
||||||
var u = new URLSearchParams();
|
|
||||||
u.append('foo', 'bar');
|
|
||||||
e.searchParams = u;
|
|
||||||
is(e.searchParams, u, "e.searchParams is the same object");
|
|
||||||
is(e.searchParams.get('foo'), 'bar', "e.searchParams.get('foo')");
|
|
||||||
is(e.href, 'http://www.example.net/?foo=bar', 'e is right');
|
|
||||||
|
|
||||||
try {
|
|
||||||
e.searchParams = null;
|
|
||||||
ok(false, "URLSearchParams is not nullable");
|
|
||||||
} catch(e) {
|
|
||||||
ok(true, "URLSearchParams is not nullable");
|
|
||||||
}
|
|
||||||
|
|
||||||
var url2 = new URL('http://www.example.net?e=f');
|
|
||||||
e.searchParams = url2.searchParams;
|
|
||||||
is(e.searchParams, url2.searchParams, "e.searchParams is not the same object");
|
|
||||||
is(e.searchParams.get('e'), 'f', "e.searchParams.get('e')");
|
|
||||||
|
|
||||||
e.href = "http://www.example.net?bar=foo";
|
|
||||||
is(e.searchParams.get('bar'), 'foo', "e.searchParams.get('bar')");
|
|
||||||
|
|
||||||
e.setAttribute('href', "http://www.example.net?bar2=foo2");
|
|
||||||
is(e.searchParams.get('bar2'), 'foo2', "e.searchParams.get('bar2')");
|
|
||||||
|
|
||||||
runTest();
|
runTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,11 +148,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
|
||||||
[ '\u0541', '%D5%81'] ];
|
[ '\u0541', '%D5%81'] ];
|
||||||
|
|
||||||
for (var i = 0; i < encoding.length; ++i) {
|
for (var i = 0; i < encoding.length; ++i) {
|
||||||
var a = new URLSearchParams();
|
|
||||||
a.set('a', encoding[i][0]);
|
|
||||||
|
|
||||||
var url = new URL('http://www.example.net');
|
var url = new URL('http://www.example.net');
|
||||||
url.searchParams = a;
|
url.searchParams.set('a', encoding[i][0]);
|
||||||
is(url.href, 'http://www.example.net/?a=' + encoding[i][1]);
|
is(url.href, 'http://www.example.net/?a=' + encoding[i][1]);
|
||||||
|
|
||||||
var url2 = new URL(url.href);
|
var url2 = new URL(url.href);
|
||||||
|
@ -209,45 +159,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
|
||||||
runTest();
|
runTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testMultiURL() {
|
|
||||||
var a = new URL('http://www.example.net?a=b&c=d');
|
|
||||||
var b = new URL('http://www.example.net?e=f');
|
|
||||||
var c = document.createElement('a');
|
|
||||||
var d = document.createElement('area');
|
|
||||||
ok(a.searchParams.has('a'), "a.searchParams.has('a')");
|
|
||||||
ok(a.searchParams.has('c'), "a.searchParams.has('c')");
|
|
||||||
ok(b.searchParams.has('e'), "b.searchParams.has('e')");
|
|
||||||
ok(c.searchParams, "c.searchParams");
|
|
||||||
ok(d.searchParams, "d.searchParams");
|
|
||||||
|
|
||||||
var u = new URLSearchParams();
|
|
||||||
a.searchParams = b.searchParams = c.searchParams = d.searchParams = u;
|
|
||||||
is(a.searchParams, u, "a.searchParams === u");
|
|
||||||
is(b.searchParams, u, "b.searchParams === u");
|
|
||||||
is(c.searchParams, u, "c.searchParams === u");
|
|
||||||
is(d.searchParams, u, "d.searchParams === u");
|
|
||||||
ok(!a.searchParams.has('a'), "!a.searchParams.has('a')");
|
|
||||||
ok(!a.searchParams.has('c'), "!a.searchParams.has('c')");
|
|
||||||
ok(!b.searchParams.has('e'), "!b.searchParams.has('e')");
|
|
||||||
|
|
||||||
u.append('foo', 'bar');
|
|
||||||
is(a.searchParams.get('foo'), 'bar', "a has foo=bar");
|
|
||||||
is(b.searchParams.get('foo'), 'bar', "b has foo=bar");
|
|
||||||
is(c.searchParams.get('foo'), 'bar', "c has foo=bar");
|
|
||||||
is(d.searchParams.get('foo'), 'bar', "d has foo=bar");
|
|
||||||
is(a + "", b + "", "stringify a == b");
|
|
||||||
is(c.searchParams + "", b.searchParams + "", "stringify c.searchParams == b.searchParams");
|
|
||||||
is(d.searchParams + "", b.searchParams + "", "stringify d.searchParams == b.searchParams");
|
|
||||||
|
|
||||||
a.search = "?bar=foo";
|
|
||||||
is(a.searchParams.get('bar'), 'foo', "a has bar=foo");
|
|
||||||
is(b.searchParams.get('bar'), 'foo', "b has bar=foo");
|
|
||||||
is(c.searchParams.get('bar'), 'foo', "c has bar=foo");
|
|
||||||
is(d.searchParams.get('bar'), 'foo', "d has bar=foo");
|
|
||||||
|
|
||||||
runTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
function testOrdering() {
|
function testOrdering() {
|
||||||
var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
|
var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
|
||||||
is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
|
is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
|
||||||
|
@ -334,7 +245,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
|
||||||
function() { testElement(document.getElementById('anchor')) },
|
function() { testElement(document.getElementById('anchor')) },
|
||||||
function() { testElement(document.getElementById('area')) },
|
function() { testElement(document.getElementById('area')) },
|
||||||
testEncoding,
|
testEncoding,
|
||||||
testMultiURL,
|
|
||||||
testOrdering,
|
testOrdering,
|
||||||
testDelete,
|
testDelete,
|
||||||
testGetNULL,
|
testGetNULL,
|
||||||
|
|
|
@ -181,12 +181,12 @@ DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::
|
||||||
return result.succeed();
|
return result.succeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* expando = EnsureExpandoObject(cx, proxy);
|
JS::Rooted<JSObject*> expando(cx, EnsureExpandoObject(cx, proxy));
|
||||||
if (!expando) {
|
if (!expando) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!js::DefineOwnProperty(cx, expando, id, desc, result)) {
|
if (!JS_DefinePropertyById(cx, expando, id, desc, result)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*defined = true;
|
*defined = true;
|
||||||
|
|
|
@ -190,6 +190,48 @@ private:
|
||||||
TypedArray(const TypedArray&) = delete;
|
TypedArray(const TypedArray&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<JSObject* UnwrapArray(JSObject*),
|
||||||
|
void GetLengthAndData(JSObject*, uint32_t*, uint8_t**),
|
||||||
|
js::Scalar::Type GetViewType(JSObject*)>
|
||||||
|
struct ArrayBufferView_base : public TypedArray_base<uint8_t, UnwrapArray,
|
||||||
|
GetLengthAndData> {
|
||||||
|
private:
|
||||||
|
typedef TypedArray_base<uint8_t, UnwrapArray, GetLengthAndData> Base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ArrayBufferView_base()
|
||||||
|
: Base()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ArrayBufferView_base(ArrayBufferView_base&& aOther)
|
||||||
|
: Base(Move(aOther)),
|
||||||
|
mType(aOther.mType)
|
||||||
|
{
|
||||||
|
aOther.mType = js::Scalar::MaxTypedArrayViewType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
js::Scalar::Type mType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline bool Init(JSObject* obj)
|
||||||
|
{
|
||||||
|
if (!Base::Init(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mType = GetViewType(this->Obj());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline js::Scalar::Type Type() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(this->inited());
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
typedef TypedArray<int8_t, js::UnwrapInt8Array, JS_GetInt8ArrayData,
|
typedef TypedArray<int8_t, js::UnwrapInt8Array, JS_GetInt8ArrayData,
|
||||||
js::GetInt8ArrayLengthAndData, JS_NewInt8Array>
|
js::GetInt8ArrayLengthAndData, JS_NewInt8Array>
|
||||||
Int8Array;
|
Int8Array;
|
||||||
|
@ -217,7 +259,9 @@ typedef TypedArray<float, js::UnwrapFloat32Array, JS_GetFloat32ArrayData,
|
||||||
typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData,
|
typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData,
|
||||||
js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array>
|
js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array>
|
||||||
Float64Array;
|
Float64Array;
|
||||||
typedef TypedArray_base<uint8_t, js::UnwrapArrayBufferView, js::GetArrayBufferViewLengthAndData>
|
typedef ArrayBufferView_base<js::UnwrapArrayBufferView,
|
||||||
|
js::GetArrayBufferViewLengthAndData,
|
||||||
|
JS_GetArrayBufferViewType>
|
||||||
ArrayBufferView;
|
ArrayBufferView;
|
||||||
typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
|
typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
|
||||||
js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
|
js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
|
||||||
|
@ -250,7 +294,9 @@ typedef TypedArray<float, js::UnwrapSharedFloat32Array, JS_GetSharedFloat32Array
|
||||||
typedef TypedArray<double, js::UnwrapSharedFloat64Array, JS_GetSharedFloat64ArrayData,
|
typedef TypedArray<double, js::UnwrapSharedFloat64Array, JS_GetSharedFloat64ArrayData,
|
||||||
js::GetSharedFloat64ArrayLengthAndData, JS_NewSharedFloat64Array>
|
js::GetSharedFloat64ArrayLengthAndData, JS_NewSharedFloat64Array>
|
||||||
SharedFloat64Array;
|
SharedFloat64Array;
|
||||||
typedef TypedArray_base<uint8_t, js::UnwrapSharedArrayBufferView, js::GetSharedArrayBufferViewLengthAndData>
|
typedef ArrayBufferView_base<js::UnwrapSharedArrayBufferView,
|
||||||
|
js::GetSharedArrayBufferViewLengthAndData,
|
||||||
|
JS_GetSharedArrayBufferViewType>
|
||||||
SharedArrayBufferView;
|
SharedArrayBufferView;
|
||||||
typedef TypedArray<uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBufferData,
|
typedef TypedArray<uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBufferData,
|
||||||
js::GetSharedArrayBufferLengthAndData, JS_NewSharedArrayBuffer>
|
js::GetSharedArrayBufferLengthAndData, JS_NewSharedArrayBuffer>
|
||||||
|
|
|
@ -224,7 +224,7 @@ WebGL2Context::TexImage3D(GLenum target, GLint level, GLenum internalformat,
|
||||||
|
|
||||||
data = view.Data();
|
data = view.Data();
|
||||||
dataLength = view.Length();
|
dataLength = view.Length();
|
||||||
jsArrayType = JS_GetArrayBufferViewType(view.Obj());
|
jsArrayType = view.Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
|
const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
|
||||||
|
@ -367,7 +367,7 @@ WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
|
||||||
return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
|
return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
|
||||||
}
|
}
|
||||||
|
|
||||||
js::Scalar::Type jsArrayType = JS_GetArrayBufferViewType(view.Obj());
|
js::Scalar::Type jsArrayType = view.Type();
|
||||||
void* data = view.Data();
|
void* data = view.Data();
|
||||||
size_t dataLength = view.Length();
|
size_t dataLength = view.Length();
|
||||||
|
|
||||||
|
|
|
@ -2033,7 +2033,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArrayBufferView& pixbuf = pixels.Value();
|
const ArrayBufferView& pixbuf = pixels.Value();
|
||||||
int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
|
int dataType = pixbuf.Type();
|
||||||
|
|
||||||
// Check the pixels param type
|
// Check the pixels param type
|
||||||
if (dataType != requiredDataType)
|
if (dataType != requiredDataType)
|
||||||
|
@ -3411,7 +3411,7 @@ WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
|
||||||
|
|
||||||
data = view.Data();
|
data = view.Data();
|
||||||
length = view.Length();
|
length = view.Length();
|
||||||
jsArrayType = JS_GetArrayBufferViewType(view.Obj());
|
jsArrayType = view.Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
|
if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
|
||||||
|
@ -3610,8 +3610,7 @@ WebGLContext::TexSubImage2D(GLenum rawTarget, GLint level,
|
||||||
|
|
||||||
return TexSubImage2D_base(rawTarget, level, xoffset, yoffset,
|
return TexSubImage2D_base(rawTarget, level, xoffset, yoffset,
|
||||||
width, height, 0, format, type,
|
width, height, 0, format, type,
|
||||||
view.Data(), view.Length(),
|
view.Data(), view.Length(), view.Type(),
|
||||||
JS_GetArrayBufferViewType(view.Obj()),
|
|
||||||
WebGLTexelFormat::Auto, false);
|
WebGLTexelFormat::Auto, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1600,8 +1600,8 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValidUrlEncodedMimeType) {
|
if (isValidUrlEncodedMimeType) {
|
||||||
nsRefPtr<URLSearchParams> params = new URLSearchParams();
|
nsRefPtr<URLSearchParams> params = new URLSearchParams(nullptr);
|
||||||
params->ParseInput(data, /* aObserver */ nullptr);
|
params->ParseInput(data);
|
||||||
|
|
||||||
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
|
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
|
||||||
FillFormIterator iterator(fd);
|
FillFormIterator iterator(fd);
|
||||||
|
|
|
@ -158,7 +158,6 @@ public:
|
||||||
using Link::SetHash;
|
using Link::SetHash;
|
||||||
|
|
||||||
// The Link::GetSearchParams is OK for us
|
// The Link::GetSearchParams is OK for us
|
||||||
// The Link::SetSearchParams is OK for us
|
|
||||||
|
|
||||||
bool NoHref() const
|
bool NoHref() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
|
||||||
void unregisterFailed();
|
void unregisterFailed();
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(103763c8-53ba-42e4-8b26-e601d5bc4afe)]
|
[scriptable, builtinclass, uuid(e633b73b-a734-4d04-a09c-b7779a439f3f)]
|
||||||
interface nsIServiceWorkerInfo : nsISupports
|
interface nsIServiceWorkerInfo : nsISupports
|
||||||
{
|
{
|
||||||
readonly attribute nsIPrincipal principal;
|
readonly attribute nsIPrincipal principal;
|
||||||
|
@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||||
readonly attribute DOMString waitingCacheName;
|
readonly attribute DOMString waitingCacheName;
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(aee94712-9adb-4c0b-80a7-a8df34dfa2e8)]
|
[scriptable, builtinclass, uuid(e9abb123-0099-4d9e-85db-c8cd0aff19e6)]
|
||||||
interface nsIServiceWorkerManager : nsISupports
|
interface nsIServiceWorkerManager : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -126,11 +126,11 @@ interface nsIServiceWorkerManager : nsISupports
|
||||||
in nsIServiceWorkerUnregisterCallback aCallback,
|
in nsIServiceWorkerUnregisterCallback aCallback,
|
||||||
in DOMString aScope);
|
in DOMString aScope);
|
||||||
|
|
||||||
[implicit_jscontext] void sendPushEvent(in jsval aOriginAttributes,
|
void sendPushEvent(in ACString aOriginAttributes,
|
||||||
in ACString aScope,
|
in ACString aScope,
|
||||||
in DOMString aData);
|
in DOMString aData);
|
||||||
[implicit_jscontext] void sendPushSubscriptionChangeEvent(in jsval aOriginAttributes,
|
void sendPushSubscriptionChangeEvent(in ACString aOriginAttributes,
|
||||||
in ACString scope);
|
in ACString scope);
|
||||||
|
|
||||||
void updateAllRegistrations();
|
void updateAllRegistrations();
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* uses service workers to notify applications. This interface exists to allow
|
* uses service workers to notify applications. This interface exists to allow
|
||||||
* privileged code to receive messages without migrating to service workers.
|
* privileged code to receive messages without migrating to service workers.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(3da6a16c-69f8-4843-9149-1e89d58a53e2)]
|
[scriptable, uuid(abde228b-7d14-4cab-b1f9-9f87750ede0f)]
|
||||||
interface nsIPushNotificationService : nsISupports
|
interface nsIPushNotificationService : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -32,20 +32,20 @@ interface nsIPushNotificationService : nsISupports
|
||||||
* Servers may drop subscriptions at any time, so callers should recreate
|
* Servers may drop subscriptions at any time, so callers should recreate
|
||||||
* subscriptions if desired.
|
* subscriptions if desired.
|
||||||
*/
|
*/
|
||||||
jsval register(in string scope, [optional] in string pageURL);
|
jsval register(in string scope, in jsval originAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revokes a push subscription for the given |scope|. Returns a promise
|
* Revokes a push subscription for the given |scope|. Returns a promise
|
||||||
* for the revoked subscription record, or `null` if the |scope| is not
|
* for the revoked subscription record, or `null` if the |scope| is not
|
||||||
* subscribed to receive notifications.
|
* subscribed to receive notifications.
|
||||||
*/
|
*/
|
||||||
jsval unregister(in string scope);
|
jsval unregister(in string scope, in jsval originAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise for the subscription record associated with the
|
* Returns a promise for the subscription record associated with the
|
||||||
* given |scope|, or `null` if the |scope| does not have a subscription.
|
* given |scope|, or `null` if the |scope| does not have a subscription.
|
||||||
*/
|
*/
|
||||||
jsval registration(in string scope);
|
jsval registration(in string scope, in jsval originAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all subscriptions
|
* Clear all subscriptions
|
||||||
|
|
|
@ -2627,33 +2627,51 @@ ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, true);
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
|
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
|
||||||
const IPCDataTransferImage& imageDetails = item.imageDetails();
|
if (item.flavor().EqualsLiteral(kJPEGImageMime) ||
|
||||||
const gfxIntSize size(imageDetails.width(), imageDetails.height());
|
item.flavor().EqualsLiteral(kJPGImageMime) ||
|
||||||
if (!size.width || !size.height) {
|
item.flavor().EqualsLiteral(kPNGImageMime) ||
|
||||||
return true;
|
item.flavor().EqualsLiteral(kGIFImageMime)) {
|
||||||
|
const IPCDataTransferImage& imageDetails = item.imageDetails();
|
||||||
|
const gfxIntSize size(imageDetails.width(), imageDetails.height());
|
||||||
|
if (!size.width || !size.height) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString text = item.data().get_nsCString();
|
||||||
|
mozilla::RefPtr<gfx::DataSourceSurface> image =
|
||||||
|
new mozilla::gfx::SourceSurfaceRawData();
|
||||||
|
mozilla::gfx::SourceSurfaceRawData* raw =
|
||||||
|
static_cast<mozilla::gfx::SourceSurfaceRawData*>(image.get());
|
||||||
|
raw->InitWrappingData(
|
||||||
|
reinterpret_cast<uint8_t*>(const_cast<nsCString&>(text).BeginWriting()),
|
||||||
|
size, imageDetails.stride(),
|
||||||
|
static_cast<mozilla::gfx::SurfaceFormat>(imageDetails.format()), false);
|
||||||
|
raw->GuaranteePersistance();
|
||||||
|
|
||||||
|
nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size);
|
||||||
|
nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable));
|
||||||
|
|
||||||
|
nsCOMPtr<nsISupportsInterfacePointer>
|
||||||
|
imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
|
||||||
|
|
||||||
|
rv = imgPtr->SetData(imageContainer);
|
||||||
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
|
|
||||||
|
trans->SetTransferData(item.flavor().get(), imgPtr, sizeof(nsISupports*));
|
||||||
|
} else {
|
||||||
|
nsCOMPtr<nsISupportsCString> dataWrapper =
|
||||||
|
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
|
|
||||||
|
const nsCString& text = item.data().get_nsCString();
|
||||||
|
rv = dataWrapper->SetData(text);
|
||||||
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
|
|
||||||
|
rv = trans->SetTransferData(item.flavor().get(), dataWrapper,
|
||||||
|
text.Length());
|
||||||
|
|
||||||
|
NS_ENSURE_SUCCESS(rv, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCString text = item.data().get_nsCString();
|
|
||||||
mozilla::RefPtr<gfx::DataSourceSurface> image =
|
|
||||||
new mozilla::gfx::SourceSurfaceRawData();
|
|
||||||
mozilla::gfx::SourceSurfaceRawData* raw =
|
|
||||||
static_cast<mozilla::gfx::SourceSurfaceRawData*>(image.get());
|
|
||||||
raw->InitWrappingData(
|
|
||||||
reinterpret_cast<uint8_t*>(const_cast<nsCString&>(text).BeginWriting()),
|
|
||||||
size, imageDetails.stride(),
|
|
||||||
static_cast<mozilla::gfx::SurfaceFormat>(imageDetails.format()), false);
|
|
||||||
raw->GuaranteePersistance();
|
|
||||||
|
|
||||||
nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size);
|
|
||||||
nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable));
|
|
||||||
|
|
||||||
nsCOMPtr<nsISupportsInterfacePointer>
|
|
||||||
imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
|
|
||||||
|
|
||||||
rv = imgPtr->SetData(imageContainer);
|
|
||||||
NS_ENSURE_SUCCESS(rv, true);
|
|
||||||
|
|
||||||
trans->SetTransferData(item.flavor().get(), imgPtr, sizeof(nsISupports*));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,10 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
||||||
[test_peerConnection_captureStream_canvas_webgl.html]
|
[test_peerConnection_captureStream_canvas_webgl.html]
|
||||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||||
[test_peerConnection_close.html]
|
[test_peerConnection_close.html]
|
||||||
|
[test_peerConnection_closeDuringIce.html]
|
||||||
[test_peerConnection_errorCallbacks.html]
|
[test_peerConnection_errorCallbacks.html]
|
||||||
|
[test_peerConnection_iceFailure.html]
|
||||||
|
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Disabling because of test failures on B2G emulator
|
||||||
[test_peerConnection_forwarding_basicAudioVideoCombined.html]
|
[test_peerConnection_forwarding_basicAudioVideoCombined.html]
|
||||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||||
[test_peerConnection_noTrickleAnswer.html]
|
[test_peerConnection_noTrickleAnswer.html]
|
||||||
|
|
|
@ -405,7 +405,7 @@ var commandsPeerConnectionOfferAnswer = [
|
||||||
},
|
},
|
||||||
|
|
||||||
function PC_LOCAL_SET_REMOTE_DESCRIPTION(test) {
|
function PC_LOCAL_SET_REMOTE_DESCRIPTION(test) {
|
||||||
test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE)
|
return test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
is(test.pcLocal.signalingState, STABLE,
|
is(test.pcLocal.signalingState, STABLE,
|
||||||
"signalingState after local setRemoteDescription is 'stable'");
|
"signalingState after local setRemoteDescription is 'stable'");
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="application/javascript" src="pc.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript">
|
||||||
|
createHTML({
|
||||||
|
bug: "1087629",
|
||||||
|
title: "Close PCs during ICE connectivity check"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test closeDuringIce to simulate problems during peer connections
|
||||||
|
|
||||||
|
|
||||||
|
function PC_LOCAL_SETUP_NULL_ICE_HANDLER(test) {
|
||||||
|
test.pcLocal.setupIceCandidateHandler(test, function() {}, function () {});
|
||||||
|
}
|
||||||
|
function PC_REMOTE_SETUP_NULL_ICE_HANDLER(test) {
|
||||||
|
test.pcRemote.setupIceCandidateHandler(test, function() {}, function () {});
|
||||||
|
}
|
||||||
|
function PC_REMOTE_ADD_FAKE_ICE_CANDIDATE(test) {
|
||||||
|
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.1 12345 typ host","sdpMid":"","sdpMLineIndex":0});
|
||||||
|
test.pcRemote.storeOrAddIceCandidate(cand);
|
||||||
|
info(test.pcRemote + " Stored fake candidate: " + JSON.stringify(cand));
|
||||||
|
}
|
||||||
|
function PC_LOCAL_ADD_FAKE_ICE_CANDIDATE(test) {
|
||||||
|
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.2 56789 typ host","sdpMid":"","sdpMLineIndex":0});
|
||||||
|
test.pcLocal.storeOrAddIceCandidate(cand);
|
||||||
|
info(test.pcLocal + " Stored fake candidate: " + JSON.stringify(cand));
|
||||||
|
}
|
||||||
|
function PC_LOCAL_CLOSE_DURING_ICE(test) {
|
||||||
|
return test.pcLocal.iceChecking.then(() => {
|
||||||
|
test.pcLocal.onsignalingstatechange = function () {};
|
||||||
|
test.pcLocal.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function PC_REMOTE_CLOSE_DURING_ICE(test) {
|
||||||
|
return test.pcRemote.iceChecking.then(() => {
|
||||||
|
test.pcRemote.onsignalingstatechange = function () {};
|
||||||
|
test.pcRemote.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function PC_LOCAL_WAIT_FOR_ICE_CHECKING(test) {
|
||||||
|
var resolveIceChecking;
|
||||||
|
test.pcLocal.iceChecking = new Promise(r => resolveIceChecking = r);
|
||||||
|
test.pcLocal.ice_connection_callbacks.checkIceStatus = () => {
|
||||||
|
if (test.pcLocal._pc.iceConnectionState === "checking") {
|
||||||
|
resolveIceChecking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function PC_REMOTE_WAIT_FOR_ICE_CHECKING(test) {
|
||||||
|
var resolveIceChecking;
|
||||||
|
test.pcRemote.iceChecking = new Promise(r => resolveIceChecking = r);
|
||||||
|
test.pcRemote.ice_connection_callbacks.checkIceStatus = () => {
|
||||||
|
if (test.pcRemote._pc.iceConnectionState === "checking") {
|
||||||
|
resolveIceChecking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runNetworkTest(() => {
|
||||||
|
var test = new PeerConnectionTest();
|
||||||
|
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||||
|
test.chain.replace("PC_LOCAL_SETUP_ICE_HANDLER", PC_LOCAL_SETUP_NULL_ICE_HANDLER);
|
||||||
|
test.chain.replace("PC_REMOTE_SETUP_ICE_HANDLER", PC_REMOTE_SETUP_NULL_ICE_HANDLER);
|
||||||
|
test.chain.insertAfter("PC_REMOTE_SETUP_NULL_ICE_HANDLER", PC_LOCAL_WAIT_FOR_ICE_CHECKING);
|
||||||
|
test.chain.insertAfter("PC_LOCAL_WAIT_FOR_ICE_CHECKING", PC_REMOTE_WAIT_FOR_ICE_CHECKING);
|
||||||
|
test.chain.removeAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION");
|
||||||
|
test.chain.append([PC_REMOTE_ADD_FAKE_ICE_CANDIDATE, PC_LOCAL_ADD_FAKE_ICE_CANDIDATE,
|
||||||
|
PC_LOCAL_CLOSE_DURING_ICE, PC_REMOTE_CLOSE_DURING_ICE]);
|
||||||
|
test.run();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,83 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="application/javascript" src="pc.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript">
|
||||||
|
createHTML({
|
||||||
|
bug: "1087629",
|
||||||
|
title: "Wait for ICE failure"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test iceFailure
|
||||||
|
|
||||||
|
function PC_LOCAL_SETUP_NULL_ICE_HANDLER(test) {
|
||||||
|
test.pcLocal.setupIceCandidateHandler(test, function() {}, function () {});
|
||||||
|
}
|
||||||
|
function PC_REMOTE_SETUP_NULL_ICE_HANDLER(test) {
|
||||||
|
test.pcRemote.setupIceCandidateHandler(test, function() {}, function () {});
|
||||||
|
}
|
||||||
|
function PC_REMOTE_ADD_FAKE_ICE_CANDIDATE(test) {
|
||||||
|
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.1 12345 typ host","sdpMid":"","sdpMLineIndex":0});
|
||||||
|
test.pcRemote.storeOrAddIceCandidate(cand);
|
||||||
|
info(test.pcRemote + " Stored fake candidate: " + JSON.stringify(cand));
|
||||||
|
}
|
||||||
|
function PC_LOCAL_ADD_FAKE_ICE_CANDIDATE(test) {
|
||||||
|
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.2 56789 typ host","sdpMid":"","sdpMLineIndex":0});
|
||||||
|
test.pcLocal.storeOrAddIceCandidate(cand);
|
||||||
|
info(test.pcLocal + " Stored fake candidate: " + JSON.stringify(cand));
|
||||||
|
}
|
||||||
|
function PC_LOCAL_WAIT_FOR_ICE_FAILURE(test) {
|
||||||
|
return test.pcLocal.iceFailed.then(() => {
|
||||||
|
ok(true, this.pcLocal + " Ice Failure Reached.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function PC_REMOTE_WAIT_FOR_ICE_FAILURE(test) {
|
||||||
|
return test.pcRemote.iceFailed.then(() => {
|
||||||
|
ok(true, this.pcRemote + " Ice Failure Reached.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function PC_LOCAL_WAIT_FOR_ICE_FAILED(test) {
|
||||||
|
var resolveIceFailed;
|
||||||
|
test.pcLocal.iceFailed = new Promise(r => resolveIceFailed = r);
|
||||||
|
test.pcLocal.ice_connection_callbacks.checkIceStatus = () => {
|
||||||
|
if (test.pcLocal._pc.iceConnectionState === "failed") {
|
||||||
|
resolveIceFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function PC_REMOTE_WAIT_FOR_ICE_FAILED(test) {
|
||||||
|
var resolveIceFailed;
|
||||||
|
test.pcRemote.iceFailed = new Promise(r => resolveIceFailed = r);
|
||||||
|
test.pcRemote.ice_connection_callbacks.checkIceStatus = () => {
|
||||||
|
if (test.pcRemote._pc.iceConnectionState === "failed") {
|
||||||
|
resolveIceFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runNetworkTest(() => {
|
||||||
|
SpecialPowers.pushPrefEnv({
|
||||||
|
'set': [
|
||||||
|
['media.peerconnection.ice.stun_client_maximum_transmits', 3],
|
||||||
|
['media.peerconnection.ice.trickle_grace_period', 3000],
|
||||||
|
]
|
||||||
|
}, function() {
|
||||||
|
var test = new PeerConnectionTest();
|
||||||
|
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||||
|
test.chain.replace("PC_LOCAL_SETUP_ICE_HANDLER", PC_LOCAL_SETUP_NULL_ICE_HANDLER);
|
||||||
|
test.chain.replace("PC_REMOTE_SETUP_ICE_HANDLER", PC_REMOTE_SETUP_NULL_ICE_HANDLER);
|
||||||
|
test.chain.insertAfter("PC_REMOTE_SETUP_NULL_ICE_HANDLER", PC_LOCAL_WAIT_FOR_ICE_FAILED);
|
||||||
|
test.chain.insertAfter("PC_LOCAL_WAIT_FOR_ICE_FAILED", PC_REMOTE_WAIT_FOR_ICE_FAILED);
|
||||||
|
test.chain.removeAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION");
|
||||||
|
test.chain.append([PC_REMOTE_ADD_FAKE_ICE_CANDIDATE, PC_LOCAL_ADD_FAKE_ICE_CANDIDATE,
|
||||||
|
PC_LOCAL_WAIT_FOR_ICE_FAILURE, PC_REMOTE_WAIT_FOR_ICE_FAILURE]);
|
||||||
|
test.run();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -21,6 +21,7 @@
|
||||||
#include "mozilla/dom/WorkerScope.h"
|
#include "mozilla/dom/WorkerScope.h"
|
||||||
#include "mozilla/ipc/BackgroundChild.h"
|
#include "mozilla/ipc/BackgroundChild.h"
|
||||||
#include "mozilla/ipc/PBackgroundChild.h"
|
#include "mozilla/ipc/PBackgroundChild.h"
|
||||||
|
#include "mozilla/unused.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
|
@ -249,6 +250,50 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ForceCloseHelper final : public nsIIPCBackgroundChildCreateCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
static void ForceClose(const MessagePortIdentifier& aIdentifier)
|
||||||
|
{
|
||||||
|
PBackgroundChild* actor =
|
||||||
|
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||||
|
if (actor) {
|
||||||
|
unused << actor->SendMessagePortForceClose(aIdentifier.uuid(),
|
||||||
|
aIdentifier.destinationUuid(),
|
||||||
|
aIdentifier.sequenceId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<ForceCloseHelper> helper = new ForceCloseHelper(aIdentifier);
|
||||||
|
if (NS_WARN_IF(!mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(helper))) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit ForceCloseHelper(const MessagePortIdentifier& aIdentifier)
|
||||||
|
: mIdentifier(aIdentifier)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~ForceCloseHelper() {}
|
||||||
|
|
||||||
|
void ActorFailed() override
|
||||||
|
{
|
||||||
|
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorCreated(mozilla::ipc::PBackgroundChild* aActor) override
|
||||||
|
{
|
||||||
|
ForceClose(mIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MessagePortIdentifier mIdentifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
|
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
|
||||||
|
@ -863,5 +908,11 @@ MessagePort::RemoveDocFromBFCache()
|
||||||
bfCacheEntry->RemoveFromBFCacheSync();
|
bfCacheEntry->RemoveFromBFCacheSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
MessagePort::ForceClose(const MessagePortIdentifier& aIdentifier)
|
||||||
|
{
|
||||||
|
ForceCloseHelper::ForceClose(aIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -86,6 +86,9 @@ public:
|
||||||
Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier,
|
Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
static void
|
||||||
|
ForceClose(const MessagePortIdentifier& aIdentifier);
|
||||||
|
|
||||||
virtual JSObject*
|
virtual JSObject*
|
||||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
|
|
|
@ -159,5 +159,19 @@ MessagePortParent::Close()
|
||||||
mEntangled = false;
|
mEntangled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
MessagePortParent::ForceClose(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
MessagePortService* service = MessagePortService::Get();
|
||||||
|
if (!service) {
|
||||||
|
NS_WARNING("The service must exist if we want to close an existing MessagePort.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return service->ForceClose(aUUID, aDestinationUUID, aSequenceID);
|
||||||
|
}
|
||||||
|
|
||||||
} // dom namespace
|
} // dom namespace
|
||||||
} // mozilla namespace
|
} // mozilla namespace
|
||||||
|
|
|
@ -36,6 +36,10 @@ public:
|
||||||
return mUUID;
|
return mUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ForceClose(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool RecvPostMessages(nsTArray<MessagePortMessage>&& aMessages)
|
virtual bool RecvPostMessages(nsTArray<MessagePortMessage>&& aMessages)
|
||||||
override;
|
override;
|
||||||
|
|
|
@ -6,16 +6,27 @@
|
||||||
#include "MessagePortService.h"
|
#include "MessagePortService.h"
|
||||||
#include "MessagePortParent.h"
|
#include "MessagePortParent.h"
|
||||||
#include "SharedMessagePortMessage.h"
|
#include "SharedMessagePortMessage.h"
|
||||||
|
#include "mozilla/ipc/BackgroundParent.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
using mozilla::ipc::AssertIsOnBackgroundThread;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
StaticRefPtr<MessagePortService> gInstance;
|
StaticRefPtr<MessagePortService> gInstance;
|
||||||
|
|
||||||
|
void
|
||||||
|
AssertIsInMainProcess()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
class MessagePortService::MessagePortServiceData final
|
class MessagePortService::MessagePortServiceData final
|
||||||
|
@ -53,9 +64,21 @@ public:
|
||||||
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> mMessages;
|
FallibleTArray<nsRefPtr<SharedMessagePortMessage>> mMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* static */ MessagePortService*
|
||||||
|
MessagePortService::Get()
|
||||||
|
{
|
||||||
|
AssertIsInMainProcess();
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
return gInstance;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ MessagePortService*
|
/* static */ MessagePortService*
|
||||||
MessagePortService::GetOrCreate()
|
MessagePortService::GetOrCreate()
|
||||||
{
|
{
|
||||||
|
AssertIsInMainProcess();
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
if (!gInstance) {
|
if (!gInstance) {
|
||||||
gInstance = new MessagePortService();
|
gInstance = new MessagePortService();
|
||||||
}
|
}
|
||||||
|
@ -248,6 +271,12 @@ MessagePortService::CloseAll(const nsID& aUUID)
|
||||||
|
|
||||||
CloseAll(destinationUUID);
|
CloseAll(destinationUUID);
|
||||||
|
|
||||||
|
// CloseAll calls itself recursively and it can happen that it deletes
|
||||||
|
// itself. Before continuing we must check if we are still alive.
|
||||||
|
if (!gInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
mPorts.EnumerateRead(CloseAllDebugCheck, const_cast<nsID*>(&aUUID));
|
mPorts.EnumerateRead(CloseAllDebugCheck, const_cast<nsID*>(&aUUID));
|
||||||
#endif
|
#endif
|
||||||
|
@ -324,5 +353,26 @@ MessagePortService::ParentDestroy(MessagePortParent* aParent)
|
||||||
CloseAll(aParent->ID());
|
CloseAll(aParent->ID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MessagePortService::ForceClose(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
MessagePortServiceData* data;
|
||||||
|
if (!mPorts.Get(aUUID, &data)) {
|
||||||
|
NS_WARNING("Unknown MessagePort in ForceClose()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data->mDestinationUUID.Equals(aDestinationUUID) ||
|
||||||
|
data->mSequenceID != aSequenceID) {
|
||||||
|
NS_WARNING("DestinationUUID and/or sequenceID do not match.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAll(aUUID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // dom namespace
|
} // dom namespace
|
||||||
} // mozilla namespace
|
} // mozilla namespace
|
||||||
|
|
|
@ -20,6 +20,7 @@ class MessagePortService final
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_REFCOUNTING(MessagePortService)
|
NS_INLINE_DECL_REFCOUNTING(MessagePortService)
|
||||||
|
|
||||||
|
static MessagePortService* Get();
|
||||||
static MessagePortService* GetOrCreate();
|
static MessagePortService* GetOrCreate();
|
||||||
|
|
||||||
bool RequestEntangling(MessagePortParent* aParent,
|
bool RequestEntangling(MessagePortParent* aParent,
|
||||||
|
@ -38,6 +39,10 @@ public:
|
||||||
|
|
||||||
void ParentDestroy(MessagePortParent* aParent);
|
void ParentDestroy(MessagePortParent* aParent);
|
||||||
|
|
||||||
|
bool ForceClose(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~MessagePortService() {}
|
~MessagePortService() {}
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
ErrorResult rv;
|
ErrorResult rv;
|
||||||
nsRefPtr<MessagePort> port =
|
nsRefPtr<MessagePort> port =
|
||||||
MessagePort::Create(closure->mWindow,
|
MessagePort::Create(closure->mWindow,
|
||||||
closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData],
|
closure->mClosure.mMessagePortIdentifiers[aExtraData],
|
||||||
rv);
|
rv);
|
||||||
if (NS_WARN_IF(rv.Failed())) {
|
if (NS_WARN_IF(rv.Failed())) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -195,13 +195,27 @@ WriteTransfer(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
||||||
|
void* aContent, uint64_t aExtraData, void* aClosure)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
auto* closure = static_cast<StructuredCloneClosureInternal*>(aClosure);
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||||
|
MOZ_ASSERT(!aContent);
|
||||||
|
MOZ_ASSERT(aExtraData < closure->mClosure.mMessagePortIdentifiers.Length());
|
||||||
|
MessagePort::ForceClose(closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const JSStructuredCloneCallbacks gCallbacks = {
|
const JSStructuredCloneCallbacks gCallbacks = {
|
||||||
Read,
|
Read,
|
||||||
Write,
|
Write,
|
||||||
Error,
|
Error,
|
||||||
ReadTransfer,
|
ReadTransfer,
|
||||||
WriteTransfer,
|
WriteTransfer,
|
||||||
nullptr
|
FreeTransfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -23,3 +23,4 @@ support-files =
|
||||||
[test_messageChannel_sharedWorker.html]
|
[test_messageChannel_sharedWorker.html]
|
||||||
[test_messageChannel_sharedWorker2.html]
|
[test_messageChannel_sharedWorker2.html]
|
||||||
[test_messageChannel_any.html]
|
[test_messageChannel_any.html]
|
||||||
|
[test_messageChannel_forceClose.html]
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1176034
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1176034 - start/close</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1176034">Mozilla Bug 1176034</a>
|
||||||
|
<div id="content"></div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function runTests() {
|
||||||
|
var mc = new MessageChannel();
|
||||||
|
|
||||||
|
try {
|
||||||
|
postMessage(42, "*", [ mc.port1, window ]);
|
||||||
|
ok(false, "Something went wrong.");
|
||||||
|
} catch(e) {
|
||||||
|
ok(true, "PostMessage should fail and we should not leak.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -23,11 +23,11 @@ Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||||
|
|
||||||
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
|
const PUSH_SUBSCRIPTION_CID = Components.ID("{CA86B665-BEDA-4212-8D0F-5C9F65270B58}");
|
||||||
|
|
||||||
function PushSubscription(pushEndpoint, scope, pageURL) {
|
function PushSubscription(pushEndpoint, scope, principal) {
|
||||||
debug("PushSubscription Constructor");
|
debug("PushSubscription Constructor");
|
||||||
this._pushEndpoint = pushEndpoint;
|
this._pushEndpoint = pushEndpoint;
|
||||||
this._scope = scope;
|
this._scope = scope;
|
||||||
this._pageURL = pageURL;
|
this._principal = principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
PushSubscription.prototype = {
|
PushSubscription.prototype = {
|
||||||
|
@ -53,10 +53,10 @@ PushSubscription.prototype = {
|
||||||
.getService(Ci.nsISyncMessageSender);
|
.getService(Ci.nsISyncMessageSender);
|
||||||
},
|
},
|
||||||
|
|
||||||
__init: function(endpoint, scope, pageURL) {
|
__init: function(endpoint, scope, principal) {
|
||||||
this._pushEndpoint = endpoint;
|
this._pushEndpoint = endpoint;
|
||||||
this._scope = scope;
|
this._scope = scope;
|
||||||
this._pageURL = pageURL;
|
this._principal = principal;
|
||||||
},
|
},
|
||||||
|
|
||||||
get endpoint() {
|
get endpoint() {
|
||||||
|
@ -71,11 +71,10 @@ PushSubscription.prototype = {
|
||||||
reject: reject });
|
reject: reject });
|
||||||
|
|
||||||
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
||||||
pageURL: this._pageURL,
|
|
||||||
scope: this._scope,
|
scope: this._scope,
|
||||||
pushEndpoint: this._pushEndpoint,
|
pushEndpoint: this._pushEndpoint,
|
||||||
requestID: resolverId
|
requestID: resolverId
|
||||||
});
|
}, null, this._principal);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
return this.createPromise(promiseInit);
|
return this.createPromise(promiseInit);
|
||||||
|
@ -92,10 +91,10 @@ PushSubscription.prototype = {
|
||||||
|
|
||||||
switch (aMessage.name) {
|
switch (aMessage.name) {
|
||||||
case "PushService:Unregister:OK":
|
case "PushService:Unregister:OK":
|
||||||
resolver.resolve(false);
|
resolver.resolve(true);
|
||||||
break;
|
break;
|
||||||
case "PushService:Unregister:KO":
|
case "PushService:Unregister:KO":
|
||||||
resolver.reject(true);
|
resolver.resolve(false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
|
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
|
||||||
|
@ -133,7 +132,6 @@ Push.prototype = {
|
||||||
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
|
gDebuggingEnabled = Services.prefs.getBoolPref("dom.push.debug");
|
||||||
debug("init()");
|
debug("init()");
|
||||||
|
|
||||||
this._pageURL = aWindow.document.nodePrincipal.URI;
|
|
||||||
this._window = aWindow;
|
this._window = aWindow;
|
||||||
|
|
||||||
this.initDOMRequestHelper(aWindow, [
|
this.initDOMRequestHelper(aWindow, [
|
||||||
|
@ -145,6 +143,7 @@ Push.prototype = {
|
||||||
|
|
||||||
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||||
.getService(Ci.nsISyncMessageSender);
|
.getService(Ci.nsISyncMessageSender);
|
||||||
|
this._principal = aWindow.document.nodePrincipal;
|
||||||
},
|
},
|
||||||
|
|
||||||
setScope: function(scope){
|
setScope: function(scope){
|
||||||
|
@ -160,8 +159,6 @@ Push.prototype = {
|
||||||
let permValue =
|
let permValue =
|
||||||
Services.perms.testExactPermissionFromPrincipal(principal, type);
|
Services.perms.testExactPermissionFromPrincipal(principal, type);
|
||||||
|
|
||||||
debug("Existing permission " + permValue);
|
|
||||||
|
|
||||||
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||||
aAllowCallback();
|
aAllowCallback();
|
||||||
return;
|
return;
|
||||||
|
@ -219,9 +216,9 @@ Push.prototype = {
|
||||||
switch (aMessage.name) {
|
switch (aMessage.name) {
|
||||||
case "PushService:Register:OK":
|
case "PushService:Register:OK":
|
||||||
{
|
{
|
||||||
let subscription = new this._window.PushSubscription(json.pushEndpoint,
|
let subscription =
|
||||||
this._scope,
|
new this._window.PushSubscription(json.pushEndpoint, this._scope,
|
||||||
this._pageURL.spec);
|
this._principal);
|
||||||
resolver.resolve(subscription);
|
resolver.resolve(subscription);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -232,8 +229,9 @@ Push.prototype = {
|
||||||
{
|
{
|
||||||
let subscription = null;
|
let subscription = null;
|
||||||
try {
|
try {
|
||||||
subscription = new this._window.PushSubscription(json.registration.pushEndpoint,
|
subscription =
|
||||||
this._scope, this._pageURL.spec);
|
new this._window.PushSubscription(json.registration.pushEndpoint,
|
||||||
|
this._scope, this._principal);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
}
|
}
|
||||||
resolver.resolve(subscription);
|
resolver.resolve(subscription);
|
||||||
|
@ -255,10 +253,9 @@ Push.prototype = {
|
||||||
this.askPermission(
|
this.askPermission(
|
||||||
function() {
|
function() {
|
||||||
this._cpmm.sendAsyncMessage("Push:Register", {
|
this._cpmm.sendAsyncMessage("Push:Register", {
|
||||||
pageURL: this._pageURL.spec,
|
|
||||||
scope: this._scope,
|
scope: this._scope,
|
||||||
requestID: resolverId
|
requestID: resolverId
|
||||||
});
|
}, null, this._principal);
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
|
@ -279,10 +276,9 @@ Push.prototype = {
|
||||||
this.askPermission(
|
this.askPermission(
|
||||||
function() {
|
function() {
|
||||||
this._cpmm.sendAsyncMessage("Push:Registration", {
|
this._cpmm.sendAsyncMessage("Push:Registration", {
|
||||||
pageURL: this._pageURL.spec,
|
|
||||||
scope: this._scope,
|
scope: this._scope,
|
||||||
requestID: resolverId
|
requestID: resolverId
|
||||||
});
|
}, null, this._principal);
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
|
@ -294,11 +290,14 @@ Push.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
hasPermission: function() {
|
hasPermission: function() {
|
||||||
debug("getSubscription()" + this._scope);
|
debug("hasPermission()" + this._scope);
|
||||||
|
|
||||||
let p = this.createPromise(function(resolve, reject) {
|
let p = this.createPromise(function(resolve, reject) {
|
||||||
let permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
|
let permissionManager = Cc["@mozilla.org/permissionmanager;1"]
|
||||||
let permission = permissionManager.testExactPermission(this._pageURL, "push");
|
.getService(Ci.nsIPermissionManager);
|
||||||
|
let permission =
|
||||||
|
permissionManager.testExactPermissionFromPrincipal(this._principal,
|
||||||
|
"push");
|
||||||
|
|
||||||
let pushPermissionStatus = "default";
|
let pushPermissionStatus = "default";
|
||||||
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||||
|
|
|
@ -147,9 +147,15 @@ this.PushDB.prototype = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Perform a unique match against { scope, originAttributes }
|
||||||
getByScope: function(aScope) {
|
getByIdentifiers: function(aPageRecord) {
|
||||||
debug("getByScope() " + aScope);
|
debug("getByIdentifiers() { " + aPageRecord.scope + ", " +
|
||||||
|
JSON.stringify(aPageRecord.originAttributes) + " }");
|
||||||
|
if (!aPageRecord.scope || aPageRecord.originAttributes == undefined) {
|
||||||
|
return Promise.reject(
|
||||||
|
new TypeError("Scope and originAttributes are required! " +
|
||||||
|
JSON.stringify(aPageRecord)));
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) =>
|
||||||
this.newTxn(
|
this.newTxn(
|
||||||
|
@ -158,11 +164,11 @@ this.PushDB.prototype = {
|
||||||
function txnCb(aTxn, aStore) {
|
function txnCb(aTxn, aStore) {
|
||||||
aTxn.result = undefined;
|
aTxn.result = undefined;
|
||||||
|
|
||||||
let index = aStore.index("scope");
|
let index = aStore.index("identifiers");
|
||||||
index.get(aScope).onsuccess = function setTxnResult(aEvent) {
|
let request = index.get(IDBKeyRange.only([aPageRecord.scope, aPageRecord.originAttributes]));
|
||||||
|
request.onsuccess = function setTxnResult(aEvent) {
|
||||||
aTxn.result = aEvent.target.result;
|
aTxn.result = aEvent.target.result;
|
||||||
debug("Fetch successful " + aEvent.target.result);
|
}
|
||||||
};
|
|
||||||
},
|
},
|
||||||
resolve,
|
resolve,
|
||||||
reject
|
reject
|
||||||
|
@ -170,6 +176,37 @@ this.PushDB.prototype = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getAllByKey: function(aKeyName, aKeyValue) {
|
||||||
|
return new Promise((resolve, reject) =>
|
||||||
|
this.newTxn(
|
||||||
|
"readonly",
|
||||||
|
this._dbStoreName,
|
||||||
|
function txnCb(aTxn, aStore) {
|
||||||
|
aTxn.result = undefined;
|
||||||
|
|
||||||
|
let index = aStore.index(aKeyName);
|
||||||
|
// It seems ok to use getAll here, since unlike contacts or other
|
||||||
|
// high storage APIs, we don't expect more than a handful of
|
||||||
|
// registrations per domain, and usually only one.
|
||||||
|
let getAllReq = index.mozGetAll(aKeyValue);
|
||||||
|
getAllReq.onsuccess = function setTxnResult(aEvent) {
|
||||||
|
aTxn.result = aEvent.target.result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resolve,
|
||||||
|
reject
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
// aOriginAttributes must be a string!
|
||||||
|
getAllByOriginAttributes: function(aOriginAttributes) {
|
||||||
|
if (typeof aOriginAttributes !== "string") {
|
||||||
|
return Promise.reject("Expected string!");
|
||||||
|
}
|
||||||
|
return this._getAllByKey("originAttributes", aOriginAttributes);
|
||||||
|
},
|
||||||
|
|
||||||
getAllKeyIDs: function() {
|
getAllKeyIDs: function() {
|
||||||
debug("getAllKeyIDs()");
|
debug("getAllKeyIDs()");
|
||||||
|
|
||||||
|
@ -178,6 +215,7 @@ this.PushDB.prototype = {
|
||||||
"readonly",
|
"readonly",
|
||||||
this._dbStoreName,
|
this._dbStoreName,
|
||||||
function txnCb(aTxn, aStore) {
|
function txnCb(aTxn, aStore) {
|
||||||
|
aTxn.result = undefined;
|
||||||
aStore.mozGetAll().onsuccess = function(event) {
|
aStore.mozGetAll().onsuccess = function(event) {
|
||||||
aTxn.result = event.target.result;
|
aTxn.result = event.target.result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,16 +38,16 @@ PushNotificationService.prototype = {
|
||||||
Ci.nsISupportsWeakReference,
|
Ci.nsISupportsWeakReference,
|
||||||
Ci.nsIPushNotificationService]),
|
Ci.nsIPushNotificationService]),
|
||||||
|
|
||||||
register: function register(scope, pageURL) {
|
register: function register(scope, originAttributes) {
|
||||||
return PushService._register({scope, pageURL});
|
return PushService._register({scope, originAttributes});
|
||||||
},
|
},
|
||||||
|
|
||||||
unregister: function unregister(scope) {
|
unregister: function unregister(scope, originAttributes) {
|
||||||
return PushService._unregister({scope});
|
return PushService._unregister({scope, originAttributes});
|
||||||
},
|
},
|
||||||
|
|
||||||
registration: function registration(scope) {
|
registration: function registration(scope, originAttributes) {
|
||||||
return PushService._registration({scope});
|
return PushService._registration({scope, originAttributes});
|
||||||
},
|
},
|
||||||
|
|
||||||
clearAll: function clearAll() {
|
clearAll: function clearAll() {
|
||||||
|
|
|
@ -116,6 +116,26 @@ this.PushService = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_makePendingKey: function(aPageRecord) {
|
||||||
|
return aPageRecord.scope + "|" + aPageRecord.originAttributes;
|
||||||
|
},
|
||||||
|
|
||||||
|
_lookupOrPutPendingRequest: function(aPageRecord) {
|
||||||
|
let key = this._makePendingKey(aPageRecord);
|
||||||
|
if (this._pendingRegisterRequest[key]) {
|
||||||
|
return this._pendingRegisterRequest[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._pendingRegisterRequest[key] = this._registerWithServer(aPageRecord);
|
||||||
|
},
|
||||||
|
|
||||||
|
_deletePendingRequest: function(aPageRecord) {
|
||||||
|
let key = this._makePendingKey(aPageRecord);
|
||||||
|
if (this._pendingRegisterRequest[key]) {
|
||||||
|
delete this._pendingRegisterRequest[key];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_setState: function(aNewState) {
|
_setState: function(aNewState) {
|
||||||
debug("new state: " + aNewState + " old state: " + this._state);
|
debug("new state: " + aNewState + " old state: " + this._state);
|
||||||
|
|
||||||
|
@ -233,24 +253,41 @@ this.PushService = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 1149274. We should support site permissions as well as a way to
|
var originAttributes =
|
||||||
// go from manifest url to 'all scopes registered for push in this app'
|
ChromeUtils.originAttributesToSuffix({ appId: data.appId,
|
||||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
inBrowser: data.browserOnly });
|
||||||
.getService(Ci.nsIAppsService);
|
this._db.getAllByOriginAttributes(originAttributes)
|
||||||
let scope = appsService.getScopeByLocalId(data.appId);
|
.then(records => {
|
||||||
if (!scope) {
|
records.forEach(record => {
|
||||||
debug("webapps-clear-data: No scope found for " + data.appId);
|
this._db.delete(this._service.getKeyFromRecord(record))
|
||||||
return;
|
.then(_ => {
|
||||||
}
|
// courtesy, but don't establish a connection
|
||||||
|
// just for it
|
||||||
|
if (this._ws) {
|
||||||
|
debug("Had a connection, so telling the server");
|
||||||
|
this._sendRequest("unregister", {channelID: records.channelID})
|
||||||
|
.catch(function(e) {
|
||||||
|
debug("Unregister errored " + e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, err => {
|
||||||
|
debug("webapps-clear-data: " + scope +
|
||||||
|
" Could not delete entry " + records.channelID);
|
||||||
|
|
||||||
this._db.getByScope(scope)
|
// courtesy, but don't establish a connection
|
||||||
.then(record =>
|
// just for it
|
||||||
Promise.all([
|
if (this._ws) {
|
||||||
this._db.delete(this._service.getKeyFromRecord(record)),
|
debug("Had a connection, so telling the server");
|
||||||
this._sendRequest("unregister", record)
|
this._sendRequest("unregister", {channelID: records.channelID})
|
||||||
])
|
.catch(function(e) {
|
||||||
).catch(_ => {
|
debug("Unregister errored " + e);
|
||||||
debug("webapps-clear-data: Error in getByScope(" + scope + ")");
|
});
|
||||||
|
}
|
||||||
|
throw "Database error";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, _ => {
|
||||||
|
debug("webapps-clear-data: Error in getAllByOriginAttributes(" + originAttributes + ")");
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -623,13 +660,9 @@ this.PushService = {
|
||||||
// records are objects describing the registration as stored in IndexedDB.
|
// records are objects describing the registration as stored in IndexedDB.
|
||||||
return this._db.getAllKeyIDs()
|
return this._db.getAllKeyIDs()
|
||||||
.then(records => {
|
.then(records => {
|
||||||
let scopes = new Set();
|
|
||||||
for (let record of records) {
|
|
||||||
scopes.add(record.scope);
|
|
||||||
}
|
|
||||||
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
||||||
.getService(Ci.nsIMessageListenerManager);
|
.getService(Ci.nsIMessageListenerManager);
|
||||||
for (let scope of scopes) {
|
for (let record of records) {
|
||||||
// Notify XPCOM observers.
|
// Notify XPCOM observers.
|
||||||
Services.obs.notifyObservers(
|
Services.obs.notifyObservers(
|
||||||
null,
|
null,
|
||||||
|
@ -638,8 +671,8 @@ this.PushService = {
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: record.originAttributes,
|
||||||
scope: scope
|
scope: record.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
|
globalMM.broadcastAsyncMessage('pushsubscriptionchange', data);
|
||||||
|
@ -659,7 +692,7 @@ this.PushService = {
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: record.originAttributes,
|
||||||
scope: record.scope
|
scope: record.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -681,7 +714,7 @@ this.PushService = {
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: record.originAttributes,
|
||||||
scope: record.scope
|
scope: record.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -695,7 +728,8 @@ this.PushService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_notifyApp: function(aPushRecord, message) {
|
_notifyApp: function(aPushRecord, message) {
|
||||||
if (!aPushRecord || !aPushRecord.scope) {
|
if (!aPushRecord || !aPushRecord.scope ||
|
||||||
|
aPushRecord.originAttributes === undefined) {
|
||||||
debug("notifyApp() something is undefined. Dropping notification: " +
|
debug("notifyApp() something is undefined. Dropping notification: " +
|
||||||
JSON.stringify(aPushRecord) );
|
JSON.stringify(aPushRecord) );
|
||||||
return;
|
return;
|
||||||
|
@ -728,7 +762,7 @@ this.PushService = {
|
||||||
// TODO data.
|
// TODO data.
|
||||||
let data = {
|
let data = {
|
||||||
payload: message,
|
payload: message,
|
||||||
originAttributes: {}, // TODO bug 1166350
|
originAttributes: aPushRecord.originAttributes,
|
||||||
scope: aPushRecord.scope
|
scope: aPushRecord.scope
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -745,7 +779,7 @@ this.PushService = {
|
||||||
return this._db.getAllKeyIDs();
|
return this._db.getAllKeyIDs();
|
||||||
},
|
},
|
||||||
|
|
||||||
_sendRequest(action, aRecord) {
|
_sendRequest: function(action, aRecord) {
|
||||||
if (this._state == PUSH_SERVICE_CONNECTION_DISABLE) {
|
if (this._state == PUSH_SERVICE_CONNECTION_DISABLE) {
|
||||||
return Promise.reject({state: 0, error: "Service not active"});
|
return Promise.reject({state: 0, error: "Service not active"});
|
||||||
} else if (this._state == PUSH_SERVICE_ACTIVE_OFFLINE) {
|
} else if (this._state == PUSH_SERVICE_ACTIVE_OFFLINE) {
|
||||||
|
@ -759,37 +793,35 @@ this.PushService = {
|
||||||
* navigator.push, identifying the sending page and other fields.
|
* navigator.push, identifying the sending page and other fields.
|
||||||
*/
|
*/
|
||||||
_registerWithServer: function(aPageRecord) {
|
_registerWithServer: function(aPageRecord) {
|
||||||
debug("registerWithServer()");
|
debug("registerWithServer()" + JSON.stringify(aPageRecord));
|
||||||
|
|
||||||
return this._sendRequest("register", aPageRecord)
|
return this._sendRequest("register", aPageRecord)
|
||||||
.then(pushRecord => this._onRegisterSuccess(pushRecord),
|
.then(pushRecord => this._onRegisterSuccess(pushRecord),
|
||||||
err => this._onRegisterError(err))
|
err => this._onRegisterError(err))
|
||||||
.then(pushRecord => {
|
.then(pushRecord => {
|
||||||
if (this._pendingRegisterRequest[aPageRecord.scope]) {
|
this._deletePendingRequest(aPageRecord);
|
||||||
delete this._pendingRegisterRequest[aPageRecord.scope];
|
|
||||||
}
|
|
||||||
return pushRecord;
|
return pushRecord;
|
||||||
}, err => {
|
}, err => {
|
||||||
if (this._pendingRegisterRequest[aPageRecord.scope]) {
|
this._deletePendingRequest(aPageRecord);
|
||||||
delete this._pendingRegisterRequest[aPageRecord.scope];
|
|
||||||
}
|
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_register: function(aPageRecord) {
|
_register: function(aPageRecord) {
|
||||||
|
debug("_register()");
|
||||||
|
if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
|
||||||
|
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||||
|
}
|
||||||
|
|
||||||
return this._checkActivated()
|
return this._checkActivated()
|
||||||
.then(_ => this._db.getByScope(aPageRecord.scope))
|
.then(_ => this._db.getByIdentifiers(aPageRecord))
|
||||||
.then(pushRecord => {
|
.then(pushRecord => {
|
||||||
if (pushRecord === undefined) {
|
if (pushRecord === undefined) {
|
||||||
if (this._pendingRegisterRequest[aPageRecord.scope]) {
|
return this._lookupOrPutPendingRequest(aPageRecord);
|
||||||
return this._pendingRegisterRequest[aPageRecord.scope];
|
|
||||||
}
|
|
||||||
return this._pendingRegisterRequest[aPageRecord.scope] = this._registerWithServer(aPageRecord);
|
|
||||||
}
|
}
|
||||||
return pushRecord;
|
return pushRecord;
|
||||||
}, error => {
|
}, error => {
|
||||||
debug("getByScope failed");
|
debug("getByIdentifiers failed");
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -833,10 +865,39 @@ this.PushService = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
|
if (!aMessage.target.assertPermission("push")) {
|
||||||
let json = aMessage.data;
|
debug("Got message from a child process that does not have 'push' permission.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this[aMessage.name.slice("Push:".length).toLowerCase()](json, mm);
|
let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
|
||||||
|
let pageRecord = aMessage.data;
|
||||||
|
|
||||||
|
let principal = aMessage.principal;
|
||||||
|
if (!principal) {
|
||||||
|
debug("No principal passed!");
|
||||||
|
let message = {
|
||||||
|
requestID: aPageRecord.requestID,
|
||||||
|
error: "SecurityError"
|
||||||
|
};
|
||||||
|
mm.sendAsyncMessage("PushService:Register:KO", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pageRecord.originAttributes =
|
||||||
|
ChromeUtils.originAttributesToSuffix(principal.originAttributes);
|
||||||
|
|
||||||
|
if (!pageRecord.scope || pageRecord.originAttributes === undefined) {
|
||||||
|
debug("Incorrect identifier values set! " + JSON.stringify(pageRecord));
|
||||||
|
let message = {
|
||||||
|
requestID: aPageRecord.requestID,
|
||||||
|
error: "SecurityError"
|
||||||
|
};
|
||||||
|
mm.sendAsyncMessage("PushService:Register:KO", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this[aMessage.name.slice("Push:".length).toLowerCase()](pageRecord, mm);
|
||||||
},
|
},
|
||||||
|
|
||||||
register: function(aPageRecord, aMessageManager) {
|
register: function(aPageRecord, aMessageManager) {
|
||||||
|
@ -883,13 +944,12 @@ this.PushService = {
|
||||||
*/
|
*/
|
||||||
_unregister: function(aPageRecord) {
|
_unregister: function(aPageRecord) {
|
||||||
debug("_unregister()");
|
debug("_unregister()");
|
||||||
|
if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
|
||||||
if (!aPageRecord.scope) {
|
|
||||||
return Promise.reject({state: 0, error: "NotFoundError"});
|
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._checkActivated()
|
return this._checkActivated()
|
||||||
.then(_ => this._db.getByScope(aPageRecord.scope))
|
.then(_ => this._db.getByIdentifiers(aPageRecord))
|
||||||
.then(record => {
|
.then(record => {
|
||||||
// If the endpoint didn't exist, let's just fail.
|
// If the endpoint didn't exist, let's just fail.
|
||||||
if (record === undefined) {
|
if (record === undefined) {
|
||||||
|
@ -932,12 +992,12 @@ this.PushService = {
|
||||||
*/
|
*/
|
||||||
_registration: function(aPageRecord) {
|
_registration: function(aPageRecord) {
|
||||||
debug("_registration()");
|
debug("_registration()");
|
||||||
if (!aPageRecord.scope) {
|
if (!aPageRecord.scope || aPageRecord.originAttributes === undefined) {
|
||||||
return Promise.reject({state: 0, error: "Database error"});
|
return Promise.reject({state: 0, error: "NotFoundError"});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._checkActivated()
|
return this._checkActivated()
|
||||||
.then(_ => this._db.getByScope(aPageRecord.scope))
|
.then(_ => this._db.getByIdentifiers(aPageRecord))
|
||||||
.then(pushRecord => {
|
.then(pushRecord => {
|
||||||
if (!pushRecord) {
|
if (!pushRecord) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -33,7 +33,7 @@ function debug(s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const kPUSHHTTP2DB_DB_NAME = "pushHttp2";
|
const kPUSHHTTP2DB_DB_NAME = "pushHttp2";
|
||||||
const kPUSHHTTP2DB_DB_VERSION = 1; // Change this if the IndexedDB format changes
|
const kPUSHHTTP2DB_DB_VERSION = 3; // Change this if the IndexedDB format changes
|
||||||
const kPUSHHTTP2DB_STORE_NAME = "pushHttp2";
|
const kPUSHHTTP2DB_STORE_NAME = "pushHttp2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -291,6 +291,7 @@ SubscriptionListener.prototype = {
|
||||||
pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint,
|
pushReceiptEndpoint: linkParserResult.pushReceiptEndpoint,
|
||||||
pageURL: this._subInfo.record.pageURL,
|
pageURL: this._subInfo.record.pageURL,
|
||||||
scope: this._subInfo.record.scope,
|
scope: this._subInfo.record.scope,
|
||||||
|
originAttributes: this._subInfo.record.originAttributes,
|
||||||
pushCount: 0,
|
pushCount: 0,
|
||||||
lastPush: 0
|
lastPush: 0
|
||||||
};
|
};
|
||||||
|
@ -385,15 +386,33 @@ this.PushServiceHttp2 = {
|
||||||
aDbInstance) {
|
aDbInstance) {
|
||||||
debug("upgradeSchemaHttp2()");
|
debug("upgradeSchemaHttp2()");
|
||||||
|
|
||||||
|
//XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old
|
||||||
|
//registrations away without even informing the app.
|
||||||
|
if (aNewVersion != aOldVersion) {
|
||||||
|
try {
|
||||||
|
aDb.deleteObjectStore(aDbInstance._dbStoreName);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === "NotFoundError") {
|
||||||
|
debug("No existing object store found");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
||||||
{ keyPath: "subscriptionUri" });
|
{ keyPath: "subscriptionUri" });
|
||||||
|
|
||||||
// index to fetch records based on endpoints. used by unregister
|
// index to fetch records based on endpoints. used by unregister
|
||||||
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
||||||
|
|
||||||
// index to fetch records per scope, so we can identify endpoints
|
// index to fetch records by identifiers.
|
||||||
// associated with an app.
|
// In the current security model, the originAttributes distinguish between
|
||||||
objectStore.createIndex("scope", "scope", { unique: true });
|
// different 'apps' on the same origin. Since ServiceWorkers are
|
||||||
|
// same-origin to the scope they are registered for, the attributes and
|
||||||
|
// scope are enough to reconstruct a valid principal.
|
||||||
|
objectStore.createIndex("identifiers", ["scope", "originAttributes"], { unique: true });
|
||||||
|
objectStore.createIndex("originAttributes", "originAttributes", { unique: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
getKeyFromRecord: function(aRecord) {
|
getKeyFromRecord: function(aRecord) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ var threadManager = Cc["@mozilla.org/thread-manager;1"]
|
||||||
.getService(Ci.nsIThreadManager);
|
.getService(Ci.nsIThreadManager);
|
||||||
|
|
||||||
const kPUSHWSDB_DB_NAME = "pushapi";
|
const kPUSHWSDB_DB_NAME = "pushapi";
|
||||||
const kPUSHWSDB_DB_VERSION = 1; // Change this if the IndexedDB format changes
|
const kPUSHWSDB_DB_VERSION = 3; // Change this if the IndexedDB format changes
|
||||||
const kPUSHWSDB_STORE_NAME = "pushapi";
|
const kPUSHWSDB_STORE_NAME = "pushapi";
|
||||||
|
|
||||||
const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
|
const kUDP_WAKEUP_WS_STATUS_CODE = 4774; // WebSocket Close status code sent
|
||||||
|
@ -132,15 +132,33 @@ this.PushServiceWebSocket = {
|
||||||
aDbInstance) {
|
aDbInstance) {
|
||||||
debug("upgradeSchemaWS()");
|
debug("upgradeSchemaWS()");
|
||||||
|
|
||||||
|
//XXXnsm We haven't shipped Push during this upgrade, so I'm just going to throw old
|
||||||
|
//registrations away without even informing the app.
|
||||||
|
if (aNewVersion != aOldVersion) {
|
||||||
|
try {
|
||||||
|
aDb.deleteObjectStore(aDbInstance._dbStoreName);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === "NotFoundError") {
|
||||||
|
debug("No existing object store found");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
let objectStore = aDb.createObjectStore(aDbInstance._dbStoreName,
|
||||||
{ keyPath: "channelID" });
|
{ keyPath: "channelID" });
|
||||||
|
|
||||||
// index to fetch records based on endpoints. used by unregister
|
// index to fetch records based on endpoints. used by unregister
|
||||||
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
objectStore.createIndex("pushEndpoint", "pushEndpoint", { unique: true });
|
||||||
|
|
||||||
// index to fetch records per scope, so we can identify endpoints
|
// index to fetch records by identifiers.
|
||||||
// associated with an app.
|
// In the current security model, the originAttributes distinguish between
|
||||||
objectStore.createIndex("scope", "scope", { unique: true });
|
// different 'apps' on the same origin. Since ServiceWorkers are
|
||||||
|
// same-origin to the scope they are registered for, the attributes and
|
||||||
|
// scope are enough to reconstruct a valid principal.
|
||||||
|
objectStore.createIndex("identifiers", ["scope", "originAttributes"], { unique: true });
|
||||||
|
objectStore.createIndex("originAttributes", "originAttributes", { unique: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
getKeyFromRecord: function(aRecord) {
|
getKeyFromRecord: function(aRecord) {
|
||||||
|
@ -870,10 +888,12 @@ this.PushServiceWebSocket = {
|
||||||
pushEndpoint: reply.pushEndpoint,
|
pushEndpoint: reply.pushEndpoint,
|
||||||
pageURL: tmp.record.pageURL,
|
pageURL: tmp.record.pageURL,
|
||||||
scope: tmp.record.scope,
|
scope: tmp.record.scope,
|
||||||
|
originAttributes: tmp.record.originAttributes,
|
||||||
pushCount: 0,
|
pushCount: 0,
|
||||||
lastPush: 0,
|
lastPush: 0,
|
||||||
version: null
|
version: null
|
||||||
};
|
};
|
||||||
|
dump("PushWebSocket " + JSON.stringify(record));
|
||||||
tmp.resolve(record);
|
tmp.resolve(record);
|
||||||
} else {
|
} else {
|
||||||
tmp.reject(reply);
|
tmp.reject(reply);
|
||||||
|
|
|
@ -15,6 +15,8 @@ skip-if = os == "android" || toolkit == "gonk"
|
||||||
skip-if = os == "android" || toolkit == "gonk"
|
skip-if = os == "android" || toolkit == "gonk"
|
||||||
[test_multiple_register_during_service_activation.html]
|
[test_multiple_register_during_service_activation.html]
|
||||||
skip-if = os == "android" || toolkit == "gonk"
|
skip-if = os == "android" || toolkit == "gonk"
|
||||||
|
[test_unregister.html]
|
||||||
|
skip-if = os == "android" || toolkit == "gonk"
|
||||||
[test_multiple_register_different_scope.html]
|
[test_multiple_register_different_scope.html]
|
||||||
skip-if = os == "android" || toolkit == "gonk"
|
skip-if = os == "android" || toolkit == "gonk"
|
||||||
[test_try_registering_offline_disabled.html]
|
[test_try_registering_offline_disabled.html]
|
||||||
|
|
|
@ -120,6 +120,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
SpecialPowers.pushPrefEnv({"set": [
|
SpecialPowers.pushPrefEnv({"set": [
|
||||||
["dom.push.enabled", true],
|
["dom.push.enabled", true],
|
||||||
|
["dom.push.debug", true],
|
||||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||||
["dom.serviceWorkers.enabled", true],
|
["dom.serviceWorkers.enabled", true],
|
||||||
["dom.serviceWorkers.testing.enabled", true]
|
["dom.serviceWorkers.testing.enabled", true]
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
Bug 1170817: Push tests.
|
||||||
|
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 1170817</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||||
|
</head>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1170817">Mozilla Bug 1170817</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
|
var registration;
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
|
||||||
|
.then(swr => { registration = swr; return swr; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterSW() {
|
||||||
|
return registration.unregister().then(function(result) {
|
||||||
|
ok(result, "Unregister should return true.");
|
||||||
|
}, function(e) {
|
||||||
|
dump("Unregistering the SW failed with " + e + "\n");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupPushNotification(swr) {
|
||||||
|
return swr.pushManager.subscribe().then(
|
||||||
|
pushSubscription => {
|
||||||
|
ok(true, "successful registered for push notification");
|
||||||
|
return pushSubscription;
|
||||||
|
}, error => {
|
||||||
|
ok(false, "could not register for push notification");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterPushNotification(pushSubscription) {
|
||||||
|
return pushSubscription.unsubscribe().then(
|
||||||
|
result => {
|
||||||
|
ok(result, "unsubscribe() on existing subscription should return true.");
|
||||||
|
return pushSubscription;
|
||||||
|
}, error => {
|
||||||
|
ok(false, "unsubscribe() should never fail.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterAgain(pushSubscription) {
|
||||||
|
return pushSubscription.unsubscribe().then(
|
||||||
|
result => {
|
||||||
|
ok(!result, "unsubscribe() on previously unsubscribed subscription should return false.");
|
||||||
|
return pushSubscription;
|
||||||
|
}, error => {
|
||||||
|
ok(false, "unsubscribe() should never fail.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
start()
|
||||||
|
.then(setupPushNotification)
|
||||||
|
.then(unregisterPushNotification)
|
||||||
|
.then(unregisterAgain)
|
||||||
|
.then(unregisterSW)
|
||||||
|
.catch(function(e) {
|
||||||
|
ok(false, "Some test failed with error " + e);
|
||||||
|
}).then(SimpleTest.finish);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [
|
||||||
|
["dom.push.enabled", true],
|
||||||
|
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||||
|
["dom.serviceWorkers.enabled", true],
|
||||||
|
["dom.serviceWorkers.testing.enabled", true]
|
||||||
|
]}, runTest);
|
||||||
|
SpecialPowers.addPermission('push', true, document);
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -25,16 +25,19 @@ add_task(function* test_notification_ack() {
|
||||||
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
channelID: '21668e05-6da8-42c9-b8ab-9cc3f4d5630c',
|
||||||
pushEndpoint: 'https://example.com/update/1',
|
pushEndpoint: 'https://example.com/update/1',
|
||||||
scope: 'https://example.org/1',
|
scope: 'https://example.org/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
}, {
|
}, {
|
||||||
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
channelID: '9a5ff87f-47c9-4215-b2b8-0bdd38b4b305',
|
||||||
pushEndpoint: 'https://example.com/update/2',
|
pushEndpoint: 'https://example.com/update/2',
|
||||||
scope: 'https://example.org/2',
|
scope: 'https://example.org/2',
|
||||||
|
originAttributes: '',
|
||||||
version: 2
|
version: 2
|
||||||
}, {
|
}, {
|
||||||
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
channelID: '5477bfda-22db-45d4-9614-fee369630260',
|
||||||
pushEndpoint: 'https://example.com/update/3',
|
pushEndpoint: 'https://example.com/update/3',
|
||||||
scope: 'https://example.org/3',
|
scope: 'https://example.org/3',
|
||||||
|
originAttributes: '',
|
||||||
version: 3
|
version: 3
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
|
|
@ -23,11 +23,13 @@ add_task(function* test_notification_duplicate() {
|
||||||
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
channelID: '8d2d9400-3597-4c5a-8a38-c546b0043bcc',
|
||||||
pushEndpoint: 'https://example.org/update/1',
|
pushEndpoint: 'https://example.org/update/1',
|
||||||
scope: 'https://example.com/1',
|
scope: 'https://example.com/1',
|
||||||
|
originAttributes: "",
|
||||||
version: 2
|
version: 2
|
||||||
}, {
|
}, {
|
||||||
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
|
channelID: '27d1e393-03ef-4c72-a5e6-9e890dfccad0',
|
||||||
pushEndpoint: 'https://example.org/update/2',
|
pushEndpoint: 'https://example.org/update/2',
|
||||||
scope: 'https://example.com/2',
|
scope: 'https://example.com/2',
|
||||||
|
originAttributes: "",
|
||||||
version: 2
|
version: 2
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
|
|
@ -19,20 +19,25 @@ function run_test() {
|
||||||
add_task(function* test_notification_error() {
|
add_task(function* test_notification_error() {
|
||||||
let db = PushServiceWebSocket.newPushDB();
|
let db = PushServiceWebSocket.newPushDB();
|
||||||
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||||
|
|
||||||
|
let originAttributes = '';
|
||||||
let records = [{
|
let records = [{
|
||||||
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
channelID: 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||||
pushEndpoint: 'https://example.org/update/success-1',
|
pushEndpoint: 'https://example.org/update/success-1',
|
||||||
scope: 'https://example.com/a',
|
scope: 'https://example.com/a',
|
||||||
|
originAttributes: originAttributes,
|
||||||
version: 1
|
version: 1
|
||||||
}, {
|
}, {
|
||||||
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
channelID: '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||||
pushEndpoint: 'https://example.org/update/error',
|
pushEndpoint: 'https://example.org/update/error',
|
||||||
scope: 'https://example.com/b',
|
scope: 'https://example.com/b',
|
||||||
|
originAttributes: originAttributes,
|
||||||
version: 2
|
version: 2
|
||||||
}, {
|
}, {
|
||||||
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
channelID: 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||||
pushEndpoint: 'https://example.org/update/success-2',
|
pushEndpoint: 'https://example.org/update/success-2',
|
||||||
scope: 'https://example.com/c',
|
scope: 'https://example.com/c',
|
||||||
|
originAttributes: originAttributes,
|
||||||
version: 3
|
version: 3
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -107,19 +112,22 @@ add_task(function* test_notification_error() {
|
||||||
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
yield waitForPromise(ackDefer.promise, DEFAULT_TIMEOUT,
|
||||||
'Timed out waiting for acknowledgements');
|
'Timed out waiting for acknowledgements');
|
||||||
|
|
||||||
let aRecord = yield db.getByScope('https://example.com/a');
|
let aRecord = yield db.getByIdentifiers({scope: 'https://example.com/a',
|
||||||
|
originAttributes: originAttributes });
|
||||||
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
equal(aRecord.channelID, 'f04f1e46-9139-4826-b2d1-9411b0821283',
|
||||||
'Wrong channel ID for record A');
|
'Wrong channel ID for record A');
|
||||||
strictEqual(aRecord.version, 2,
|
strictEqual(aRecord.version, 2,
|
||||||
'Should return the new version for record A');
|
'Should return the new version for record A');
|
||||||
|
|
||||||
let bRecord = yield db.getByScope('https://example.com/b');
|
let bRecord = yield db.getByIdentifiers({scope: 'https://example.com/b',
|
||||||
|
originAttributes: originAttributes });
|
||||||
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
equal(bRecord.channelID, '3c3930ba-44de-40dc-a7ca-8a133ec1a866',
|
||||||
'Wrong channel ID for record B');
|
'Wrong channel ID for record B');
|
||||||
strictEqual(bRecord.version, 2,
|
strictEqual(bRecord.version, 2,
|
||||||
'Should return the previous version for record B');
|
'Should return the previous version for record B');
|
||||||
|
|
||||||
let cRecord = yield db.getByScope('https://example.com/c');
|
let cRecord = yield db.getByIdentifiers({scope: 'https://example.com/c',
|
||||||
|
originAttributes: originAttributes });
|
||||||
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
equal(cRecord.channelID, 'b63f7bef-0a0d-4236-b41e-086a69dfd316',
|
||||||
'Wrong channel ID for record C');
|
'Wrong channel ID for record C');
|
||||||
strictEqual(cRecord.version, 4,
|
strictEqual(cRecord.version, 4,
|
||||||
|
|
|
@ -57,17 +57,20 @@ add_task(function* test_pushNotifications() {
|
||||||
subscriptionUri: serverURL + '/pushNotifications/subscription1',
|
subscriptionUri: serverURL + '/pushNotifications/subscription1',
|
||||||
pushEndpoint: serverURL + '/pushEndpoint1',
|
pushEndpoint: serverURL + '/pushEndpoint1',
|
||||||
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint1',
|
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint1',
|
||||||
scope: 'https://example.com/page/1'
|
scope: 'https://example.com/page/1',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
}, {
|
}, {
|
||||||
subscriptionUri: serverURL + '/pushNotifications/subscription2',
|
subscriptionUri: serverURL + '/pushNotifications/subscription2',
|
||||||
pushEndpoint: serverURL + '/pushEndpoint2',
|
pushEndpoint: serverURL + '/pushEndpoint2',
|
||||||
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2',
|
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2',
|
||||||
scope: 'https://example.com/page/2'
|
scope: 'https://example.com/page/2',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
}, {
|
}, {
|
||||||
subscriptionUri: serverURL + '/pushNotifications/subscription3',
|
subscriptionUri: serverURL + '/pushNotifications/subscription3',
|
||||||
pushEndpoint: serverURL + '/pushEndpoint3',
|
pushEndpoint: serverURL + '/pushEndpoint3',
|
||||||
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3',
|
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3',
|
||||||
scope: 'https://example.com/page/3'
|
scope: 'https://example.com/page/3',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
}];
|
}];
|
||||||
|
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ add_task(function* test_notification_version_string() {
|
||||||
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
channelID: '6ff97d56-d0c0-43bc-8f5b-61b855e1d93b',
|
||||||
pushEndpoint: 'https://example.org/updates/1',
|
pushEndpoint: 'https://example.org/updates/1',
|
||||||
scope: 'https://example.com/page/1',
|
scope: 'https://example.com/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 2
|
version: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,8 @@ add_task(function* test1() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.com/retry5xxCode'
|
'https://example.com/retry5xxCode',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
var subscriptionUri = serverURL + '/subscription';
|
var subscriptionUri = serverURL + '/subscription';
|
||||||
|
|
|
@ -47,7 +47,8 @@ add_task(function* test_register_case() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield waitForPromise(
|
let newRecord = yield waitForPromise(
|
||||||
PushNotificationService.register('https://example.net/case'),
|
PushNotificationService.register('https://example.net/case',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
DEFAULT_TIMEOUT,
|
DEFAULT_TIMEOUT,
|
||||||
'Mixed-case register response timed out'
|
'Mixed-case register response timed out'
|
||||||
);
|
);
|
||||||
|
|
|
@ -47,7 +47,8 @@ add_task(function* test_pushSubscriptionNoConnection() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-response'),
|
'https://example.net/page/invalid-response',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes("Error");
|
return error && error.includes("Error");
|
||||||
},
|
},
|
||||||
|
@ -87,7 +88,8 @@ add_task(function* test_pushSubscriptionMissingLocation() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-response'),
|
'https://example.net/page/invalid-response',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes("Return code 201, but the answer is bogus");
|
return error && error.includes("Return code 201, but the answer is bogus");
|
||||||
},
|
},
|
||||||
|
@ -113,7 +115,8 @@ add_task(function* test_pushSubscriptionMissingLink() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-response'),
|
'https://example.net/page/invalid-response',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes("Return code 201, but the answer is bogus");
|
return error && error.includes("Return code 201, but the answer is bogus");
|
||||||
},
|
},
|
||||||
|
@ -139,7 +142,8 @@ add_task(function* test_pushSubscriptionMissingLink1() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-response'),
|
'https://example.net/page/invalid-response',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes("Return code 201, but the answer is bogus");
|
return error && error.includes("Return code 201, but the answer is bogus");
|
||||||
},
|
},
|
||||||
|
@ -165,7 +169,8 @@ add_task(function* test_pushSubscriptionLocationBogus() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-response'),
|
'https://example.net/page/invalid-response',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes("Return code 201, but URI is bogus.");
|
return error && error.includes("Return code 201, but URI is bogus.");
|
||||||
},
|
},
|
||||||
|
@ -191,7 +196,8 @@ add_task(function* test_pushSubscriptionNot2xxCode() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-response'),
|
'https://example.net/page/invalid-response',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes("Error");
|
return error && error.includes("Error");
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,6 +29,7 @@ add_task(function* test_register_flush() {
|
||||||
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
channelID: '9bcc7efb-86c7-4457-93ea-e24e6eb59b74',
|
||||||
pushEndpoint: 'https://example.org/update/1',
|
pushEndpoint: 'https://example.org/update/1',
|
||||||
scope: 'https://example.com/page/1',
|
scope: 'https://example.com/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 2
|
version: 2
|
||||||
};
|
};
|
||||||
yield db.put(record);
|
yield db.put(record);
|
||||||
|
@ -75,8 +76,7 @@ add_task(function* test_register_flush() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.com/page/2'
|
'https://example.com/page/2', '');
|
||||||
);
|
|
||||||
equal(newRecord.pushEndpoint, 'https://example.org/update/2',
|
equal(newRecord.pushEndpoint, 'https://example.org/update/2',
|
||||||
'Wrong push endpoint in record');
|
'Wrong push endpoint in record');
|
||||||
equal(newRecord.scope, 'https://example.com/page/2',
|
equal(newRecord.scope, 'https://example.com/page/2',
|
||||||
|
|
|
@ -48,7 +48,8 @@ add_task(function* test_register_invalid_channel() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/invalid-channel'),
|
PushNotificationService.register('https://example.com/invalid-channel',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'Invalid channel ID';
|
return error == 'Invalid channel ID';
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,8 @@ add_task(function* test_register_invalid_endpoint() {
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register(
|
PushNotificationService.register(
|
||||||
'https://example.net/page/invalid-endpoint'),
|
'https://example.net/page/invalid-endpoint',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error && error.includes('Invalid pushEndpoint');
|
return error && error.includes('Invalid pushEndpoint');
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,8 @@ add_task(function* test_register_invalid_json() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.net/page/invalid-json'),
|
PushNotificationService.register('https://example.net/page/invalid-json',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,7 +53,8 @@ add_task(function* test_register_no_id() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/incomplete'),
|
PushNotificationService.register('https://example.com/incomplete',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,10 +45,12 @@ add_task(function* test_register_request_queue() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let firstRegister = PushNotificationService.register(
|
let firstRegister = PushNotificationService.register(
|
||||||
'https://example.com/page/1'
|
'https://example.com/page/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
let secondRegister = PushNotificationService.register(
|
let secondRegister = PushNotificationService.register(
|
||||||
'https://example.com/page/1'
|
'https://example.com/page/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
yield waitForPromise(Promise.all([
|
yield waitForPromise(Promise.all([
|
||||||
|
|
|
@ -74,7 +74,8 @@ add_task(function* test_register_rollback() {
|
||||||
|
|
||||||
// Should return a rejected promise if storage fails.
|
// Should return a rejected promise if storage fails.
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/storage-error'),
|
PushNotificationService.register('https://example.com/storage-error',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'universe has imploded';
|
return error == 'universe has imploded';
|
||||||
},
|
},
|
||||||
|
|
|
@ -57,7 +57,8 @@ add_task(function* test_register_success() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.org/1'
|
'https://example.org/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }
|
||||||
);
|
);
|
||||||
equal(newRecord.channelID, channelID,
|
equal(newRecord.channelID, channelID,
|
||||||
'Wrong channel ID in registration record');
|
'Wrong channel ID in registration record');
|
||||||
|
|
|
@ -57,7 +57,8 @@ add_task(function* test_pushSubscriptionSuccess() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.org/1'
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
);
|
);
|
||||||
|
|
||||||
var subscriptionUri = serverURL + '/pushSubscriptionSuccesss';
|
var subscriptionUri = serverURL + '/pushSubscriptionSuccesss';
|
||||||
|
@ -99,7 +100,8 @@ add_task(function* test_pushSubscriptionMissingLink2() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let newRecord = yield PushNotificationService.register(
|
let newRecord = yield PushNotificationService.register(
|
||||||
'https://example.org/no_receiptEndpoint'
|
'https://example.org/no_receiptEndpoint',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
);
|
);
|
||||||
|
|
||||||
var subscriptionUri = serverURL + '/subscriptionMissingLink2';
|
var subscriptionUri = serverURL + '/subscriptionMissingLink2';
|
||||||
|
|
|
@ -83,7 +83,8 @@ add_task(function* test_register_timeout() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.net/page/timeout'),
|
PushNotificationService.register('https://example.net/page/timeout',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -59,7 +59,8 @@ add_task(function* test_register_wrong_id() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/mismatched'),
|
PushNotificationService.register('https://example.com/mismatched',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,8 @@ add_task(function* test_register_wrong_type() {
|
||||||
let promise =
|
let promise =
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.register('https://example.com/mistyped'),
|
PushNotificationService.register('https://example.com/mistyped',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'TimeoutError';
|
return error == 'TimeoutError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,7 +21,7 @@ add_task(function* test_registrations_error() {
|
||||||
serverURI: "wss://push.example.org/",
|
serverURI: "wss://push.example.org/",
|
||||||
networkInfo: new MockDesktopNetworkInfo(),
|
networkInfo: new MockDesktopNetworkInfo(),
|
||||||
db: makeStub(db, {
|
db: makeStub(db, {
|
||||||
getByScope(prev, scope) {
|
getByIdentifiers(prev, scope) {
|
||||||
return Promise.reject('Database error');
|
return Promise.reject('Database error');
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -31,7 +31,8 @@ add_task(function* test_registrations_error() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.registration('https://example.net/1'),
|
PushNotificationService.registration('https://example.net/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'Database error';
|
return error == 'Database error';
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,14 +18,15 @@ add_task(function* test_registrations_error() {
|
||||||
serverURI: "https://push.example.org/",
|
serverURI: "https://push.example.org/",
|
||||||
networkInfo: new MockDesktopNetworkInfo(),
|
networkInfo: new MockDesktopNetworkInfo(),
|
||||||
db: makeStub(db, {
|
db: makeStub(db, {
|
||||||
getByScope(prev, scope) {
|
getByIdentifiers() {
|
||||||
return Promise.reject('Database error');
|
return Promise.reject('Database error');
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.registration('https://example.net/1'),
|
PushNotificationService.registration('https://example.net/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error == 'Database error';
|
return error == 'Database error';
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,9 +20,9 @@ add_task(function* test_registration_missing_scope() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.registration(''),
|
PushNotificationService.registration('', ''),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error.error == 'Database error';
|
return error.error == 'NotFoundError';
|
||||||
},
|
},
|
||||||
'Record missing page and manifest URLs'
|
'Record missing page and manifest URLs'
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,6 +24,7 @@ add_task(function* test_registration_none() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let registration = yield PushNotificationService.registration(
|
let registration = yield PushNotificationService.registration(
|
||||||
'https://example.net/1');
|
'https://example.net/1',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false });
|
||||||
ok(!registration, 'Should not open a connection without registration');
|
ok(!registration, 'Should not open a connection without registration');
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,16 +20,19 @@ add_task(function* test_registration_success() {
|
||||||
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
channelID: 'bf001fe0-2684-42f2-bc4d-a3e14b11dd5b',
|
||||||
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
pushEndpoint: 'https://example.com/update/same-manifest/1',
|
||||||
scope: 'https://example.net/a',
|
scope: 'https://example.net/a',
|
||||||
|
originAttributes: '',
|
||||||
version: 5
|
version: 5
|
||||||
}, {
|
}, {
|
||||||
channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
|
channelID: 'f6edfbcd-79d6-49b8-9766-48b9dcfeff0f',
|
||||||
pushEndpoint: 'https://example.com/update/same-manifest/2',
|
pushEndpoint: 'https://example.com/update/same-manifest/2',
|
||||||
scope: 'https://example.net/b',
|
scope: 'https://example.net/b',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: 42 }),
|
||||||
version: 10
|
version: 10
|
||||||
}, {
|
}, {
|
||||||
channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
|
channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
|
||||||
pushEndpoint: 'https://example.org/update/different-manifest',
|
pushEndpoint: 'https://example.org/update/different-manifest',
|
||||||
scope: 'https://example.org/c',
|
scope: 'https://example.org/c',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: 42, inBrowser: true }),
|
||||||
version: 15
|
version: 15
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -59,7 +62,7 @@ add_task(function* test_registration_success() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let registration = yield PushNotificationService.registration(
|
let registration = yield PushNotificationService.registration(
|
||||||
'https://example.net/a');
|
'https://example.net/a', '');
|
||||||
equal(
|
equal(
|
||||||
registration.pushEndpoint,
|
registration.pushEndpoint,
|
||||||
'https://example.com/update/same-manifest/1',
|
'https://example.com/update/same-manifest/1',
|
||||||
|
|
|
@ -41,17 +41,20 @@ add_task(function* test_pushNotifications() {
|
||||||
subscriptionUri: serverURL + '/subscriptionA',
|
subscriptionUri: serverURL + '/subscriptionA',
|
||||||
pushEndpoint: serverURL + '/pushEndpointA',
|
pushEndpoint: serverURL + '/pushEndpointA',
|
||||||
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointA',
|
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointA',
|
||||||
scope: 'https://example.net/a'
|
scope: 'https://example.net/a',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
}, {
|
}, {
|
||||||
subscriptionUri: serverURL + '/subscriptionB',
|
subscriptionUri: serverURL + '/subscriptionB',
|
||||||
pushEndpoint: serverURL + '/pushEndpointB',
|
pushEndpoint: serverURL + '/pushEndpointB',
|
||||||
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointB',
|
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointB',
|
||||||
scope: 'https://example.net/b'
|
scope: 'https://example.net/b',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
}, {
|
}, {
|
||||||
subscriptionUri: serverURL + '/subscriptionC',
|
subscriptionUri: serverURL + '/subscriptionC',
|
||||||
pushEndpoint: serverURL + '/pushEndpointC',
|
pushEndpoint: serverURL + '/pushEndpointC',
|
||||||
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointC',
|
pushReceiptEndpoint: serverURL + '/pushReceiptEndpointC',
|
||||||
scope: 'https://example.net/c'
|
scope: 'https://example.net/c',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false })
|
||||||
}];
|
}];
|
||||||
|
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -64,7 +67,8 @@ add_task(function* test_pushNotifications() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let registration = yield PushNotificationService.registration(
|
let registration = yield PushNotificationService.registration(
|
||||||
'https://example.net/a');
|
'https://example.net/a',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }));
|
||||||
equal(
|
equal(
|
||||||
registration.pushEndpoint,
|
registration.pushEndpoint,
|
||||||
serverURL + '/pushEndpointA',
|
serverURL + '/pushEndpointA',
|
||||||
|
|
|
@ -29,7 +29,8 @@ add_task(function* test_unregister_empty_scope() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield rejects(
|
yield rejects(
|
||||||
PushNotificationService.unregister(''),
|
PushNotificationService.unregister('',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
function(error) {
|
function(error) {
|
||||||
return error.error == 'NotFoundError';
|
return error.error == 'NotFoundError';
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,6 +20,7 @@ add_task(function* test_unregister_error() {
|
||||||
channelID: channelID,
|
channelID: channelID,
|
||||||
pushEndpoint: 'https://example.org/update/failure',
|
pushEndpoint: 'https://example.org/update/failure',
|
||||||
scope: 'https://example.net/page/failure',
|
scope: 'https://example.net/page/failure',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ add_task(function* test_unregister_error() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.net/page/failure');
|
'https://example.net/page/failure', '');
|
||||||
|
|
||||||
let result = yield db.getByKeyID(channelID);
|
let result = yield db.getByKeyID(channelID);
|
||||||
ok(!result, 'Deleted push record exists');
|
ok(!result, 'Deleted push record exists');
|
||||||
|
|
|
@ -24,11 +24,13 @@ add_task(function* test_unregister_invalid_json() {
|
||||||
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
|
channelID: '87902e90-c57e-4d18-8354-013f4a556559',
|
||||||
pushEndpoint: 'https://example.org/update/1',
|
pushEndpoint: 'https://example.org/update/1',
|
||||||
scope: 'https://example.edu/page/1',
|
scope: 'https://example.edu/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
}, {
|
}, {
|
||||||
channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
|
channelID: '057caa8f-9b99-47ff-891c-adad18ce603e',
|
||||||
pushEndpoint: 'https://example.com/update/2',
|
pushEndpoint: 'https://example.com/update/2',
|
||||||
scope: 'https://example.net/page/1',
|
scope: 'https://example.net/page/1',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
}];
|
}];
|
||||||
for (let record of records) {
|
for (let record of records) {
|
||||||
|
@ -61,13 +63,13 @@ add_task(function* test_unregister_invalid_json() {
|
||||||
// "unregister" is fire-and-forget: it's sent via _send(), not
|
// "unregister" is fire-and-forget: it's sent via _send(), not
|
||||||
// _sendRequest().
|
// _sendRequest().
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.edu/page/1');
|
'https://example.edu/page/1', '');
|
||||||
let record = yield db.getByKeyID(
|
let record = yield db.getByKeyID(
|
||||||
'87902e90-c57e-4d18-8354-013f4a556559');
|
'87902e90-c57e-4d18-8354-013f4a556559');
|
||||||
ok(!record, 'Failed to delete unregistered record');
|
ok(!record, 'Failed to delete unregistered record');
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.net/page/1');
|
'https://example.net/page/1', '');
|
||||||
record = yield db.getByKeyID(
|
record = yield db.getByKeyID(
|
||||||
'057caa8f-9b99-47ff-891c-adad18ce603e');
|
'057caa8f-9b99-47ff-891c-adad18ce603e');
|
||||||
ok(!record,
|
ok(!record,
|
||||||
|
|
|
@ -29,7 +29,8 @@ add_task(function* test_unregister_not_found() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let promise = PushNotificationService.unregister(
|
let promise = PushNotificationService.unregister(
|
||||||
'https://example.net/nonexistent');
|
'https://example.net/nonexistent',
|
||||||
|
{ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false });
|
||||||
yield rejects(promise, function(error) {
|
yield rejects(promise, function(error) {
|
||||||
return error == 'NotFoundError';
|
return error == 'NotFoundError';
|
||||||
}, 'Wrong error for nonexistent scope');
|
}, 'Wrong error for nonexistent scope');
|
||||||
|
|
|
@ -20,6 +20,7 @@ add_task(function* test_unregister_success() {
|
||||||
channelID,
|
channelID,
|
||||||
pushEndpoint: 'https://example.org/update/unregister-success',
|
pushEndpoint: 'https://example.org/update/unregister-success',
|
||||||
scope: 'https://example.com/page/unregister-success',
|
scope: 'https://example.com/page/unregister-success',
|
||||||
|
originAttributes: '',
|
||||||
version: 1
|
version: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ add_task(function* test_unregister_success() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.com/page/unregister-success');
|
'https://example.com/page/unregister-success', '');
|
||||||
let record = yield db.getByKeyID(channelID);
|
let record = yield db.getByKeyID(channelID);
|
||||||
ok(!record, 'Unregister did not remove record');
|
ok(!record, 'Unregister did not remove record');
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,8 @@ add_task(function* test_pushUnsubscriptionSuccess() {
|
||||||
subscriptionUri: serverURL + '/subscriptionUnsubscriptionSuccess',
|
subscriptionUri: serverURL + '/subscriptionUnsubscriptionSuccess',
|
||||||
pushEndpoint: serverURL + '/pushEndpointUnsubscriptionSuccess',
|
pushEndpoint: serverURL + '/pushEndpointUnsubscriptionSuccess',
|
||||||
pushReceiptEndpoint: serverURL + '/receiptPushEndpointUnsubscriptionSuccess',
|
pushReceiptEndpoint: serverURL + '/receiptPushEndpointUnsubscriptionSuccess',
|
||||||
scope: 'https://example.com/page/unregister-success'
|
scope: 'https://example.com/page/unregister-success',
|
||||||
|
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
|
||||||
});
|
});
|
||||||
|
|
||||||
PushService.init({
|
PushService.init({
|
||||||
|
@ -62,7 +63,8 @@ add_task(function* test_pushUnsubscriptionSuccess() {
|
||||||
});
|
});
|
||||||
|
|
||||||
yield PushNotificationService.unregister(
|
yield PushNotificationService.unregister(
|
||||||
'https://example.com/page/unregister-success');
|
'https://example.com/page/unregister-success',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }));
|
||||||
let record = yield db.getByKeyID(serverURL + '/subscriptionUnsubscriptionSuccess');
|
let record = yield db.getByKeyID(serverURL + '/subscriptionUnsubscriptionSuccess');
|
||||||
ok(!record, 'Unregister did not remove record');
|
ok(!record, 'Unregister did not remove record');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {PushDB, PushService, PushServiceWebSocket} = serviceExports;
|
||||||
|
|
||||||
|
const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
|
||||||
|
const channelIDs = ['0ef2ad4a-6c49-41ad-af6e-95d2425276bf', '4818b54a-97c5-4277-ad5d-0bfe630e4e50'];
|
||||||
|
var channelIDCounter = 0;
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
do_get_profile();
|
||||||
|
setPrefs({
|
||||||
|
userAgentID,
|
||||||
|
requestTimeout: 1000,
|
||||||
|
retryBaseInterval: 150
|
||||||
|
});
|
||||||
|
disableServiceWorkerEvents(
|
||||||
|
'https://example.org/1'
|
||||||
|
);
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(function* test_webapps_cleardata() {
|
||||||
|
let db = PushServiceWebSocket.newPushDB();
|
||||||
|
do_register_cleanup(() => {return db.drop().then(_ => db.close());});
|
||||||
|
|
||||||
|
PushService._generateID = () => channelID;
|
||||||
|
PushService.init({
|
||||||
|
serverURI: "wss://push.example.org",
|
||||||
|
networkInfo: new MockDesktopNetworkInfo(),
|
||||||
|
db,
|
||||||
|
makeWebSocket(uri) {
|
||||||
|
return new MockWebSocket(uri, {
|
||||||
|
onHello(data) {
|
||||||
|
equal(data.messageType, 'hello', 'Handshake: wrong message type');
|
||||||
|
equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
|
||||||
|
this.serverSendMsg(JSON.stringify({
|
||||||
|
messageType: 'hello',
|
||||||
|
status: 200,
|
||||||
|
uaid: userAgentID
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
onRegister(data) {
|
||||||
|
equal(data.messageType, 'register', 'Register: wrong message type');
|
||||||
|
this.serverSendMsg(JSON.stringify({
|
||||||
|
messageType: 'register',
|
||||||
|
status: 200,
|
||||||
|
channelID: data.channelID,
|
||||||
|
uaid: userAgentID,
|
||||||
|
pushEndpoint: 'https://example.com/update/' + Math.random(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let registers = yield Promise.all([
|
||||||
|
PushNotificationService.register(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: false })),
|
||||||
|
PushNotificationService.register(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true })),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Services.obs.notifyObservers(
|
||||||
|
{ appId: 1, browserOnly: false,
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])},
|
||||||
|
"webapps-clear-data", "");
|
||||||
|
|
||||||
|
let waitAWhile = new Promise(function(res) {
|
||||||
|
setTimeout(res, 2000);
|
||||||
|
});
|
||||||
|
yield waitAWhile;
|
||||||
|
|
||||||
|
let registration;
|
||||||
|
registration = yield PushNotificationService.registration(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: false }));
|
||||||
|
ok(!registration, 'Registration for { 1, false } should not exist.');
|
||||||
|
|
||||||
|
registration = yield PushNotificationService.registration(
|
||||||
|
'https://example.org/1',
|
||||||
|
ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true }));
|
||||||
|
ok(registration, 'Registration for { 1, true } should still exist.');
|
||||||
|
});
|
||||||
|
|
|
@ -30,6 +30,7 @@ skip-if = toolkit == 'android'
|
||||||
[test_unregister_invalid_json.js]
|
[test_unregister_invalid_json.js]
|
||||||
[test_unregister_not_found.js]
|
[test_unregister_not_found.js]
|
||||||
[test_unregister_success.js]
|
[test_unregister_success.js]
|
||||||
|
[test_webapps_cleardata.js]
|
||||||
#http2 test
|
#http2 test
|
||||||
[test_resubscribe_4xxCode_http2.js]
|
[test_resubscribe_4xxCode_http2.js]
|
||||||
[test_resubscribe_5xxCode_http2.js]
|
[test_resubscribe_5xxCode_http2.js]
|
||||||
|
|
|
@ -18,6 +18,14 @@ interface ChromeUtils : ThreadSafeChromeUtils {
|
||||||
*/
|
*/
|
||||||
static ByteString
|
static ByteString
|
||||||
originAttributesToCookieJar(optional OriginAttributesDictionary originAttrs);
|
originAttributesToCookieJar(optional OriginAttributesDictionary originAttrs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper that converts OriginAttributesDictionary to a opaque suffix string.
|
||||||
|
*
|
||||||
|
* @param originAttrs The originAttributes from the caller.
|
||||||
|
*/
|
||||||
|
static ByteString
|
||||||
|
originAttributesToSuffix(optional OriginAttributesDictionary originAttrs);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,6 +21,5 @@ interface Location {
|
||||||
[Throws, UnsafeInPrerendering]
|
[Throws, UnsafeInPrerendering]
|
||||||
void reload(optional boolean forceget = false);
|
void reload(optional boolean forceget = false);
|
||||||
};
|
};
|
||||||
// No support for .searchParams on Location yet. See bug 1082734.
|
|
||||||
|
|
||||||
Location implements URLUtils;
|
Location implements URLUtils;
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
* https://w3c.github.io/push-api/
|
* https://w3c.github.io/push-api/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
interface Principal;
|
||||||
|
|
||||||
[JSImplementation="@mozilla.org/push/PushSubscription;1",
|
[JSImplementation="@mozilla.org/push/PushSubscription;1",
|
||||||
Constructor(DOMString pushEndpoint, DOMString scope, DOMString pageURL), ChromeOnly]
|
Constructor(DOMString pushEndpoint, DOMString scope, Principal principal), ChromeOnly]
|
||||||
interface PushSubscription
|
interface PushSubscription
|
||||||
{
|
{
|
||||||
readonly attribute USVString endpoint;
|
readonly attribute USVString endpoint;
|
||||||
|
|
|
@ -51,5 +51,5 @@ interface URLUtils {
|
||||||
[NoInterfaceObject,
|
[NoInterfaceObject,
|
||||||
Exposed=(Window, Worker)]
|
Exposed=(Window, Worker)]
|
||||||
interface URLUtilsSearchParams {
|
interface URLUtilsSearchParams {
|
||||||
attribute URLSearchParams searchParams;
|
readonly attribute URLSearchParams searchParams;
|
||||||
};
|
};
|
||||||
|
|
|
@ -284,7 +284,7 @@ private:
|
||||||
nsRefPtr<ServiceWorkerManagerChild> mActor;
|
nsRefPtr<ServiceWorkerManagerChild> mActor;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS0(ServiceWorkerJob)
|
NS_IMPL_ISUPPORTS0(ServiceWorkerJob)
|
||||||
NS_IMPL_ISUPPORTS0(ServiceWorkerRegistrationInfo)
|
NS_IMPL_ISUPPORTS0(ServiceWorkerRegistrationInfo)
|
||||||
|
@ -1587,6 +1587,74 @@ ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Just holds a ref to a ServiceWorker until the Promise is fulfilled.
|
||||||
|
class KeepAliveHandler final : public PromiseNativeHandler
|
||||||
|
{
|
||||||
|
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||||
|
|
||||||
|
virtual ~KeepAliveHandler()
|
||||||
|
{}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit KeepAliveHandler(const nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
|
||||||
|
: mServiceWorker(aServiceWorker)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
workerPrivate->AssertIsOnWorkerThread();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||||
|
MOZ_ASSERT(workerPrivate);
|
||||||
|
workerPrivate->AssertIsOnWorkerThread();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a Promise if the event was successfully dispatched and no exceptions
|
||||||
|
// were raised, otherwise returns null.
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
DispatchExtendableEventOnWorkerScope(JSContext* aCx,
|
||||||
|
WorkerGlobalScope* aWorkerScope,
|
||||||
|
ExtendableEvent* aEvent)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aWorkerScope);
|
||||||
|
MOZ_ASSERT(aEvent);
|
||||||
|
nsCOMPtr<nsIGlobalObject> sgo = aWorkerScope;
|
||||||
|
WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
|
||||||
|
|
||||||
|
ErrorResult result;
|
||||||
|
result = aWorkerScope->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
|
||||||
|
if (result.Failed() || internalEvent->mFlags.mExceptionHasBeenRisen) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Promise> waitUntilPromise = aEvent->GetPromise();
|
||||||
|
if (!waitUntilPromise) {
|
||||||
|
ErrorResult result;
|
||||||
|
waitUntilPromise =
|
||||||
|
Promise::Resolve(sgo, aCx, JS::UndefinedHandleValue, result);
|
||||||
|
if (NS_WARN_IF(result.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(waitUntilPromise);
|
||||||
|
return waitUntilPromise.forget();
|
||||||
|
}
|
||||||
|
}; // anonymous namespace
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to handle ExtendableEvent::waitUntil() and proceed with
|
* Used to handle ExtendableEvent::waitUntil() and proceed with
|
||||||
* installation/activation.
|
* installation/activation.
|
||||||
|
@ -1674,23 +1742,12 @@ LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPriva
|
||||||
|
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
|
|
||||||
nsRefPtr<Promise> waitUntilPromise;
|
nsRefPtr<Promise> waitUntilPromise =
|
||||||
|
DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event);
|
||||||
ErrorResult result;
|
if (waitUntilPromise) {
|
||||||
result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
nsRefPtr<LifecycleEventPromiseHandler> handler =
|
||||||
|
new LifecycleEventPromiseHandler(mTask, mServiceWorker, false /* activateImmediately */);
|
||||||
nsCOMPtr<nsIGlobalObject> sgo = aWorkerPrivate->GlobalScope();
|
waitUntilPromise->AppendNativeHandler(handler);
|
||||||
WidgetEvent* internalEvent = event->GetInternalNSEvent();
|
|
||||||
if (!result.Failed() && !internalEvent->mFlags.mExceptionHasBeenRisen) {
|
|
||||||
waitUntilPromise = event->GetPromise();
|
|
||||||
if (!waitUntilPromise) {
|
|
||||||
ErrorResult result;
|
|
||||||
waitUntilPromise =
|
|
||||||
Promise::Resolve(sgo, aCx, JS::UndefinedHandleValue, result);
|
|
||||||
if (NS_WARN_IF(result.Failed())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Continue with a canceled install.
|
// Continue with a canceled install.
|
||||||
// Although the spec has different routines to deal with popping stuff
|
// Although the spec has different routines to deal with popping stuff
|
||||||
|
@ -1699,12 +1756,8 @@ LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPriva
|
||||||
nsRefPtr<ContinueLifecycleRunnable> r =
|
nsRefPtr<ContinueLifecycleRunnable> r =
|
||||||
new ContinueLifecycleRunnable(mTask, false /* success */, false /* activate immediately */);
|
new ContinueLifecycleRunnable(mTask, false /* success */, false /* activate immediately */);
|
||||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<LifecycleEventPromiseHandler> handler =
|
|
||||||
new LifecycleEventPromiseHandler(mTask, mServiceWorker, false /* activateImmediately */);
|
|
||||||
waitUntilPromise->AppendNativeHandler(handler);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2091,8 +2144,13 @@ public:
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
event->PostInit(mServiceWorker);
|
event->PostInit(mServiceWorker);
|
||||||
|
|
||||||
nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
|
nsRefPtr<Promise> waitUntilPromise =
|
||||||
target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(), event);
|
||||||
|
if (waitUntilPromise) {
|
||||||
|
nsRefPtr<KeepAliveHandler> handler = new KeepAliveHandler(mServiceWorker);
|
||||||
|
waitUntilPromise->AppendNativeHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2142,16 +2200,15 @@ public:
|
||||||
#endif /* ! MOZ_SIMPLEPUSH */
|
#endif /* ! MOZ_SIMPLEPUSH */
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
|
ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
|
||||||
const nsACString& aScope,
|
const nsACString& aScope,
|
||||||
const nsAString& aData,
|
const nsAString& aData)
|
||||||
JSContext* aCx)
|
|
||||||
{
|
{
|
||||||
#ifdef MOZ_SIMPLEPUSH
|
#ifdef MOZ_SIMPLEPUSH
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
#else
|
#else
|
||||||
OriginAttributes attrs;
|
OriginAttributes attrs;
|
||||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2168,7 +2225,9 @@ ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
|
||||||
new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData,
|
new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData,
|
||||||
serviceWorkerHandle);
|
serviceWorkerHandle);
|
||||||
|
|
||||||
if (NS_WARN_IF(!r->Dispatch(aCx))) {
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2177,15 +2236,14 @@ ServiceWorkerManager::SendPushEvent(JS::Handle<JS::Value> aOriginAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
ServiceWorkerManager::SendPushSubscriptionChangeEvent(JS::Handle<JS::Value> aOriginAttributes,
|
ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginAttributes,
|
||||||
const nsACString& aScope,
|
const nsACString& aScope)
|
||||||
JSContext* aCx)
|
|
||||||
{
|
{
|
||||||
#ifdef MOZ_SIMPLEPUSH
|
#ifdef MOZ_SIMPLEPUSH
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
#else
|
#else
|
||||||
OriginAttributes attrs;
|
OriginAttributes attrs;
|
||||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2201,7 +2259,9 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(JS::Handle<JS::Value> aOri
|
||||||
new SendPushSubscriptionChangeEventRunnable(
|
new SendPushSubscriptionChangeEventRunnable(
|
||||||
serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
|
serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
|
||||||
|
|
||||||
if (NS_WARN_IF(!r->Dispatch(aCx))) {
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
if (NS_WARN_IF(!r->Dispatch(jsapi.cx()))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3296,7 +3356,7 @@ public:
|
||||||
rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
|
rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
mContentPolicyType = loadInfo->GetContentPolicyType();
|
mContentPolicyType = loadInfo->InternalContentPolicyType();
|
||||||
|
|
||||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||||
if (httpChannel) {
|
if (httpChannel) {
|
||||||
|
|
|
@ -838,21 +838,6 @@ URL::SearchParams()
|
||||||
return mSearchParams;
|
return mSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
URL::SetSearchParams(URLSearchParams& aSearchParams)
|
|
||||||
{
|
|
||||||
if (mSearchParams) {
|
|
||||||
mSearchParams->RemoveObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
mSearchParams = &aSearchParams;
|
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
|
|
||||||
nsAutoString search;
|
|
||||||
mSearchParams->Serialize(search);
|
|
||||||
SetSearchInternal(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
|
URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
|
||||||
{
|
{
|
||||||
|
@ -959,7 +944,7 @@ URL::UpdateURLSearchParams()
|
||||||
nsAutoString search;
|
nsAutoString search;
|
||||||
ErrorResult rv;
|
ErrorResult rv;
|
||||||
GetSearch(search, rv);
|
GetSearch(search, rv);
|
||||||
mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)), this);
|
mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,8 +952,7 @@ void
|
||||||
URL::CreateSearchParamsIfNeeded()
|
URL::CreateSearchParamsIfNeeded()
|
||||||
{
|
{
|
||||||
if (!mSearchParams) {
|
if (!mSearchParams) {
|
||||||
mSearchParams = new URLSearchParams();
|
mSearchParams = new URLSearchParams(this);
|
||||||
mSearchParams->AddObserver(this);
|
|
||||||
UpdateURLSearchParams();
|
UpdateURLSearchParams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,8 +108,6 @@ public:
|
||||||
|
|
||||||
URLSearchParams* SearchParams();
|
URLSearchParams* SearchParams();
|
||||||
|
|
||||||
void SetSearchParams(URLSearchParams& aSearchParams);
|
|
||||||
|
|
||||||
void GetHash(nsAString& aHost, ErrorResult& aRv) const;
|
void GetHash(nsAString& aHost, ErrorResult& aRv) const;
|
||||||
|
|
||||||
void SetHash(const nsAString& aHash, ErrorResult& aRv);
|
void SetHash(const nsAString& aHash, ErrorResult& aRv);
|
||||||
|
|
|
@ -763,7 +763,14 @@ struct WorkerStructuredCloneCallbacks
|
||||||
FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership,
|
||||||
void *aContent, uint64_t aExtraData, void* aClosure)
|
void *aContent, uint64_t aExtraData, void* aClosure)
|
||||||
{
|
{
|
||||||
// Nothing to do.
|
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
|
||||||
|
MOZ_ASSERT(aClosure);
|
||||||
|
MOZ_ASSERT(!aContent);
|
||||||
|
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
|
||||||
|
|
||||||
|
MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length());
|
||||||
|
dom::MessagePort::ForceClose(closure->mMessagePortIdentifiers[aExtraData]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -116,28 +116,6 @@ onmessage = function() {
|
||||||
url.searchParams.set('e', 'f');
|
url.searchParams.set('e', 'f');
|
||||||
ok(url.href.indexOf('e=f') != 1, 'URL right');
|
ok(url.href.indexOf('e=f') != 1, 'URL right');
|
||||||
|
|
||||||
var u = new URLSearchParams();
|
|
||||||
u.append('foo', 'bar');
|
|
||||||
url.searchParams = u;
|
|
||||||
is(url.searchParams, u, "URL.searchParams is the same object");
|
|
||||||
is(url.searchParams.get('foo'), 'bar', "URL.searchParams.get('foo')");
|
|
||||||
is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
|
|
||||||
|
|
||||||
try {
|
|
||||||
url.searchParams = null;
|
|
||||||
ok(false, "URLSearchParams is not nullable");
|
|
||||||
} catch(e) {
|
|
||||||
ok(true, "URLSearchParams is not nullable");
|
|
||||||
}
|
|
||||||
|
|
||||||
var url2 = new URL('http://www.example.net?e=f');
|
|
||||||
url.searchParams = url2.searchParams;
|
|
||||||
is(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
|
|
||||||
is(url.searchParams.get('e'), 'f', "URL.searchParams.get('e')");
|
|
||||||
|
|
||||||
url.href = "http://www.example.net?bar=foo";
|
|
||||||
is(url.searchParams.get('bar'), 'foo', "URL.searchParams.get('bar')");
|
|
||||||
|
|
||||||
runTest();
|
runTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,11 +126,8 @@ onmessage = function() {
|
||||||
[ '\u0541', '%D5%81'] ];
|
[ '\u0541', '%D5%81'] ];
|
||||||
|
|
||||||
for (var i = 0; i < encoding.length; ++i) {
|
for (var i = 0; i < encoding.length; ++i) {
|
||||||
var a = new URLSearchParams();
|
|
||||||
a.set('a', encoding[i][0]);
|
|
||||||
|
|
||||||
var url = new URL('http://www.example.net');
|
var url = new URL('http://www.example.net');
|
||||||
url.searchParams = a;
|
url.searchParams.set('a', encoding[i][0]);
|
||||||
is(url.href, 'http://www.example.net/?a=' + encoding[i][1]);
|
is(url.href, 'http://www.example.net/?a=' + encoding[i][1]);
|
||||||
|
|
||||||
var url2 = new URL(url.href);
|
var url2 = new URL(url.href);
|
||||||
|
@ -162,39 +137,12 @@ onmessage = function() {
|
||||||
runTest();
|
runTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
function testMultiURL() {
|
|
||||||
var a = new URL('http://www.example.net?a=b&c=d');
|
|
||||||
var b = new URL('http://www.example.net?e=f');
|
|
||||||
ok(a.searchParams.has('a'), "a.searchParams.has('a')");
|
|
||||||
ok(a.searchParams.has('c'), "a.searchParams.has('c')");
|
|
||||||
ok(b.searchParams.has('e'), "b.searchParams.has('e')");
|
|
||||||
|
|
||||||
var u = new URLSearchParams();
|
|
||||||
a.searchParams = b.searchParams = u;
|
|
||||||
is(a.searchParams, u, "a.searchParams === u");
|
|
||||||
is(b.searchParams, u, "b.searchParams === u");
|
|
||||||
ok(!a.searchParams.has('a'), "!a.searchParams.has('a')");
|
|
||||||
ok(!a.searchParams.has('c'), "!a.searchParams.has('c')");
|
|
||||||
ok(!b.searchParams.has('e'), "!b.searchParams.has('e')");
|
|
||||||
|
|
||||||
u.append('foo', 'bar');
|
|
||||||
is(a.searchParams.get('foo'), 'bar', "a has foo=bar");
|
|
||||||
is(b.searchParams.get('foo'), 'bar', "b has foo=bar");
|
|
||||||
is(a + "", b + "", "stringify a == b");
|
|
||||||
|
|
||||||
a.search = "?bar=foo";
|
|
||||||
is(a.searchParams.get('bar'), 'foo', "a has bar=foo");
|
|
||||||
is(b.searchParams.get('bar'), 'foo', "b has bar=foo");
|
|
||||||
|
|
||||||
runTest();
|
|
||||||
}
|
|
||||||
var tests = [
|
var tests = [
|
||||||
testSimpleURLSearchParams,
|
testSimpleURLSearchParams,
|
||||||
testCopyURLSearchParams,
|
testCopyURLSearchParams,
|
||||||
testParserURLSearchParams,
|
testParserURLSearchParams,
|
||||||
testURL,
|
testURL,
|
||||||
testEncoding,
|
testEncoding,
|
||||||
testMultiURL
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function runTest() {
|
function runTest() {
|
||||||
|
|
|
@ -92,19 +92,19 @@ struct GCMethods<nsXBLMaybeCompiled<UncompiledT> >
|
||||||
|
|
||||||
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
|
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
|
||||||
|
|
||||||
static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp,
|
static bool needsPostBarrier(nsXBLMaybeCompiled<UncompiledT> function)
|
||||||
nsXBLMaybeCompiled<UncompiledT> prev,
|
|
||||||
nsXBLMaybeCompiled<UncompiledT> next)
|
|
||||||
{
|
{
|
||||||
if (next.IsCompiled()) {
|
return function.IsCompiled() && Base::needsPostBarrier(function.GetJSFunction());
|
||||||
Base::postBarrier(&functionp->UnsafeGetJSFunction(),
|
}
|
||||||
prev.IsCompiled() ? prev.UnsafeGetJSFunction() : nullptr,
|
|
||||||
next.UnsafeGetJSFunction());
|
static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp)
|
||||||
} else if (prev.IsCompiled()) {
|
{
|
||||||
Base::postBarrier(&prev.UnsafeGetJSFunction(),
|
Base::postBarrier(&functionp->UnsafeGetJSFunction());
|
||||||
prev.UnsafeGetJSFunction(),
|
}
|
||||||
nullptr);
|
|
||||||
}
|
static void relocate(nsXBLMaybeCompiled<UncompiledT>* functionp)
|
||||||
|
{
|
||||||
|
Base::relocate(&functionp->UnsafeGetJSFunction());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -457,6 +457,17 @@ private:
|
||||||
double mY;
|
double mY;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
CairoPatternAddGradientStop(cairo_pattern_t* aPattern,
|
||||||
|
const GradientStop &aStop,
|
||||||
|
Float aNudge = 0)
|
||||||
|
{
|
||||||
|
cairo_pattern_add_color_stop_rgba(aPattern, aStop.offset + aNudge,
|
||||||
|
aStop.color.r, aStop.color.g, aStop.color.b,
|
||||||
|
aStop.color.a);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Never returns nullptr. As such, you must always pass in Cairo-compatible
|
// Never returns nullptr. As such, you must always pass in Cairo-compatible
|
||||||
// patterns, most notably gradients with a GradientStopCairo.
|
// patterns, most notably gradients with a GradientStopCairo.
|
||||||
// The pattern returned must have cairo_pattern_destroy() called on it by the
|
// The pattern returned must have cairo_pattern_destroy() called on it by the
|
||||||
|
@ -465,7 +476,9 @@ private:
|
||||||
// lifetime of the cairo_pattern_t returned must not exceed the lifetime of the
|
// lifetime of the cairo_pattern_t returned must not exceed the lifetime of the
|
||||||
// Pattern passed in.
|
// Pattern passed in.
|
||||||
static cairo_pattern_t*
|
static cairo_pattern_t*
|
||||||
GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha)
|
GfxPatternToCairoPattern(const Pattern& aPattern,
|
||||||
|
Float aAlpha,
|
||||||
|
const Matrix& aTransform)
|
||||||
{
|
{
|
||||||
cairo_pattern_t* pat;
|
cairo_pattern_t* pat;
|
||||||
const Matrix* matrix = nullptr;
|
const Matrix* matrix = nullptr;
|
||||||
|
@ -512,11 +525,25 @@ GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha)
|
||||||
matrix = &pattern.mMatrix;
|
matrix = &pattern.mMatrix;
|
||||||
|
|
||||||
const std::vector<GradientStop>& stops = cairoStops->GetStops();
|
const std::vector<GradientStop>& stops = cairoStops->GetStops();
|
||||||
|
if (stops.size() >= 2 && stops.front().offset == stops.back().offset) {
|
||||||
|
// Certain Cairo backends that use pixman to implement gradients can have jagged
|
||||||
|
// edges occur with hard stops. Such hard stops are used for implementing certain
|
||||||
|
// types of CSS borders. Work around this by turning these hard-stops into half-pixel
|
||||||
|
// gradients to anti-alias them. See bug 1033375
|
||||||
|
Matrix patternToDevice = aTransform * pattern.mMatrix;
|
||||||
|
Float gradLength = (patternToDevice * pattern.mEnd - patternToDevice * pattern.mBegin).Length();
|
||||||
|
if (gradLength > 0) {
|
||||||
|
Float aaOffset = 0.25 / gradLength;
|
||||||
|
CairoPatternAddGradientStop(pat, stops.front(), -aaOffset);
|
||||||
|
for (size_t i = 1; i < stops.size()-1; ++i) {
|
||||||
|
CairoPatternAddGradientStop(pat, stops[i]);
|
||||||
|
}
|
||||||
|
CairoPatternAddGradientStop(pat, stops.back(), aaOffset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (size_t i = 0; i < stops.size(); ++i) {
|
for (size_t i = 0; i < stops.size(); ++i) {
|
||||||
const GradientStop& stop = stops[i];
|
CairoPatternAddGradientStop(pat, stops[i]);
|
||||||
cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r,
|
|
||||||
stop.color.g, stop.color.b,
|
|
||||||
stop.color.a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -536,10 +563,7 @@ GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha)
|
||||||
|
|
||||||
const std::vector<GradientStop>& stops = cairoStops->GetStops();
|
const std::vector<GradientStop>& stops = cairoStops->GetStops();
|
||||||
for (size_t i = 0; i < stops.size(); ++i) {
|
for (size_t i = 0; i < stops.size(); ++i) {
|
||||||
const GradientStop& stop = stops[i];
|
CairoPatternAddGradientStop(pat, stops[i]);
|
||||||
cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r,
|
|
||||||
stop.color.g, stop.color.b,
|
|
||||||
stop.color.a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -892,7 +916,7 @@ DrawTargetCairo::DrawPattern(const Pattern& aPattern,
|
||||||
|
|
||||||
AutoClearDeviceOffset clear(aPattern);
|
AutoClearDeviceOffset clear(aPattern);
|
||||||
|
|
||||||
cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha);
|
cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha, GetTransform());
|
||||||
if (!pat) {
|
if (!pat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1174,7 +1198,7 @@ DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
|
||||||
ScaledFontBase* scaledFont = static_cast<ScaledFontBase*>(aFont);
|
ScaledFontBase* scaledFont = static_cast<ScaledFontBase*>(aFont);
|
||||||
cairo_set_scaled_font(mContext, scaledFont->GetCairoScaledFont());
|
cairo_set_scaled_font(mContext, scaledFont->GetCairoScaledFont());
|
||||||
|
|
||||||
cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha);
|
cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha, GetTransform());
|
||||||
if (!pat)
|
if (!pat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1213,12 +1237,12 @@ DrawTargetCairo::Mask(const Pattern &aSource,
|
||||||
|
|
||||||
cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
|
cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
|
||||||
|
|
||||||
cairo_pattern_t* source = GfxPatternToCairoPattern(aSource, aOptions.mAlpha);
|
cairo_pattern_t* source = GfxPatternToCairoPattern(aSource, aOptions.mAlpha, GetTransform());
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_pattern_t* mask = GfxPatternToCairoPattern(aMask, aOptions.mAlpha);
|
cairo_pattern_t* mask = GfxPatternToCairoPattern(aMask, aOptions.mAlpha, GetTransform());
|
||||||
if (!mask) {
|
if (!mask) {
|
||||||
cairo_pattern_destroy(source);
|
cairo_pattern_destroy(source);
|
||||||
return;
|
return;
|
||||||
|
@ -1254,7 +1278,7 @@ DrawTargetCairo::MaskSurface(const Pattern &aSource,
|
||||||
|
|
||||||
cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
|
cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
|
||||||
|
|
||||||
cairo_pattern_t* pat = GfxPatternToCairoPattern(aSource, aOptions.mAlpha);
|
cairo_pattern_t* pat = GfxPatternToCairoPattern(aSource, aOptions.mAlpha, GetTransform());
|
||||||
if (!pat) {
|
if (!pat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,6 @@
|
||||||
#include "GLContext.h"
|
#include "GLContext.h"
|
||||||
#include "GLLibraryEGL.h"
|
#include "GLLibraryEGL.h"
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
|
||||||
#include "HwcComposer2D.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class nsIWidget;
|
class nsIWidget;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -128,9 +124,6 @@ protected:
|
||||||
bool mIsDoubleBuffered;
|
bool mIsDoubleBuffered;
|
||||||
bool mCanBindToTexture;
|
bool mCanBindToTexture;
|
||||||
bool mShareWithEGLImage;
|
bool mShareWithEGLImage;
|
||||||
#ifdef MOZ_WIDGET_GONK
|
|
||||||
nsRefPtr<HwcComposer2D> mHwc;
|
|
||||||
#endif
|
|
||||||
bool mOwnsContext;
|
bool mOwnsContext;
|
||||||
|
|
||||||
static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
|
static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
|
#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
|
||||||
#elif defined(MOZ_WIDGET_GONK)
|
#elif defined(MOZ_WIDGET_GONK)
|
||||||
#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
|
#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
|
||||||
#include "HwcComposer2D.h"
|
|
||||||
#include "libdisplay/GonkDisplay.h"
|
#include "libdisplay/GonkDisplay.h"
|
||||||
#include "nsWindow.h"
|
#include "nsWindow.h"
|
||||||
#include "nsScreenManagerGonk.h"
|
#include "nsScreenManagerGonk.h"
|
||||||
|
|
|
@ -183,6 +183,9 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||||
if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {
|
if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {
|
||||||
AppendToString(aStream, m.GetScrollParentId(), "] [scrollParent=");
|
AppendToString(aStream, m.GetScrollParentId(), "] [scrollParent=");
|
||||||
}
|
}
|
||||||
|
if (m.IsRootContent()) {
|
||||||
|
aStream << "] [rcd";
|
||||||
|
}
|
||||||
if (m.HasClipRect()) {
|
if (m.HasClipRect()) {
|
||||||
AppendToString(aStream, m.ClipRect(), "] [clip=");
|
AppendToString(aStream, m.ClipRect(), "] [clip=");
|
||||||
}
|
}
|
||||||
|
@ -202,8 +205,8 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
|
||||||
m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(),
|
m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(),
|
||||||
m.GetScrollGeneration()).get();
|
m.GetScrollGeneration()).get();
|
||||||
AppendToString(aStream, m.GetScrollParentId(), "] [p=");
|
AppendToString(aStream, m.GetScrollParentId(), "] [p=");
|
||||||
aStream << nsPrintfCString("] [i=(%ld %lld)] }",
|
aStream << nsPrintfCString("] [i=(%ld %lld %d)] }",
|
||||||
m.GetPresShellId(), m.GetScrollId()).get();
|
m.GetPresShellId(), m.GetScrollId(), m.IsRootContent()).get();
|
||||||
}
|
}
|
||||||
aStream << sfx;
|
aStream << sfx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,11 +217,6 @@ public:
|
||||||
MonitorAutoLock lock(mMonitor);
|
MonitorAutoLock lock(mMonitor);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// XXX(seth): The queue popping code below is NOT efficient, obviously,
|
|
||||||
// since we're removing an element from the front of the array. However,
|
|
||||||
// it's not worth implementing something better right now, because we are
|
|
||||||
// replacing this FIFO behavior with LIFO behavior very soon.
|
|
||||||
|
|
||||||
// Prioritize size decodes over full decodes.
|
// Prioritize size decodes over full decodes.
|
||||||
if (!mSizeDecodeQueue.IsEmpty()) {
|
if (!mSizeDecodeQueue.IsEmpty()) {
|
||||||
return PopWorkFromQueue(mSizeDecodeQueue);
|
return PopWorkFromQueue(mSizeDecodeQueue);
|
||||||
|
@ -249,8 +244,8 @@ private:
|
||||||
{
|
{
|
||||||
Work work;
|
Work work;
|
||||||
work.mType = Work::Type::DECODE;
|
work.mType = Work::Type::DECODE;
|
||||||
work.mDecoder = aQueue.ElementAt(0);
|
work.mDecoder = aQueue.LastElement();
|
||||||
aQueue.RemoveElementAt(0);
|
aQueue.RemoveElementAt(aQueue.Length() - 1);
|
||||||
|
|
||||||
return work;
|
return work;
|
||||||
}
|
}
|
||||||
|
|
|
@ -588,6 +588,17 @@ BackgroundParentImpl::DeallocPMessagePortParent(PMessagePortParent* aActor)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BackgroundParentImpl::RecvMessagePortForceClose(const nsID& aUUID,
|
||||||
|
const nsID& aDestinationUUID,
|
||||||
|
const uint32_t& aSequenceID)
|
||||||
|
{
|
||||||
|
AssertIsInMainProcess();
|
||||||
|
AssertIsOnBackgroundThread();
|
||||||
|
|
||||||
|
return MessagePortParent::ForceClose(aUUID, aDestinationUUID, aSequenceID);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче