import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1173641 - Hoist shutdown promise resolution into a helper. r=jww (1a02bd90a)
- Bug 1173641 - Null out the thread pool when resolving shutdown. r=jww (ab3f723d5)
- Bug 1173641 - Remove now-unnecessary null-out in MediaDecoderReader::BreakCycles. r=jww (3330778c6)
- Bug 1173656 - Disallow TrackID reuse in TrackUnionStream. r=roc (7f4da1ea2)
- Bug 1175768 - Implement SilentReadAt. r=jya (ece3c2ffa)
- Bug 1178437 - Assert OnTaskQueue for most of the remaining MDSM methods. r=jww (da13ec549)
- Bug 1178437 - Remove ReadOnWrongThread. r=jww (f9cf8946d)
- Bug 1178437 - Dispatch SetFragmentEndTime. r=jww (740ce9882)
- Bug 1178437 - Make mRealTime const and allow it to be accessed on any thread. r=jww (a65c22f1f)
- Bug 1139964 part 1. Factor out the guts of BackstagePass::Resolve and BackstagePass::Enumerate to allow reuse for other globals that want to opt in to Exposed=System WebIDL annotations. r=smaug (d5eb8c704)
- Bug 1139964 part 2. Add classinfo helpers for the various message manager stuff to install WebIDL Exposed=System things on those globals. r=smaug (47085f2a6)
- Bug 1139964 part 3. Add a test. r=bzbarsky (d87e0907b)
- Bug 1130028 - Custom elements, set registered prototype in compartment of caller of registerElement. r=mrbkap (5bd643614)
- Bug 1130028 - Send inputmethod-contextchange to systemapp to hide keyboard when frame crash. r=yxl (1e100121f)
- Bug 1156629 - OpenGL core context deprecated default VAO. r=jgilbert (5ecabb650)
-  Bug 1110120 - Remove use of UniquePtr for XFB and UB tracking.; r=smaug (92ebc132a)
- Bug 1167504 - Part 11: Clean up buffer binding constraints. r=jgilbert (4f3005203)
- Bug 1167504 - Part 13: Unbind buffers from cached state on buffer deletion. r=jgilbert (bb9e3f53d)
- Bug 1180523 - Part 1: Store the audio mute/volume information on the outer window; r=baku (3b686c6b9)
- line endings dos->unix (d7491a87c)
- Bug 1153258 - directly instantiate nsStandardURL in nsChromeProtocolHandler.cpp; r=bsmedberg (01150c663)
- Bug 1175344 - Include nsContentUtils.h explicitly to avoid compile error on unified building. r=ehsan (10a3d42ac)
- Bug 959752 - Make the network predictor work under e10s. r=mcmanus (3b46a6b65)
- Bug 1159747 - delete h2 static compression table in such a way to avoid crashes after network changes. r=mcmanus (ed34f8d80)
- Bug 1173016 - Cache the basic waveform PeriodicWaves. r=karlt (d64c962f0)
- part of Bug 1165816 - Cancel remote application reputation requests after a certain timeout. r=gcp (4cdc98d99)
- Bug 1082837 - Call content policies on cached image redirects in imgLoader::ValidateSecurityInfo. Content policies check the last hop (final uri) of the cached image. For Mixed Content Blocker, we do an additional check to see if any of the intermediary hops went through an insecure redirect. r=smaug, feedback=seth (ffaf3debe)
- Bug 1082837 - Use nsresult for static ShouldLoad and use NS_IMETHODIMP for nsIContentPolicy::ShouldLoad(). CLOSED TREE (acde35e25)
This commit is contained in:
2021-04-13 09:40:42 +08:00
parent aa4b6876ee
commit 3d36fa43e7
67 changed files with 1749 additions and 586 deletions
@@ -1,139 +1,139 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIEHistoryEnumerator.h"
#include <urlhist.h>
#include <shlguid.h>
#include "nsStringAPI.h"
#include "nsNetUtil.h"
#include "nsIVariant.h"
#include "nsCOMArray.h"
#include "nsArrayEnumerator.h"
namespace {
PRTime FileTimeToPRTime(FILETIME* filetime)
{
SYSTEMTIME st;
::FileTimeToSystemTime(filetime, &st);
PRExplodedTime prt;
prt.tm_year = st.wYear;
// SYSTEMTIME's day-of-month parameter is 1-based,
// PRExplodedTime's is 0-based.
prt.tm_month = st.wMonth - 1;
prt.tm_mday = st.wDay;
prt.tm_hour = st.wHour;
prt.tm_min = st.wMinute;
prt.tm_sec = st.wSecond;
prt.tm_usec = st.wMilliseconds * 1000;
prt.tm_wday = 0;
prt.tm_yday = 0;
prt.tm_params.tp_gmt_offset = 0;
prt.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&prt);
}
} // Anonymous namespace.
////////////////////////////////////////////////////////////////////////////////
//// nsIEHistoryEnumerator
NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator)
nsIEHistoryEnumerator::nsIEHistoryEnumerator()
{
::CoInitialize(nullptr);
}
nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
{
::CoUninitialize();
}
void
nsIEHistoryEnumerator::EnsureInitialized()
{
if (mURLEnumerator)
return;
HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUrlHistoryStg2,
getter_AddRefs(mIEHistory));
if (FAILED(hr))
return;
hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator));
if (FAILED(hr))
return;
}
NS_IMETHODIMP
nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
{
*_retval = false;
EnsureInitialized();
MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator");
if (!mURLEnumerator)
return NS_OK;
STATURL statURL;
ULONG fetched;
// First argument is not implemented, so doesn't matter what we pass.
HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched);
if (FAILED(hr) || fetched != 1UL) {
// Reached the last entry.
return NS_OK;
}
nsCOMPtr<nsIURI> uri;
if (statURL.pwcsUrl) {
nsDependentString url(statURL.pwcsUrl);
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
::CoTaskMemFree(statURL.pwcsUrl);
if (NS_FAILED(rv)) {
// Got a corrupt or invalid URI, continue to the next entry.
return HasMoreElements(_retval);
}
}
nsDependentString title(statURL.pwcsTitle);
PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
if (mCachedNextEntry) {
mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
*_retval = true;
}
if (statURL.pwcsTitle)
::CoTaskMemFree(statURL.pwcsTitle);
return NS_OK;
}
NS_IMETHODIMP
nsIEHistoryEnumerator::GetNext(nsISupports** _retval)
{
*_retval = nullptr;
if (!mCachedNextEntry)
return NS_ERROR_FAILURE;
NS_ADDREF(*_retval = mCachedNextEntry);
// Release the cached entry, so it can't be returned twice.
mCachedNextEntry = nullptr;
return NS_OK;
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIEHistoryEnumerator.h"
#include <urlhist.h>
#include <shlguid.h>
#include "nsStringAPI.h"
#include "nsNetUtil.h"
#include "nsIVariant.h"
#include "nsCOMArray.h"
#include "nsArrayEnumerator.h"
namespace {
PRTime FileTimeToPRTime(FILETIME* filetime)
{
SYSTEMTIME st;
::FileTimeToSystemTime(filetime, &st);
PRExplodedTime prt;
prt.tm_year = st.wYear;
// SYSTEMTIME's day-of-month parameter is 1-based,
// PRExplodedTime's is 0-based.
prt.tm_month = st.wMonth - 1;
prt.tm_mday = st.wDay;
prt.tm_hour = st.wHour;
prt.tm_min = st.wMinute;
prt.tm_sec = st.wSecond;
prt.tm_usec = st.wMilliseconds * 1000;
prt.tm_wday = 0;
prt.tm_yday = 0;
prt.tm_params.tp_gmt_offset = 0;
prt.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&prt);
}
} // Anonymous namespace.
////////////////////////////////////////////////////////////////////////////////
//// nsIEHistoryEnumerator
NS_IMPL_ISUPPORTS(nsIEHistoryEnumerator, nsISimpleEnumerator)
nsIEHistoryEnumerator::nsIEHistoryEnumerator()
{
::CoInitialize(nullptr);
}
nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
{
::CoUninitialize();
}
void
nsIEHistoryEnumerator::EnsureInitialized()
{
if (mURLEnumerator)
return;
HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IUrlHistoryStg2,
getter_AddRefs(mIEHistory));
if (FAILED(hr))
return;
hr = mIEHistory->EnumUrls(getter_AddRefs(mURLEnumerator));
if (FAILED(hr))
return;
}
NS_IMETHODIMP
nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
{
*_retval = false;
EnsureInitialized();
MOZ_ASSERT(mURLEnumerator, "Should have instanced an IE History URLEnumerator");
if (!mURLEnumerator)
return NS_OK;
STATURL statURL;
ULONG fetched;
// First argument is not implemented, so doesn't matter what we pass.
HRESULT hr = mURLEnumerator->Next(1, &statURL, &fetched);
if (FAILED(hr) || fetched != 1UL) {
// Reached the last entry.
return NS_OK;
}
nsCOMPtr<nsIURI> uri;
if (statURL.pwcsUrl) {
nsDependentString url(statURL.pwcsUrl);
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
::CoTaskMemFree(statURL.pwcsUrl);
if (NS_FAILED(rv)) {
// Got a corrupt or invalid URI, continue to the next entry.
return HasMoreElements(_retval);
}
}
nsDependentString title(statURL.pwcsTitle);
PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
if (mCachedNextEntry) {
mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
*_retval = true;
}
if (statURL.pwcsTitle)
::CoTaskMemFree(statURL.pwcsTitle);
return NS_OK;
}
NS_IMETHODIMP
nsIEHistoryEnumerator::GetNext(nsISupports** _retval)
{
*_retval = nullptr;
if (!mCachedNextEntry)
return NS_ERROR_FAILURE;
NS_ADDREF(*_retval = mCachedNextEntry);
// Release the cached entry, so it can't be returned twice.
mCachedNextEntry = nullptr;
return NS_OK;
}
+6 -9
View File
@@ -24,6 +24,7 @@
#include "nsIStandardURL.h"
#include "nsNetUtil.h"
#include "nsString.h"
#include "nsStandardURL.h"
////////////////////////////////////////////////////////////////////////////////
@@ -69,32 +70,28 @@ nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
nsIURI *aBaseURI,
nsIURI **result)
{
nsresult rv;
// Chrome: URLs (currently) have no additional structure beyond that provided
// by standard URLs, so there is no "outer" given to CreateInstance
nsCOMPtr<nsIStandardURL> surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsStandardURL> surl = new nsStandardURL();
rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI);
nsresult rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec,
aCharset, aBaseURI);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(surl, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// Canonify the "chrome:" URL; e.g., so that we collapse
// "chrome://navigator/content/" and "chrome://navigator/content"
// and "chrome://navigator/content/navigator.xul".
rv = nsChromeRegistry::Canonify(url);
rv = nsChromeRegistry::Canonify(surl);
if (NS_FAILED(rv))
return rv;
surl->SetMutable(false);
NS_ADDREF(*result = url);
surl.forget(result);
return NS_OK;
}
+6 -2
View File
@@ -422,12 +422,16 @@ Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
CustomElementData* data = GetCustomElementData();
if (obj && data) {
// If this is a registered custom element then fix the prototype.
JSAutoCompartment ac(aCx, obj);
nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
JS::Rooted<JSObject*> prototype(aCx);
document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &prototype);
if (prototype) {
if (!JS_WrapObject(aCx, &prototype) || !JS_SetPrototype(aCx, obj, prototype)) {
// We want to set the custom prototype in the compartment where it was
// registered. In the case that |obj| and |prototype| are in different
// compartments, this will set the prototype on the |obj|'s wrapper and
// thus only visible in the wrapper's compartment.
JSAutoCompartment ac(aCx, prototype);
if (!JS_WrapObject(aCx, &obj) || !JS_SetPrototype(aCx, obj, prototype)) {
dom::Throw(aCx, NS_ERROR_FAILURE);
return nullptr;
}
+45 -2
View File
@@ -257,11 +257,15 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager,
nsMessageManagerSH<nsEventTargetSH>,
DOM_DEFAULT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_ENUMERATE |
nsIXPCScriptable::IS_GLOBAL_OBJECT)
NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager, nsDOMGenericSH,
NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager,
nsMessageManagerSH<nsDOMGenericSH>,
DOM_DEFAULT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_ENUMERATE |
nsIXPCScriptable::IS_GLOBAL_OBJECT)
NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -2576,3 +2580,42 @@ nsNonDOMObjectSH::GetFlags(uint32_t *aFlags)
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY | nsIClassInfo::SINGLETON_CLASSINFO;
return NS_OK;
}
// nsContentFrameMessageManagerSH
template<typename Super>
NS_IMETHODIMP
nsMessageManagerSH<Super>::Resolve(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj_,
jsid id_, bool* resolvedp,
bool* _retval)
{
JS::Rooted<JSObject*> obj(cx, obj_);
JS::Rooted<jsid> id(cx, id_);
*_retval = SystemGlobalResolve(cx, obj, id, resolvedp);
NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
if (*resolvedp) {
return NS_OK;
}
return Super::Resolve(wrapper, cx, obj, id, resolvedp, _retval);
}
template<typename Super>
NS_IMETHODIMP
nsMessageManagerSH<Super>::Enumerate(nsIXPConnectWrappedNative* wrapper,
JSContext* cx, JSObject* obj_,
bool* _retval)
{
JS::Rooted<JSObject*> obj(cx, obj_);
*_retval = SystemGlobalEnumerate(cx, obj);
NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
// Don't call up to our superclass, since neither nsDOMGenericSH nor
// nsEventTargetSH have WANT_ENUMERATE.
MOZ_ASSERT(!(this->GetScriptableFlags() & nsIXPCScriptable::WANT_ENUMERATE));
return NS_OK;
}
+25
View File
@@ -311,4 +311,29 @@ public:
}
};
template<typename Super>
class nsMessageManagerSH : public Super
{
protected:
explicit nsMessageManagerSH(nsDOMClassInfoData* aData)
: Super(aData)
{
}
virtual ~nsMessageManagerSH()
{
}
public:
NS_IMETHOD Resolve(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* obj_, jsid id_, bool* resolvedp,
bool* _retval) override;
NS_IMETHOD Enumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* obj_, bool* _retval) override;
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsMessageManagerSH(aData);
}
};
#endif /* nsDOMClassInfo_h___ */
+1
View File
@@ -10,6 +10,7 @@
* via XMLHttpRequest).
*/
#include "nsContentUtils.h"
#include "nsDataDocumentContentPolicy.h"
#include "nsNetUtil.h"
#include "nsScriptSecurityManager.h"
+70 -44
View File
@@ -6172,16 +6172,30 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
int32_t namespaceID = kNameSpaceID_XHTML;
JS::Rooted<JSObject*> protoObject(aCx);
{
JSAutoCompartment ac(aCx, global);
JS::Rooted<JSObject*> htmlProto(aCx);
JS::Rooted<JSObject*> svgProto(aCx);
{
JSAutoCompartment ac(aCx, global);
JS::Handle<JSObject*> htmlProto(
HTMLElementBinding::GetProtoObjectHandle(aCx, global));
if (!htmlProto) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx, global);
if (!htmlProto) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
svgProto = SVGElementBinding::GetProtoObjectHandle(aCx, global);
if (!svgProto) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
if (!aOptions.mPrototype) {
if (!JS_WrapObject(aCx, &htmlProto)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
if (!protoObject) {
rv.Throw(NS_ERROR_UNEXPECTED);
@@ -6190,19 +6204,11 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
} else {
protoObject = aOptions.mPrototype;
// We are already operating on the document's (/global's) compartment. Let's
// get a view of the passed in proto from this compartment.
if (!JS_WrapObject(aCx, &protoObject)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
// We also need an unwrapped version of it for various checks.
JS::Rooted<JSObject*> protoObjectUnwrapped(aCx,
js::CheckedUnwrap(protoObject));
// Get the unwrapped prototype to do some checks.
JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
if (!protoObjectUnwrapped) {
// If the documents compartment does not have same origin access
// to the compartment of the proto we should just throw.
// If the caller's compartment does not have permission to access the
// unwrapped prototype then throw.
rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -6218,7 +6224,7 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
JS::Rooted<JSPropertyDescriptor> descRoot(aCx);
JS::MutableHandle<JSPropertyDescriptor> desc(&descRoot);
// This check will go through a wrapper, but as we checked above
// This check may go through a wrapper, but as we checked above
// it should be transparent or an xray. This should be fine for now,
// until the spec is sorted out.
if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
@@ -6231,15 +6237,13 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
return;
}
JS::Handle<JSObject*> svgProto(
SVGElementBinding::GetProtoObjectHandle(aCx, global));
if (!svgProto) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
JS::Rooted<JSObject*> protoProto(aCx, protoObject);
if (!JS_WrapObject(aCx, &htmlProto) || !JS_WrapObject(aCx, &svgProto)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
JS::Rooted<JSObject*> protoProto(aCx, protoObject);
// If PROTOTYPE's interface inherits from SVGElement, set NAMESPACE to SVG
// Namespace.
while (protoProto) {
@@ -6257,7 +6261,7 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
return;
}
}
}
} // Done with the checks, leave prototype's compartment.
// If name was provided and not null...
if (!lcName.IsEmpty()) {
@@ -6295,22 +6299,25 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
}
} // Leaving the document's compartment for the LifecycleCallbacks init
JS::Rooted<JSObject*> wrappedProto(aCx, protoObject);
if (!JS_WrapObject(aCx, &wrappedProto)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
// Note: We call the init from the caller compartment here
nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks());
JS::RootedValue rootedv(aCx, JS::ObjectValue(*protoObject));
JS::RootedValue rootedv(aCx, JS::ObjectValue(*wrappedProto));
if (!JS_WrapValue(aCx, &rootedv) || !callbacksHolder->Init(aCx, rootedv)) {
rv.Throw(NS_ERROR_FAILURE);
return;
}
// Entering the global's compartment again
JSAutoCompartment ac(aCx, global);
// Associate the definition with the custom element.
CustomElementHashKey key(namespaceID, typeAtom);
LifecycleCallbacks* callbacks = callbacksHolder.forget();
CustomElementDefinition* definition =
new CustomElementDefinition(protoObject,
new CustomElementDefinition(wrappedProto,
typeAtom,
nameAtom,
callbacks,
@@ -6343,9 +6350,13 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
CallQueryInterface(elem, &cache);
MOZ_ASSERT(cache, "Element doesn't support wrapper cache?");
// We want to set the custom prototype in the caller's comparment.
// In the case that element is in a different compartment,
// this will set the prototype on the element's wrapper and
// thus only visible in the wrapper's compartment.
JS::RootedObject wrapper(aCx);
if ((wrapper = cache->GetWrapper())) {
if (!JS_SetPrototype(aCx, wrapper, protoObject)) {
if ((wrapper = cache->GetWrapper()) && JS_WrapObject(aCx, &wrapper)) {
if (!JS_SetPrototype(aCx, wrapper, wrappedProto)) {
continue;
}
}
@@ -6354,23 +6365,38 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
}
}
// Create constructor to return. Store the name of the custom element as the
// name of the function.
JSFunction* constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
JSFUN_CONSTRUCTOR,
NS_ConvertUTF16toUTF8(lcType).get());
if (!constructor) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
JS::Rooted<JSFunction*> constructor(aCx);
{
// Go into the document's global compartment when creating the constructor
// function because we want to get the correct document (where the
// definition is registered) when it is called.
JSAutoCompartment ac(aCx, global);
// Create constructor to return. Store the name of the custom element as the
// name of the function.
constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
JSFUN_CONSTRUCTOR,
NS_ConvertUTF16toUTF8(lcType).get());
if (!constructor) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
JS::Rooted<JSObject*> constructorObj(aCx, JS_GetFunctionObject(constructor));
if (!JS_LinkConstructorAndPrototype(aCx, constructorObj, protoObject)) {
JS::Rooted<JSObject*> wrappedConstructor(aCx);
wrappedConstructor = JS_GetFunctionObject(constructor);
if (!JS_WrapObject(aCx, &wrappedConstructor)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
aRetval.set(constructorObj);
if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
aRetval.set(wrappedConstructor);
}
void
+2 -1
View File
@@ -403,7 +403,8 @@ protected:
CandidateMap;
// Hashtable for custom element definitions in web components.
// Custom prototypes are in the document's compartment.
// Custom prototypes are stored in the compartment where
// registerElement was called.
DefinitionMap mCustomDefinitions;
// The "upgrade candidates map" from the web components spec. Maps from a
+9 -9
View File
@@ -3694,8 +3694,8 @@ nsPIDOMWindow::CreatePerformanceObjectIfNeeded()
bool
nsPIDOMWindow::GetAudioMuted() const
{
if (!IsInnerWindow()) {
return mInnerWindow->GetAudioMuted();
if (IsInnerWindow()) {
return mOuterWindow->GetAudioMuted();
}
return mAudioMuted;
@@ -3704,8 +3704,8 @@ nsPIDOMWindow::GetAudioMuted() const
void
nsPIDOMWindow::SetAudioMuted(bool aMuted)
{
if (!IsInnerWindow()) {
mInnerWindow->SetAudioMuted(aMuted);
if (IsInnerWindow()) {
mOuterWindow->SetAudioMuted(aMuted);
return;
}
@@ -3720,8 +3720,8 @@ nsPIDOMWindow::SetAudioMuted(bool aMuted)
float
nsPIDOMWindow::GetAudioVolume() const
{
if (!IsInnerWindow()) {
return mInnerWindow->GetAudioVolume();
if (IsInnerWindow()) {
return mOuterWindow->GetAudioVolume();
}
return mAudioVolume;
@@ -3730,8 +3730,8 @@ nsPIDOMWindow::GetAudioVolume() const
nsresult
nsPIDOMWindow::SetAudioVolume(float aVolume)
{
if (!IsInnerWindow()) {
return mInnerWindow->SetAudioVolume(aVolume);
if (IsInnerWindow()) {
return mOuterWindow->SetAudioVolume(aVolume);
}
if (aVolume < 0.0) {
@@ -3779,7 +3779,7 @@ nsPIDOMWindow::RefreshMediaElements()
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
service->RefreshAgentsVolume(this);
service->RefreshAgentsVolume(GetCurrentInnerWindow());
}
// nsISpeechSynthesisGetter
+6
View File
@@ -16,8 +16,11 @@ support-files =
file_bug990812-3.xul
file_bug990812-4.xul
file_bug990812-5.xul
file_bug1139964.xul
fileconstructor_file.png
frame_bug814638.xul
frame_registerElement_content.html
registerElement_ep.js
host_bug814638.xul
window_nsITextInputProcessor.xul
title_window.xul
@@ -59,10 +62,13 @@ skip-if = buildapp == 'mulet'
[test_bug914381.html]
[test_bug990812.xul]
[test_bug1063837.xul]
[test_bug1139964.xul]
[test_bug1346936.html]
[test_cpows.xul]
skip-if = buildapp == 'mulet'
[test_document_register.xul]
[test_registerElement_content.xul]
[test_registerElement_ep.xul]
[test_domparsing.xul]
[test_fileconstructor.xul]
[test_fileconstructor_tempfile.xul]
+62
View File
@@ -0,0 +1,62 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1139964
-->
<window title="Mozilla Bug 1139964"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="run()">
<label value="Mozilla Bug 1139964"/>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
var Cc = Components.classes;
var Ci = Components.interfaces;
var ppm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageBroadcaster);
function ok(cond, msg) {
opener.wrappedJSObject.ok(cond, msg);
}
var msgName = "TEST:Global_has_Promise";
function mmScriptForPromiseTest() {
sendAsyncMessage("TEST:Global_has_Promise",
{
hasPromise: ("Promise" in this),
hasTextEncoder: ("TextEncoder" in this),
hasWindow: ("Window" in this),
});
}
function processListener(m) {
ppm.removeMessageListener(msgName, processListener);
ok(m.data.hasPromise, "ProcessGlobal should have Promise object in the global scope!");
ok(m.data.hasTextEncoder, "ProcessGlobal should have TextEncoder object in the global scope!");
ok(!m.data.hasWindow, "ProcessGlobal should not have Window object in the global scope!");
messageManager.addMessageListener(msgName, tabListener)
messageManager.loadFrameScript("data:,(" + mmScriptForPromiseTest.toString() + ")()", true);
}
function tabListener(m) {
messageManager.removeMessageListener(msgName, tabListener);
ok(m.data.hasPromise, "TabChildGlobal should have Promise object in the global scope!");
ok(m.data.hasTextEncoder, "TabChildGlobal should have TextEncoder object in the global scope!");
ok(!m.data.hasWindow, "TabChildGlobal should not have Window object in the global scope!");
opener.setTimeout("done()", 0);
window.close();
}
function run() {
ppm.addMessageListener(msgName, processListener)
ppm.loadProcessScript("data:,(" + mmScriptForPromiseTest.toString() + ")()", true);
}
]]></script>
<browser type="content" src="about:blank" id="ifr"/>
</window>
@@ -0,0 +1,5 @@
<html>
<body>
<x-bar></x-bar>
</body>
</html>
@@ -0,0 +1,8 @@
var proto = Object.create(HTMLElement.prototype);
proto.magicNumber = 42;
proto.createdCallback = function() {
finishTest(this.magicNumber === 42);
};
document.registerElement("x-foo", { prototype: proto });
document.createElement("x-foo");
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1139964
-->
<window title="Mozilla Bug 1139964"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1139964"
target="_blank">Mozilla Bug 1139964</a>
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
/** Test for Bug 1139964 **/
SimpleTest.waitForExplicitFinish();
function done() {
SimpleTest.finish();
}
addLoadEvent(function() {
window.open("file_bug1139964.xul", "", "chrome");
});
]]></script>
</window>
@@ -0,0 +1,55 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
-->
<window title="Mozilla Bug 1130028"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
target="_blank">Mozilla Bug 1130028</a>
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
/** Test for Bug 1130028 **/
SimpleTest.waitForExplicitFinish();
var createdCallbackCount = 0;
// Callback should be called once by element created in chrome,
// and once by element created in content.
function createdCallbackCalled() {
createdCallbackCount++;
ok(true, "Created callback called, should be called twice in test.");
is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
if (createdCallbackCount == 2) {
SimpleTest.finish();
}
}
function startTests() {
var frame = $("frame");
var c = frame.contentDocument.registerElement("x-foo");
var elem = new c();
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
proto.magicNumber = 42;
proto.createdCallback = createdCallbackCalled;
frame.contentDocument.registerElement("x-bar", { prototype: proto });
frame.contentDocument.createElement("x-bar");
}
]]></script>
</window>
@@ -0,0 +1,44 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
-->
<window title="Mozilla Bug 1130028"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
target="_blank">Mozilla Bug 1130028</a>
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
Components.utils.import("resource://gre/modules/Services.jsm");
/** Test for Bug 1130028 **/
SimpleTest.waitForExplicitFinish();
function finishTest(canSeePrototype) {
ok(true, "createdCallback called when reigsterElement was called with an extended principal.");
ok(canSeePrototype, "createdCallback should be able to see custom prototype.");
SimpleTest.finish();
}
function startTests() {
var frame = $("frame");
// Create a sandbox with an extended principal then run a script that registers a custom element in the sandbox.
var sandbox = Components.utils.Sandbox([frame.contentWindow], { sandboxPrototype: frame.contentWindow });
sandbox.finishTest = finishTest;
Services.scriptloader.loadSubScript("chrome://mochitests/content/chrome/dom/base/test/chrome/registerElement_ep.js", sandbox);
}
]]></script>
</window>
+18 -3
View File
@@ -78,10 +78,25 @@ function runTest() {
utils.audioVolume = 0;
is(utils.audioVolume, 0.0, "utils.audioVolume is ok");
utils.audioVolume = 1.0;
is(utils.audioVolume, 1.0, "utils.audioVolume is ok");
utils.audioVolume = 0.6;
is(utils.audioVolume.toFixed(2), "0.60", "utils.audioVolume is ok");
utils.audioMuted = true;
SimpleTest.finish();
// Navigate the iframe to another URL, and verify that the volume and muted
// information is preserved.
iframe.onload = function() {
utils = SpecialPowers.wrap(iframe.contentWindow).
QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
ok(utils, "nsIDOMWindowUtils");
ok(utils.audioMuted, "Audio should still be muted");
utils.audioMuted = false;
ok(utils.audioVolume.toFixed(2), "0.60", "Volume should be preserved");
SimpleTest.finish();
};
iframe.src = "data:text/html,page";
}
SpecialPowers.pushPrefEnv({ "set": [["media.useAudioChannelService", true]]}, runTest);
+32
View File
@@ -43,6 +43,7 @@
#include "mozilla/dom/HTMLEmbedElementBinding.h"
#include "mozilla/dom/HTMLAppletElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ResolveSystemBinding.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "WorkerPrivate.h"
#include "nsDOMClassInfo.h"
@@ -2374,6 +2375,10 @@ bool
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId, bool* aResolvedp)
{
MOZ_ASSERT(JS_IsGlobalObject(aObj),
"Should have a global here, since we plan to resolve standard "
"classes!");
return JS_ResolveStandardClass(aCx, aObj, aId, aResolvedp);
}
@@ -2386,6 +2391,10 @@ MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj)
bool
EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
MOZ_ASSERT(JS_IsGlobalObject(aObj),
"Should have a global here, since we plan to enumerate standard "
"classes!");
return JS_EnumerateStandardClasses(aCx, aObj);
}
@@ -2801,5 +2810,28 @@ UnwrapArgImpl(JS::Handle<JSObject*> src,
return wrappedJS->QueryInterface(iid, ppArg);
}
bool
SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, bool* resolvedp)
{
if (!ResolveGlobal(cx, obj, id, resolvedp)) {
return false;
}
if (*resolvedp) {
return true;
}
return ResolveSystemBinding(cx, obj, id, resolvedp);
}
bool
SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj)
{
bool ignored = false;
return EnumerateGlobal(cx, obj) &&
ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
}
} // namespace dom
} // namespace mozilla
+11
View File
@@ -3252,6 +3252,17 @@ GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
return JS_GetErrorPrototype(aCx);
}
// Resolve an id on the given global object that wants to be included in
// Exposed=System webidl annotations. False return value means exception
// thrown.
bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
JS::Handle<jsid> id, bool* resolvedp);
// Enumerate all ids on the given global object that wants to be included in
// Exposed=System webidl annotations. False return value means exception
// thrown.
bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
// A callback to perform funToString on an interface object
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
-1
View File
@@ -33,7 +33,6 @@ private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;
virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) override;
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
-16
View File
@@ -35,22 +35,6 @@ WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
return false;
}
/** Buffer and Target validation for BindBuffer */
bool
WebGL1Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
const char* info)
{
if (!buffer)
return true;
if (buffer->HasEverBeenBound() && target != buffer->Target()) {
ErrorInvalidOperation("%s: buffer already bound to a different target", info);
return false;
}
return true;
}
bool
WebGL1Context::ValidateBufferUsageEnum(GLenum usage, const char* info)
{
+2 -6
View File
@@ -161,15 +161,11 @@ WebGLContext::InitWebGL2()
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
&mGLMaxUniformBufferBindings);
mBoundTransformFeedbackBuffers =
MakeUnique<WebGLRefPtr<WebGLBuffer>[]>(mGLMaxTransformFeedbackSeparateAttribs);
mBoundUniformBuffers =
MakeUnique<WebGLRefPtr<WebGLBuffer>[]>(mGLMaxUniformBufferBindings);
mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;
auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
mBoundTransformFeedbackBuffers.reset(xfBuffers);
mBypassShaderValidation = true;
-1
View File
@@ -371,7 +371,6 @@ private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;
virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) override;
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
+20 -31
View File
@@ -45,36 +45,6 @@ WebGL2Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
}
}
bool
WebGL2Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
const char* info)
{
if (!buffer)
return true;
switch (target) {
case LOCAL_GL_COPY_READ_BUFFER:
case LOCAL_GL_COPY_WRITE_BUFFER:
return true;
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
return !buffer->HasEverBeenBound() ||
buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER;
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_PIXEL_PACK_BUFFER:
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
case LOCAL_GL_UNIFORM_BUFFER:
return !buffer->HasEverBeenBound() ||
buffer->Target() != LOCAL_GL_ELEMENT_ARRAY_BUFFER;
}
ErrorInvalidOperation("%s: buffer already bound to a incompatible target %s",
info, EnumName(buffer->Target()));
return false;
}
bool
WebGL2Context::ValidateBufferUsageEnum(GLenum usage, const char* info)
{
@@ -123,7 +93,7 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
if (!readBuffer)
return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget");
const WebGLBuffer* writeBuffer = writeBufferSlot.get();
WebGLBuffer* writeBuffer = writeBufferSlot.get();
if (!writeBuffer)
return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget");
@@ -145,8 +115,27 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
return;
}
WebGLBuffer::Kind readType = readBuffer->Content();
WebGLBuffer::Kind writeType = writeBuffer->Content();
if (readType != WebGLBuffer::Kind::Undefined &&
writeType != WebGLBuffer::Kind::Undefined &&
writeType != readType)
{
ErrorInvalidOperation("copyBufferSubData: Can't copy %s data to %s data",
(readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
(writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
return;
}
WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset,
writeOffset, size);
if (writeType == WebGLBuffer::Kind::Undefined) {
writeBuffer->BindTo(
(readType == WebGLBuffer::Kind::OtherData) ? LOCAL_GL_ARRAY_BUFFER
: LOCAL_GL_ELEMENT_ARRAY_BUFFER);
}
}
void
+31 -22
View File
@@ -15,7 +15,7 @@ namespace mozilla {
WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
: WebGLContextBoundObject(webgl)
, mGLName(buf)
, mTarget(LOCAL_GL_NONE)
, mContent(Kind::Undefined)
, mByteLength(0)
{
mContext->mBuffers.insertBack(this);
@@ -26,6 +26,34 @@ WebGLBuffer::~WebGLBuffer()
DeleteOnce();
}
void
WebGLBuffer::BindTo(GLenum target)
{
switch (target) {
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
mContent = Kind::ElementArray;
if (!mCache)
mCache = new WebGLElementArrayCache;
break;
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_PIXEL_PACK_BUFFER:
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
case LOCAL_GL_UNIFORM_BUFFER:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
mContent = Kind::OtherData;
break;
case LOCAL_GL_COPY_READ_BUFFER:
case LOCAL_GL_COPY_WRITE_BUFFER:
/* Do nothing. Doesn't set the type of the buffer contents. */
break;
default:
MOZ_CRASH();
}
}
void
WebGLBuffer::Delete()
{
@@ -36,30 +64,11 @@ WebGLBuffer::Delete()
LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
}
void
WebGLBuffer::BindTo(GLenum target)
{
MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE.");
MOZ_ASSERT(!HasEverBeenBound() || mTarget == target, "Rebinding is illegal.");
bool targetChanged = (target != mTarget);
mTarget = target;
if (targetChanged)
OnTargetChanged();
}
void
WebGLBuffer::OnTargetChanged()
{
if (!mCache && mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
mCache = new WebGLElementArrayCache;
}
bool
WebGLBuffer::ElementArrayCacheBufferData(const void* ptr,
size_t bufferSizeInBytes)
{
if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
if (mContent == Kind::ElementArray)
return mCache->BufferData(ptr, bufferSizeInBytes);
return true;
@@ -69,7 +78,7 @@ void
WebGLBuffer::ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
size_t updateSizeInBytes)
{
if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
if (mContent == Kind::ElementArray)
mCache->BufferSubData(pos, ptr, updateSizeInBytes);
}
+11 -8
View File
@@ -25,8 +25,18 @@ class WebGLBuffer final
, public WebGLContextBoundObject
{
public:
enum class Kind {
Undefined,
ElementArray,
OtherData
};
explicit WebGLBuffer(WebGLContext* webgl, GLuint buf);
void BindTo(GLenum target);
Kind Content() const { return mContent; }
void Delete();
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
@@ -39,10 +49,6 @@ public:
void ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
size_t updateSizeInBytes);
void BindTo(GLenum target);
bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
GLenum Target() const { return mTarget; }
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
uint32_t* const out_upperBound);
@@ -62,10 +68,7 @@ public:
protected:
~WebGLBuffer();
void OnTargetChanged();
GLenum mTarget;
Kind mContent;
WebGLsizeiptr mByteLength;
nsAutoPtr<WebGLElementArrayCache> mCache;
};
+2 -8
View File
@@ -343,14 +343,8 @@ WebGLContext::DestroyResourcesAndContext()
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
if (mBoundTransformFeedbackBuffers) {
for (GLuint i = 0; i < mGLMaxTransformFeedbackSeparateAttribs; i++) {
mBoundTransformFeedbackBuffers[i] = nullptr;
}
}
for (GLuint i = 0; i < mGLMaxUniformBufferBindings; i++)
mBoundUniformBuffers[i] = nullptr;
mBoundTransformFeedbackBuffers.Clear();
mBoundUniformBuffers.Clear();
while (!mTextures.isEmpty())
mTextures.getLast()->DeleteOnce();
+5 -3
View File
@@ -937,13 +937,15 @@ protected:
WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
WebGLRefPtr<WebGLBuffer> mBoundUniformBuffer;
UniquePtr<WebGLRefPtr<WebGLBuffer>[]> mBoundUniformBuffers;
UniquePtr<WebGLRefPtr<WebGLBuffer>[]> mBoundTransformFeedbackBuffers;
nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundUniformBuffers;
nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundTransformFeedbackBuffers;
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
GLuint index);
GLenum GetCurrentBinding(WebGLBuffer* buffer) const;
// -----------------------------------------------------------------------------
// Queries (WebGL2ContextQueries.cpp)
protected:
@@ -1400,7 +1402,7 @@ private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) = 0;
virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info);
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) = 0;
virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
+157 -25
View File
@@ -20,24 +20,7 @@ WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
if (!buffer)
return;
/* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
*
* In the WebGL 2 API, buffers have their WebGL buffer type
* initially set to undefined. Calling bindBuffer, bindBufferRange
* or bindBufferBase with the target argument set to any buffer
* binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
* then set the WebGL buffer type of the buffer being bound
* according to the table above.
*
* Any call to one of these functions which attempts to bind a
* WebGLBuffer that has the element array WebGL buffer type to a
* binding point that falls under other data, or bind a
* WebGLBuffer which has the other data WebGL buffer type to
* ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
* and the state of the binding point will remain untouched.
*/
if (target != LOCAL_GL_COPY_READ_BUFFER && target != LOCAL_GL_COPY_WRITE_BUFFER)
buffer->BindTo(target);
buffer->BindTo(target);
}
void
@@ -424,12 +407,50 @@ WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
if (!buffer || buffer->IsDeleted())
return;
if (mBoundArrayBuffer == buffer)
BindBuffer(LOCAL_GL_ARRAY_BUFFER, static_cast<WebGLBuffer*>(nullptr));
// TODO: Extract this into a helper function?
if (mBoundArrayBuffer == buffer) {
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr);
mBoundArrayBuffer = nullptr;
}
if (mBoundVertexArray->mElementArrayBuffer == buffer) {
BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER,
static_cast<WebGLBuffer*>(nullptr));
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr);
mBoundVertexArray->mElementArrayBuffer = nullptr;
}
// WebGL binding points
if (IsWebGL2()) {
if (mBoundCopyReadBuffer == buffer)
mBoundCopyReadBuffer = nullptr;
if (mBoundCopyWriteBuffer == buffer)
mBoundCopyWriteBuffer = nullptr;
if (mBoundPixelPackBuffer == buffer)
mBoundPixelPackBuffer = nullptr;
if (mBoundPixelUnpackBuffer == buffer)
mBoundPixelUnpackBuffer = nullptr;
if (mBoundTransformFeedbackBuffer == buffer)
mBoundTransformFeedbackBuffer = nullptr;
if (mBoundUniformBuffer == buffer)
mBoundUniformBuffer = nullptr;
const size_t xfBufferCount = mBoundTransformFeedbackBuffers.Length();
for (size_t n = 0; n < xfBufferCount; n++) {
if (mBoundTransformFeedbackBuffers[n] == buffer) {
mBoundTransformFeedbackBuffers[n] = nullptr;
}
}
const size_t uniformBufferCount = mBoundUniformBuffers.Length();
for (size_t n = 0; n < uniformBufferCount; n++) {
if (mBoundUniformBuffers[n] == buffer) {
mBoundUniformBuffers[n] = nullptr;
}
}
}
for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
@@ -449,9 +470,89 @@ WebGLContext::IsBuffer(WebGLBuffer* buffer)
if (IsContextLost())
return false;
return ValidateObjectAllowDeleted("isBuffer", buffer) &&
!buffer->IsDeleted() &&
buffer->HasEverBeenBound();
if (!ValidateObjectAllowDeleted("isBuffer", buffer))
return false;
if (buffer->IsDeleted())
return false;
MakeContextCurrent();
return gl->fIsBuffer(buffer->mGLName);
}
bool
WebGLContext::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
const char* info)
{
if (!buffer)
return true;
/* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
*
* In the WebGL 2 API, buffers have their WebGL buffer type
* initially set to undefined. Calling bindBuffer, bindBufferRange
* or bindBufferBase with the target argument set to any buffer
* binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
* then set the WebGL buffer type of the buffer being bound
* according to the table above.
*
* Any call to one of these functions which attempts to bind a
* WebGLBuffer that has the element array WebGL buffer type to a
* binding point that falls under other data, or bind a
* WebGLBuffer which has the other data WebGL buffer type to
* ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
* and the state of the binding point will remain untouched.
*/
GLenum boundTo = GetCurrentBinding(buffer);
if (boundTo != LOCAL_GL_NONE) {
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
boundTo != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER)
{
ErrorInvalidOperation("Can't bind buffer to TRANSFORM_FEEDBACK_BUFFER as the "
"buffer is already bound to another bind point.");
return false;
}
else if (target != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
boundTo == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER)
{
ErrorInvalidOperation("Can't bind buffer to bind point as it is currently "
"bound to TRANSFORM_FEEDBACK_BUFFER.");
return false;
}
}
WebGLBuffer::Kind content = buffer->Content();
if (content == WebGLBuffer::Kind::Undefined)
return true;
switch (target) {
case LOCAL_GL_COPY_READ_BUFFER:
case LOCAL_GL_COPY_WRITE_BUFFER:
return true;
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
if (content == WebGLBuffer::Kind::ElementArray)
return true;
break;
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_PIXEL_PACK_BUFFER:
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
case LOCAL_GL_UNIFORM_BUFFER:
if (content == WebGLBuffer::Kind::OtherData)
return true;
break;
default:
MOZ_CRASH();
}
ErrorInvalidOperation("%s: buffer already contains %s data.", info,
content == WebGLBuffer::Kind::OtherData ? "other" : "element");
return false;
}
bool
@@ -524,6 +625,37 @@ WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index)
}
}
GLenum
WebGLContext::GetCurrentBinding(WebGLBuffer* buffer) const
{
if (mBoundArrayBuffer == buffer)
return LOCAL_GL_ARRAY_BUFFER;
if (mBoundCopyReadBuffer == buffer)
return LOCAL_GL_COPY_READ_BUFFER;
if (mBoundCopyWriteBuffer == buffer)
return LOCAL_GL_COPY_WRITE_BUFFER;
if (mBoundPixelPackBuffer == buffer)
return LOCAL_GL_PIXEL_PACK_BUFFER;
if (mBoundPixelUnpackBuffer == buffer)
return LOCAL_GL_PIXEL_UNPACK_BUFFER;
if (mBoundTransformFeedbackBuffer == buffer ||
mBoundTransformFeedbackBuffers.Contains(buffer)) {
return LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER;
}
if (mBoundUniformBuffer == buffer ||
mBoundUniformBuffers.Contains(buffer)) {
return LOCAL_GL_UNIFORM_BUFFER;
}
return LOCAL_GL_NONE;
}
GLenum
WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size,
const GLvoid* data, GLenum usage)
+1 -2
View File
@@ -126,8 +126,7 @@ WebGLMemoryTracker::GetBufferCacheMemoryUsed()
buffer;
buffer = buffer->getNext())
{
if (buffer->HasEverBeenBound() &&
buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
if (buffer->Content() == WebGLBuffer::Kind::ElementArray) {
result += buffer->SizeOfIncludingThis(WebGLBufferMallocSizeOf);
}
}
+11
View File
@@ -38,6 +38,17 @@ void
WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size)
{
gl->MakeCurrent();
#ifdef XP_MACOSX
if (buffer && buffer->Content() == WebGLBuffer::Kind::Undefined &&
gl->WorkAroundDriverBugs())
{
// BindBufferRange will fail if the buffer's contents is undefined.
// Bind so driver initializes the buffer.
gl->fBindBuffer(target, buffer->mGLName);
}
#endif
gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
}
+19 -2
View File
@@ -266,8 +266,10 @@ WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset
MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
bool separate = (readOffset + size < writeOffset || writeOffset + size < readOffset);
if (!separate)
ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, writeOffset + size) overlap");
if (!separate) {
ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, "
"writeOffset + size) overlap", info);
}
return separate;
}
@@ -1951,6 +1953,21 @@ WebGLContext::InitAndValidateGL()
mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
mBoundVertexArray = mDefaultVertexArray;
// OpenGL core profiles remove the default VAO object from version
// 4.0.0. We create a default VAO for all core profiles,
// regardless of version.
//
// GL Spec 4.0.0:
// (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
// in Section E.2.2 "Removed Features", pg 397: "[...] The default
// vertex array object (the name zero) is also deprecated. [...]"
if (gl->IsCoreProfile()) {
MakeContextCurrent();
mDefaultVertexArray->GenVertexArray();
mDefaultVertexArray->BindVertexArray();
}
if (mLoseContextOnMemoryPressure)
mContextObserver->RegisterMemoryPressureEvent();
+5
View File
@@ -115,6 +115,11 @@ this.Keyboard = {
// The application has been closed unexpectingly. Let's tell the
// keyboard app that the focus has been lost.
this.sendToKeyboard('Keyboard:FocusChange', { 'type': 'blur' });
// Notify system app to hide keyboard.
SystemAppProxy.dispatchEvent({
type: 'inputmethod-contextchange',
inputType: 'blur'
});
}
} else {
// Ignore notifications that aren't from a BrowserOrApp
+1 -2
View File
@@ -1161,8 +1161,7 @@ void MediaDecoder::SetFragmentEndTime(double aTime)
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoderStateMachine) {
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mDecoderStateMachine->SetFragmentEndTime(static_cast<int64_t>(aTime * USECS_PER_S));
mDecoderStateMachine->DispatchSetFragmentEndTime(static_cast<int64_t>(aTime * USECS_PER_S));
}
}
+5 -3
View File
@@ -174,11 +174,11 @@ MediaDecoderReader::GetBuffered()
NS_ENSURE_TRUE(mStartTime >= 0, media::TimeIntervals());
AutoPinned<MediaResource> stream(mDecoder->GetResource());
if (!mDuration.ReadOnWrongThread().isSome()) {
if (!mDuration.Ref().isSome()) {
return TimeIntervals();
}
return GetEstimatedBufferedTimeRanges(stream, mDuration.ReadOnWrongThread().ref().ToMicroseconds());
return GetEstimatedBufferedTimeRanges(stream, mDuration.Ref().ref().ToMicroseconds());
}
nsRefPtr<MediaDecoderReader::MetadataPromise>
@@ -339,7 +339,9 @@ MediaDecoderReader::RequestAudioData()
void
MediaDecoderReader::BreakCycles()
{
mTaskQueue = nullptr;
// Nothing left to do here these days. We keep this method around so that, if
// we need it, we don't have to make all of the subclass implementations call
// the superclass method again.
}
nsRefPtr<ShutdownPromise>
+2 -12
View File
@@ -1382,11 +1382,6 @@ void MediaDecoderStateMachine::VolumeChanged()
}
}
bool MediaDecoderStateMachine::IsRealTime() const
{
return mRealTime;
}
void MediaDecoderStateMachine::RecomputeDuration()
{
MOZ_ASSERT(OnTaskQueue());
@@ -1419,13 +1414,6 @@ void MediaDecoderStateMachine::RecomputeDuration()
mDuration = Some(duration);
}
void MediaDecoderStateMachine::SetFragmentEndTime(int64_t aEndTime)
{
AssertCurrentThreadInMonitor();
mFragmentEndTime = aEndTime < 0 ? aEndTime : aEndTime;
}
bool MediaDecoderStateMachine::IsDormantNeeded()
{
return mReader->IsDormantNeeded();
@@ -2795,6 +2783,7 @@ int64_t MediaDecoderStateMachine::GetStreamClock() const
int64_t MediaDecoderStateMachine::GetVideoStreamPosition() const
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
if (!IsPlaying()) {
@@ -3153,6 +3142,7 @@ void MediaDecoderStateMachine::StartBuffering()
void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
mPlayStartTime = aTimeStamp;
if (!mAudioSink) {
+14 -8
View File
@@ -145,11 +145,6 @@ public:
DECODER_STATE_ERROR
};
State GetState() {
AssertCurrentThreadInMonitor();
return mState;
}
DecodedStreamData* GetDecodedStream() const;
void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
@@ -191,7 +186,8 @@ public:
void FinishShutdown();
bool IsRealTime() const;
// Immutable after construction - may be called on any thread.
bool IsRealTime() const { return mRealTime; }
// Functions used by assertions to ensure we're calling things
// on the appropriate threads.
@@ -231,6 +227,7 @@ public:
// This is called on the state machine thread and audio thread.
// The decoder monitor must be obtained before calling this.
bool HasAudio() const {
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
return mInfo.HasAudio();
}
@@ -238,6 +235,7 @@ public:
// This is called on the state machine thread and audio thread.
// The decoder monitor must be obtained before calling this.
bool HasVideo() const {
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
return mInfo.HasVideo();
}
@@ -306,7 +304,14 @@ public:
void NotReached() { MOZ_DIAGNOSTIC_ASSERT(false); }
// Set the media fragment end time. aEndTime is in microseconds.
void SetFragmentEndTime(int64_t aEndTime);
void DispatchSetFragmentEndTime(int64_t aEndTime)
{
nsRefPtr<MediaDecoderStateMachine> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aEndTime] () {
self->mFragmentEndTime = aEndTime;
});
TaskQueue()->Dispatch(r.forget());
}
// Drop reference to decoder. Only called during shutdown dance.
void BreakCycles() {
@@ -584,6 +589,7 @@ protected:
// not start at 0. Note this is different than the "current playback position",
// which is in the range [0,duration].
int64_t GetMediaTime() const {
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
return mCurrentPosition;
}
@@ -715,7 +721,7 @@ private:
WatchManager<MediaDecoderStateMachine> mWatchManager;
// True is we are decoding a realtime stream, like a camera stream.
bool mRealTime;
const bool mRealTime;
// True if we've dispatched a task to run the state machine but the task has
// yet to run.
+52
View File
@@ -751,6 +751,29 @@ nsresult ChannelMediaResource::ReadAt(int64_t aOffset,
return rv;
}
already_AddRefed<MediaByteBuffer>
ChannelMediaResource::SilentReadAt(int64_t aOffset, uint32_t aCount)
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
bool ok = bytes->SetCapacity(aCount, fallible);
NS_ENSURE_TRUE(ok, nullptr);
int64_t pos = mCacheStream.Tell();
char* curr = reinterpret_cast<char*>(bytes->Elements());
while (aCount > 0) {
uint32_t bytesRead;
nsresult rv = mCacheStream.ReadAt(aOffset, curr, aCount, &bytesRead);
NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_TRUE(bytesRead > 0, nullptr);
aOffset += bytesRead;
aCount -= bytesRead;
curr += bytesRead;
}
mCacheStream.Seek(nsISeekableStream::NS_SEEK_SET, pos);
return bytes.forget();
}
nsresult ChannelMediaResource::Seek(int32_t aWhence, int64_t aOffset)
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
@@ -1183,6 +1206,7 @@ public:
virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) override;
virtual nsresult ReadAt(int64_t aOffset, char* aBuffer,
uint32_t aCount, uint32_t* aBytes) override;
virtual already_AddRefed<MediaByteBuffer> SilentReadAt(int64_t aOffset, uint32_t aCount) override;
virtual nsresult Seek(int32_t aWhence, int64_t aOffset) override;
virtual int64_t Tell() override;
@@ -1502,6 +1526,34 @@ nsresult FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
return rv;
}
already_AddRefed<MediaByteBuffer>
FileMediaResource::SilentReadAt(int64_t aOffset, uint32_t aCount)
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
MutexAutoLock lock(mLock);
nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
bool ok = bytes->SetCapacity(aCount, fallible);
NS_ENSURE_TRUE(ok, nullptr);
int64_t pos = 0;
NS_ENSURE_TRUE(mSeekable, nullptr);
nsresult rv = mSeekable->Tell(&pos);
NS_ENSURE_SUCCESS(rv, nullptr);
rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
NS_ENSURE_SUCCESS(rv, nullptr);
char* curr = reinterpret_cast<char*>(bytes->Elements());
while (aCount > 0) {
uint32_t bytesRead;
rv = UnsafeRead(curr, aCount, &bytesRead);
NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_TRUE(bytesRead > 0, nullptr);
aCount -= bytesRead;
curr += bytesRead;
}
UnsafeSeek(nsISeekableStream::NS_SEEK_SET, pos);
return bytes.forget();
}
nsresult FileMediaResource::Seek(int32_t aWhence, int64_t aOffset)
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
+30
View File
@@ -9,6 +9,7 @@
#include "mozilla/Mutex.h"
#include "nsIChannel.h"
#include "nsIURI.h"
#include "nsISeekableStream.h"
#include "nsIStreamingProtocolController.h"
#include "nsIStreamListener.h"
#include "nsIChannelEventSink.h"
@@ -288,6 +289,34 @@ public:
// results and requirements are the same as per the Read method.
virtual nsresult ReadAt(int64_t aOffset, char* aBuffer,
uint32_t aCount, uint32_t* aBytes) = 0;
// ReadAt without side-effects. Given that our MediaResource infrastructure
// is very side-effecty, this accomplishes its job by checking the initial
// position and seeking back to it. If the seek were to fail, a side-effect
// might be observable.
//
// This method returns null if anything fails, including the failure to read
// aCount bytes. Otherwise, it returns an owned buffer.
virtual already_AddRefed<MediaByteBuffer> SilentReadAt(int64_t aOffset, uint32_t aCount)
{
nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
bool ok = bytes->SetCapacity(aCount, fallible);
NS_ENSURE_TRUE(ok, nullptr);
int64_t pos = Tell();
char* curr = reinterpret_cast<char*>(bytes->Elements());
while (aCount > 0) {
uint32_t bytesRead;
nsresult rv = ReadAt(aOffset, curr, aCount, &bytesRead);
NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_TRUE(bytesRead > 0, nullptr);
aOffset += bytesRead;
aCount -= bytesRead;
curr += bytesRead;
}
Seek(nsISeekableStream::NS_SEEK_SET, pos);
return bytes.forget();
}
// Seek to the given bytes offset in the stream. aWhence can be
// one of:
// NS_SEEK_SET
@@ -599,6 +628,7 @@ public:
virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) override;
virtual nsresult ReadAt(int64_t offset, char* aBuffer,
uint32_t aCount, uint32_t* aBytes) override;
virtual already_AddRefed<MediaByteBuffer> SilentReadAt(int64_t aOffset, uint32_t aCount) override;
virtual nsresult Seek(int32_t aWhence, int64_t aOffset) override;
virtual int64_t Tell() override;
+4 -5
View File
@@ -168,9 +168,7 @@ MediaTaskQueue::BeginShutdown()
MonitorAutoLock mon(mQueueMonitor);
mIsShutdown = true;
nsRefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
if (!mIsRunning) {
mShutdownPromise.Resolve(true, __func__);
}
MaybeResolveShutdown();
mon.NotifyAll();
return p;
}
@@ -238,7 +236,7 @@ MediaTaskQueue::Runner::Run()
MOZ_ASSERT(mQueue->mIsRunning);
if (mQueue->mTasks.size() == 0) {
mQueue->mIsRunning = false;
mQueue->mShutdownPromise.ResolveIfExists(true, __func__);
mQueue->MaybeResolveShutdown();
mon.NotifyAll();
return NS_OK;
}
@@ -269,7 +267,7 @@ MediaTaskQueue::Runner::Run()
if (mQueue->mTasks.size() == 0) {
// No more events to run. Exit the task runner.
mQueue->mIsRunning = false;
mQueue->mShutdownPromise.ResolveIfExists(true, __func__);
mQueue->MaybeResolveShutdown();
mon.NotifyAll();
return NS_OK;
}
@@ -286,6 +284,7 @@ MediaTaskQueue::Runner::Run()
MonitorAutoLock mon(mQueue->mQueueMonitor);
mQueue->mIsRunning = false;
mQueue->mIsShutdown = true;
mQueue->MaybeResolveShutdown();
mon.NotifyAll();
}
+9
View File
@@ -85,6 +85,15 @@ protected:
DispatchFailureHandling aFailureHandling,
DispatchReason aReason = NormalDispatch);
void MaybeResolveShutdown()
{
mQueueMonitor.AssertCurrentThreadOwns();
if (mIsShutdown && !mIsRunning) {
mShutdownPromise.ResolveIfExists(true, __func__);
mPool = nullptr;
}
}
RefPtr<SharedThreadPool> mPool;
// Monitor that protects the queue and mIsRunning;
-8
View File
@@ -166,9 +166,6 @@ private:
return mValue;
}
// Temporary workaround for misbehaving code.
const T& ReadOnWrongThread() { return mValue; }
void Set(const T& aNewValue)
{
MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
@@ -247,7 +244,6 @@ public:
// Access to the T.
const T& Ref() const { return *mImpl; }
const T& ReadOnWrongThread() const { return mImpl->ReadOnWrongThread(); }
operator const T&() const { return Ref(); }
void Set(const T& aNewValue) { mImpl->Set(aNewValue); }
Canonical& operator=(const T& aNewValue) { Set(aNewValue); return *this; }
@@ -305,9 +301,6 @@ private:
return mValue;
}
// Temporary workaround for naughty code.
const T& ReadOnWrongThread() { return mValue; }
virtual void UpdateValue(const T& aNewValue) override
{
MOZ_ASSERT(OwnerThread()->IsCurrentThreadIn());
@@ -372,7 +365,6 @@ public:
// Access to the T.
const T& Ref() const { return *mImpl; }
const T& ReadOnWrongThread() const { return mImpl->ReadOnWrongThread(); }
operator const T&() const { return Ref(); }
private:
+16 -16
View File
@@ -46,7 +46,7 @@ PRLogModuleInfo* gTrackUnionStreamLog;
#define STREAM_LOG(type, msg) MOZ_LOG(gTrackUnionStreamLog, type, msg)
TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
ProcessedMediaStream(aWrapper)
ProcessedMediaStream(aWrapper), mNextAvailableTrackID(1)
{
if (!gTrackUnionStreamLog) {
gTrackUnionStreamLog = PR_NewLogModule("TrackUnionStream");
@@ -161,23 +161,23 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
GraphTime aFrom)
{
// Use the ID of the source track if it's not already assigned to a track,
// otherwise allocate a new unique ID.
TrackID id = aTrack->GetID();
TrackID maxTrackID = 0;
for (uint32_t i = 0; i < mTrackMap.Length(); ++i) {
TrackID outID = mTrackMap[i].mOutputTrackID;
maxTrackID = std::max(maxTrackID, outID);
}
// Note: we might have removed it here, but it might still be in the
// StreamBuffer if the TrackUnionStream sees its input stream flip from
// A to B, where both A and B have a track with the same ID
while (1) {
// search until we find one not in use here, and not in mBuffer
if (!mBuffer.FindTrack(id)) {
break;
if (id > mNextAvailableTrackID &&
mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex) {
// Input id available. Mark it used in mUsedTracks.
mUsedTracks.InsertElementSorted(id);
} else {
// Input id taken, allocate a new one.
id = mNextAvailableTrackID;
// Update mNextAvailableTrackID and prune any mUsedTracks members it now
// covers.
while (1) {
if (!mUsedTracks.RemoveElementSorted(++mNextAvailableTrackID)) {
// Not in use. We're done.
break;
}
}
id = ++maxTrackID;
}
// Round up the track start time so the track, if anything, starts a
+9
View File
@@ -50,6 +50,8 @@ protected:
nsAutoPtr<MediaSegment> mSegment;
};
// Add the track to this stream, retaining its TrackID if it has never
// been previously used in this stream, allocating a new TrackID otherwise.
uint32_t AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
GraphTime aFrom);
void EndTrack(uint32_t aIndex);
@@ -58,6 +60,13 @@ protected:
bool* aOutputTrackFinished);
nsTArray<TrackMapEntry> mTrackMap;
// The next available TrackID, starting at 1 and progressing upwards.
// All TrackIDs in [1, mNextAvailableTrackID) have implicitly been used.
TrackID mNextAvailableTrackID;
// Sorted array of used TrackIDs that require manual tracking.
nsTArray<TrackID> mUsedTracks;
};
} // namespace mozilla
+44
View File
@@ -35,6 +35,7 @@
#include "PeriodicWave.h"
#include "ConvolverNode.h"
#include "OscillatorNode.h"
#include "blink/PeriodicWave.h"
#include "nsNetUtil.h"
#include "AudioStream.h"
#include "mozilla/dom/Promise.h"
@@ -1031,5 +1032,48 @@ AudioContext::ExtraCurrentTime() const
return mDestination->ExtraCurrentTime();
}
BasicWaveFormCache*
AudioContext::GetBasicWaveFormCache()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mBasicWaveFormCache) {
mBasicWaveFormCache = new BasicWaveFormCache(SampleRate());
}
return mBasicWaveFormCache;
}
BasicWaveFormCache::BasicWaveFormCache(uint32_t aSampleRate)
: mSampleRate(aSampleRate)
{
MOZ_ASSERT(NS_IsMainThread());
}
BasicWaveFormCache::~BasicWaveFormCache()
{ }
WebCore::PeriodicWave*
BasicWaveFormCache::GetBasicWaveForm(OscillatorType aType)
{
MOZ_ASSERT(!NS_IsMainThread());
if (aType == OscillatorType::Sawtooth) {
if (!mSawtooth) {
mSawtooth = WebCore::PeriodicWave::createSawtooth(mSampleRate);
}
return mSawtooth;
} else if (aType == OscillatorType::Square) {
if (!mSquare) {
mSquare = WebCore::PeriodicWave::createSquare(mSampleRate);
}
return mSquare;
} else if (aType == OscillatorType::Triangle) {
if (!mTriangle) {
mTriangle = WebCore::PeriodicWave::createTriangle(mSampleRate);
}
return mTriangle;
} else {
MOZ_ASSERT(false, "Not reached");
return nullptr;
}
}
} // namespace dom
} // namespace mozilla
+27
View File
@@ -27,6 +27,10 @@
#undef CurrentTime
#endif
namespace WebCore {
class PeriodicWave;
};
class nsPIDOMWindow;
namespace mozilla {
@@ -65,6 +69,25 @@ class StereoPannerNode;
class WaveShaperNode;
class PeriodicWave;
class Promise;
enum class OscillatorType : uint32_t;
// This is addrefed by the OscillatorNodeEngine on the main thread
// and then used from the MSG thread.
// It can be released either from the graph thread or the main thread.
class BasicWaveFormCache
{
public:
BasicWaveFormCache(uint32_t aSampleRate);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BasicWaveFormCache)
WebCore::PeriodicWave* GetBasicWaveForm(OscillatorType aType);
private:
~BasicWaveFormCache();
nsRefPtr<WebCore::PeriodicWave> mSawtooth;
nsRefPtr<WebCore::PeriodicWave> mSquare;
nsRefPtr<WebCore::PeriodicWave> mTriangle;
uint32_t mSampleRate;
};
/* This runnable allows the MSG to notify the main thread when audio is actually
* flowing */
@@ -292,6 +315,8 @@ public:
void OnStateChanged(void* aPromise, AudioContextState aNewState);
BasicWaveFormCache* GetBasicWaveFormCache();
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)
@@ -337,6 +362,8 @@ private:
// Hashsets containing all the PannerNodes, to compute the doppler shift.
// These are weak pointers.
nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
// Cache to avoid recomputing basic waveforms all the time.
nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
// Number of channels passed in the OfflineAudioContext ctor.
uint32_t mNumberOfChannels;
// Number of nodes that currently exist for this AudioContext
+5 -6
View File
@@ -40,6 +40,8 @@ public:
, mRecomputeParameters(true)
, mCustomLength(0)
{
MOZ_ASSERT(NS_IsMainThread());
mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
}
void SetSourceStream(AudioNodeStream* aSource)
@@ -104,13 +106,9 @@ public:
mPhase = 0.0;
break;
case OscillatorType::Square:
mPeriodicWave = WebCore::PeriodicWave::createSquare(mSource->SampleRate());
break;
case OscillatorType::Triangle:
mPeriodicWave = WebCore::PeriodicWave::createTriangle(mSource->SampleRate());
break;
case OscillatorType::Sawtooth:
mPeriodicWave = WebCore::PeriodicWave::createSawtooth(mSource->SampleRate());
mPeriodicWave = mBasicWaveFormCache->GetBasicWaveForm(mType);
break;
case OscillatorType::Custom:
break;
@@ -371,8 +369,9 @@ public:
float mPhaseIncrement;
bool mRecomputeParameters;
nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
uint32_t mCustomLength;
nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
nsRefPtr<WebCore::PeriodicWave> mPeriodicWave;
};
OscillatorNode::OscillatorNode(AudioContext* aContext)
-1
View File
@@ -12,7 +12,6 @@
#include "mozilla/Attributes.h"
#include "AudioContext.h"
#include "AudioNodeEngine.h"
#include "nsAutoPtr.h"
namespace mozilla {
+4
View File
@@ -42,6 +42,9 @@ typedef nsTArray<float> AudioFloatArray;
class PeriodicWave {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeriodicWave);
static PeriodicWave* createSine(float sampleRate);
static PeriodicWave* createSquare(float sampleRate);
static PeriodicWave* createSawtooth(float sampleRate);
@@ -75,6 +78,7 @@ public:
private:
explicit PeriodicWave(float sampleRate);
~PeriodicWave() {}
void generateBasicWaveform(mozilla::dom::OscillatorType);
+40 -2
View File
@@ -291,6 +291,10 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
return NS_OK;
}
/* This version of ShouldLoad() is non-static and called by the Content Policy
* API and AsyncOnChannelRedirect(). See nsIContentPolicy::ShouldLoad()
* for detailed description of the parameters.
*/
NS_IMETHODIMP
nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
nsIURI* aContentLocation,
@@ -300,6 +304,36 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
nsISupports* aExtra,
nsIPrincipal* aRequestPrincipal,
int16_t* aDecision)
{
// We pass in false as the first parameter to ShouldLoad(), because the
// callers of this method don't know whether the load went through cached
// image redirects. This is handled by direct callers of the static
// ShouldLoad.
nsresult rv = ShouldLoad(false, //aHadInsecureImageRedirect
aContentType,
aContentLocation,
aRequestingLocation,
aRequestingContext,
aMimeGuess,
aExtra,
aRequestPrincipal,
aDecision);
return rv;
}
/* Static version of ShouldLoad() that contains all the Mixed Content Blocker
* logic. Called from non-static ShouldLoad().
*/
nsresult
nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
uint32_t aContentType,
nsIURI* aContentLocation,
nsIURI* aRequestingLocation,
nsISupports* aRequestingContext,
const nsACString& aMimeGuess,
nsISupports* aExtra,
nsIPrincipal* aRequestPrincipal,
int16_t* aDecision)
{
// Asserting that we are on the main thread here and hence do not have to lock
// and unlock sBlockMixedScript and sBlockMixedDisplay before reading/writing
@@ -461,8 +495,12 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
*aDecision = REJECT_REQUEST;
return NS_ERROR_FAILURE;
}
if (schemeLocal || schemeNoReturnData || schemeInherits || schemeSecure) {
// TYPE_IMAGE redirects are cached based on the original URI, not the final
// destination and hence cache hits for images may not have the correct
// aContentLocation. Check if the cached hit went through an http redirect,
// and if it did, we can't treat this as a secure subresource.
if (!aHadInsecureImageRedirect &&
(schemeLocal || schemeNoReturnData || schemeInherits || schemeSecure)) {
*aDecision = ACCEPT;
return NS_OK;
}
+21
View File
@@ -26,10 +26,12 @@ enum MixedContentTypes {
#include "nsIContentPolicy.h"
#include "nsIChannel.h"
#include "nsIChannelEventSink.h"
#include "imgRequest.h"
class nsMixedContentBlocker : public nsIContentPolicy,
public nsIChannelEventSink
{
private:
virtual ~nsMixedContentBlocker();
public:
@@ -38,6 +40,25 @@ public:
NS_DECL_NSICHANNELEVENTSINK
nsMixedContentBlocker();
/* Static version of ShouldLoad() that contains all the Mixed Content Blocker
* logic. Called from non-static ShouldLoad().
* Called directly from imageLib when an insecure redirect exists in a cached
* image load.
* @param aHadInsecureImageRedirect
* boolean flag indicating that an insecure redirect through http
* occured when this image was initially loaded and cached.
* Remaining parameters are from nsIContentPolicy::ShouldLoad().
*/
static nsresult ShouldLoad(bool aHadInsecureImageRedirect,
uint32_t aContentType,
nsIURI* aContentLocation,
nsIURI* aRequestingLocation,
nsISupports* aRequestingContext,
const nsACString& aMimeGuess,
nsISupports* aExtra,
nsIPrincipal* aRequestPrincipal,
int16_t* aDecision);
static bool sBlockMixedScript;
static bool sBlockMixedDisplay;
};
+74 -4
View File
@@ -16,6 +16,7 @@
#include "nsCOMPtr.h"
#include "nsContentPolicyUtils.h"
#include "nsContentUtils.h"
#include "nsCORSListenerProxy.h"
#include "nsNetUtil.h"
@@ -30,6 +31,7 @@
#include "nsIFileURL.h"
#include "nsCRT.h"
#include "nsINetworkPredictor.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "nsIApplicationCache.h"
#include "nsIApplicationCacheContainer.h"
@@ -584,6 +586,71 @@ ShouldRevalidateEntry(imgCacheEntry* aEntry,
return bValidateEntry;
}
/* Call content policies on cached images that went through a redirect */
static bool
ShouldLoadCachedImage(imgRequest* aImgRequest,
nsISupports* aLoadingContext,
nsIPrincipal* aLoadingPrincipal)
{
/* Call content policies on cached images - Bug 1082837
* Cached images are keyed off of the first uri in a redirect chain.
* Hence content policies don't get a chance to test the intermediate hops
* or the final desitnation. Here we test the final destination using
* mCurrentURI off of the imgRequest and passing it into content policies.
* For Mixed Content Blocker, we do an additional check to determine if any
* of the intermediary hops went through an insecure redirect with the
* mHadInsecureRedirect flag
*/
bool insecureRedirect = aImgRequest->HadInsecureRedirect();
nsCOMPtr<nsIURI> contentLocation;
aImgRequest->GetCurrentURI(getter_AddRefs(contentLocation));
nsresult rv;
int16_t decision = nsIContentPolicy::REJECT_REQUEST;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_IMAGE,
contentLocation,
aLoadingPrincipal,
aLoadingContext,
EmptyCString(), //mime guess
nullptr, //aExtra
&decision,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv) || !NS_CP_ACCEPTED(decision)) {
return false;
}
// We call all Content Policies above, but we also have to call mcb
// individually to check the intermediary redirect hops are secure.
if (insecureRedirect) {
if (!nsContentUtils::IsSystemPrincipal(aLoadingPrincipal)) {
// Set the requestingLocation from the aLoadingPrincipal.
nsCOMPtr<nsIURI> requestingLocation;
if (aLoadingPrincipal) {
rv = aLoadingPrincipal->GetURI(getter_AddRefs(requestingLocation));
NS_ENSURE_SUCCESS(rv, false);
}
// reset the decision for mixed content blocker check
decision = nsIContentPolicy::REJECT_REQUEST;
rv = nsMixedContentBlocker::ShouldLoad(insecureRedirect,
nsIContentPolicy::TYPE_IMAGE,
contentLocation,
requestingLocation,
aLoadingContext,
EmptyCString(), //mime guess
nullptr,
aLoadingPrincipal,
&decision);
if (NS_FAILED(rv) || !NS_CP_ACCEPTED(decision)) {
return false;
}
}
}
return true;
}
// Returns true if this request is compatible with the given CORS mode on the
// given loading principal, and false if the request may not be reused due
// to CORS. Also checks the Referrer Policy, since requests with different
@@ -591,7 +658,7 @@ ShouldRevalidateEntry(imgCacheEntry* aEntry,
static bool
ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
int32_t corsmode, nsIPrincipal* loadingPrincipal,
ReferrerPolicy referrerPolicy)
nsISupports* aCX, ReferrerPolicy referrerPolicy)
{
// If the entry's Referrer Policy doesn't match, we can't use this request.
if (referrerPolicy != request->GetReferrerPolicy()) {
@@ -615,11 +682,14 @@ ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
if (otherprincipal && loadingPrincipal) {
bool equals = false;
otherprincipal->Equals(loadingPrincipal, &equals);
return equals;
if (!equals) {
return false;
}
}
}
return true;
// Content Policy Check on Cached Images
return ShouldLoadCachedImage(request, aCX, loadingPrincipal);
}
static nsresult
@@ -1729,7 +1799,7 @@ imgLoader::ValidateEntry(imgCacheEntry* aEntry,
if (!ValidateSecurityInfo(request, aEntry->ForcePrincipalCheck(),
aCORSMode, aLoadingPrincipal,
aReferrerPolicy))
aCX, aReferrerPolicy))
return false;
// data URIs are immutable and by their nature can't leak data, so we can
+5 -32
View File
@@ -10,10 +10,7 @@
#include "BackstagePass.h"
#include "nsDOMClassInfo.h"
#include "nsIPrincipal.h"
#include "mozilla/dom/ResolveSystemBinding.h"
using mozilla::dom::ResolveSystemBinding;
#include "mozilla/dom/BindingUtils.h"
NS_INTERFACE_MAP_BEGIN(BackstagePass)
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
@@ -68,25 +65,8 @@ BackstagePass::Resolve(nsIXPConnectWrappedNative* wrapper,
{
JS::RootedObject obj(cx, objArg);
JS::RootedId id(cx, idArg);
bool resolved;
*_retval = !!JS_ResolveStandardClass(cx, obj, id, &resolved);
NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
if (resolved) {
*resolvedp = true;
return NS_OK;
}
*_retval = ResolveSystemBinding(cx, obj, id, &resolved);
NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
if (resolved) {
*resolvedp = true;
return NS_OK;
}
return NS_OK;
*_retval = mozilla::dom::SystemGlobalResolve(cx, obj, id, resolvedp);
return *_retval ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
@@ -94,15 +74,8 @@ BackstagePass::Enumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* objArg, bool* _retval)
{
JS::RootedObject obj(cx, objArg);
*_retval = JS_EnumerateStandardClasses(cx, obj);
NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
bool ignored = false;
*_retval = ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored);
NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
return NS_OK;
*_retval = mozilla::dom::SystemGlobalEnumerate(cx, obj);
return *_retval ? NS_OK : NS_ERROR_FAILURE;
}
/***************************************************************************/
+183 -50
View File
@@ -39,6 +39,9 @@
#include "mozilla/net/NeckoCommon.h"
#include "LoadContextInfo.h"
#include "mozilla/ipc/URIUtils.h"
#include "SerializedLoadContext.h"
#include "mozilla/net/NeckoChild.h"
#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
#include "nsIPropertyBag2.h"
@@ -254,8 +257,8 @@ Predictor::Action::OnCacheEntryAvailable(nsICacheEntry *entry, bool isNew,
targetURI.get(), sourceURI.get(), mStackCount,
isNew, result));
if (NS_FAILED(result)) {
PREDICTOR_LOG(("OnCacheEntryAvailable %p FAILED to get cache entry. "
"Aborting.", this));
PREDICTOR_LOG(("OnCacheEntryAvailable %p FAILED to get cache entry (0x%08X). "
"Aborting.", this, result));
return NS_OK;
}
if (mPredict) {
@@ -275,7 +278,8 @@ NS_IMPL_ISUPPORTS(Predictor,
nsIObserver,
nsISpeculativeConnectionOverrider,
nsIInterfaceRequestor,
nsICacheEntryMetaDataVisitor)
nsICacheEntryMetaDataVisitor,
nsINetworkPredictorVerifier)
Predictor::Predictor()
:mInitialized(false)
@@ -520,6 +524,8 @@ Predictor::OnMetaDataElement(const char *asciiKey, const char *asciiValue)
nsresult
Predictor::Init()
{
MOZ_DIAGNOSTIC_ASSERT(!IsNeckoChild());
if (!NS_IsMainThread()) {
MOZ_ASSERT(false, "Predictor::Init called off the main thread!");
return NS_ERROR_UNEXPECTED;
@@ -723,6 +729,11 @@ Predictor::Create(nsISupports *aOuter, const nsIID& aIID,
}
nsRefPtr<Predictor> svc = new Predictor();
if (IsNeckoChild()) {
// Child threads only need to be call into the public interface methods
// so we don't bother with initialization
return svc->QueryInterface(aIID, aResult);
}
rv = svc->Init();
if (NS_FAILED(rv)) {
@@ -743,29 +754,59 @@ Predictor::Predict(nsIURI *targetURI, nsIURI *sourceURI,
PredictorPredictReason reason, nsILoadContext *loadContext,
nsINetworkPredictorVerifier *verifier)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread(),
"Predictor interface methods must be called on the main thread");
PREDICTOR_LOG(("Predictor::Predict"));
if (IsNeckoChild()) {
MOZ_DIAGNOSTIC_ASSERT(gNeckoChild);
PREDICTOR_LOG((" called on child process"));
ipc::OptionalURIParams serTargetURI, serSourceURI;
SerializeURI(targetURI, serTargetURI);
SerializeURI(sourceURI, serSourceURI);
IPC::SerializedLoadContext serLoadContext;
serLoadContext.Init(loadContext);
// If two different threads are predicting concurently, this will be
// overwritten. Thankfully, we only use this in tests, which will
// overwrite mVerifier perhaps multiple times for each individual test;
// however, within each test, the multiple predict calls should have the
// same verifier.
if (verifier) {
PREDICTOR_LOG((" was given a verifier"));
mChildVerifier = verifier;
}
PREDICTOR_LOG((" forwarding to parent process"));
gNeckoChild->SendPredPredict(serTargetURI, serSourceURI,
reason, serLoadContext, verifier);
return NS_OK;
}
PREDICTOR_LOG((" called on parent process"));
if (!mInitialized) {
PREDICTOR_LOG((" not initialized"));
return NS_OK;
}
if (!mEnabled) {
PREDICTOR_LOG((" not enabled"));
return NS_OK;
}
if (loadContext && loadContext->UsePrivateBrowsing()) {
// Don't want to do anything in PB mode
PREDICTOR_LOG((" in PB mode"));
return NS_OK;
}
if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
// Nothing we can do for non-HTTP[S] schemes
PREDICTOR_LOG((" got non-http[s] URI"));
return NS_OK;
}
@@ -776,6 +817,7 @@ Predictor::Predict(nsIURI *targetURI, nsIURI *sourceURI,
switch (reason) {
case nsINetworkPredictor::PREDICT_LINK:
if (!targetURI || !sourceURI) {
PREDICTOR_LOG((" link invalid URI state"));
return NS_ERROR_INVALID_ARG;
}
// Link hover is a special case where we can predict without hitting the
@@ -784,17 +826,20 @@ Predictor::Predict(nsIURI *targetURI, nsIURI *sourceURI,
return NS_OK;
case nsINetworkPredictor::PREDICT_LOAD:
if (!targetURI || sourceURI) {
PREDICTOR_LOG((" load invalid URI state"));
return NS_ERROR_INVALID_ARG;
}
break;
case nsINetworkPredictor::PREDICT_STARTUP:
if (targetURI || sourceURI) {
PREDICTOR_LOG((" startup invalid URI state"));
return NS_ERROR_INVALID_ARG;
}
uriKey = mStartupURI;
originKey = mStartupURI;
break;
default:
PREDICTOR_LOG((" invalid reason"));
return NS_ERROR_INVALID_ARG;
}
@@ -809,7 +854,7 @@ Predictor::Predict(nsIURI *targetURI, nsIURI *sourceURI,
nullptr, verifier, this);
nsAutoCString uriKeyStr;
uriKey->GetAsciiSpec(uriKeyStr);
PREDICTOR_LOG(("Predict uri=%s reason=%d action=%p", uriKeyStr.get(),
PREDICTOR_LOG((" Predict uri=%s reason=%d action=%p", uriKeyStr.get(),
reason, uriAction.get()));
uint32_t openFlags = nsICacheStorage::OPEN_READONLY |
nsICacheStorage::OPEN_SECRETLY |
@@ -831,7 +876,7 @@ Predictor::Predict(nsIURI *targetURI, nsIURI *sourceURI,
targetOrigin, nullptr, verifier, this);
nsAutoCString originKeyStr;
originKey->GetAsciiSpec(originKeyStr);
PREDICTOR_LOG(("Predict origin=%s reason=%d action=%p", originKeyStr.get(),
PREDICTOR_LOG((" Predict origin=%s reason=%d action=%p", originKeyStr.get(),
reason, originAction.get()));
openFlags = nsICacheStorage::OPEN_READONLY |
nsICacheStorage::OPEN_SECRETLY |
@@ -840,6 +885,7 @@ Predictor::Predict(nsIURI *targetURI, nsIURI *sourceURI,
NS_LITERAL_CSTRING(PREDICTOR_ORIGIN_EXTENSION),
openFlags, originAction);
PREDICTOR_LOG((" predict returning"));
return NS_OK;
}
@@ -851,6 +897,7 @@ Predictor::PredictInternal(PredictorPredictReason reason, nsICacheEntry *entry,
{
MOZ_ASSERT(NS_IsMainThread());
PREDICTOR_LOG(("Predictor::PredictInternal"));
bool rv = false;
if (reason == nsINetworkPredictor::PREDICT_LOAD) {
@@ -859,6 +906,7 @@ Predictor::PredictInternal(PredictorPredictReason reason, nsICacheEntry *entry,
if (isNew) {
// nothing else we can do here
PREDICTOR_LOG((" new entry"));
return rv;
}
@@ -870,6 +918,7 @@ Predictor::PredictInternal(PredictorPredictReason reason, nsICacheEntry *entry,
rv = PredictForStartup(entry, verifier);
break;
default:
PREDICTOR_LOG((" invalid reason"));
MOZ_ASSERT(false, "Got unexpected value for prediction reason");
}
@@ -882,7 +931,9 @@ Predictor::PredictForLink(nsIURI *targetURI, nsIURI *sourceURI,
{
MOZ_ASSERT(NS_IsMainThread());
PREDICTOR_LOG(("Predictor::PredictForLink"));
if (!mSpeculativeService) {
PREDICTOR_LOG((" missing speculative service"));
return;
}
@@ -891,13 +942,14 @@ Predictor::PredictForLink(nsIURI *targetURI, nsIURI *sourceURI,
sourceURI->SchemeIs("https", &isSSL);
if (isSSL) {
// We don't want to predict from an HTTPS page, to avoid info leakage
PREDICTOR_LOG(("Not predicting for link hover - on an SSL page"));
PREDICTOR_LOG((" Not predicting for link hover - on an SSL page"));
return;
}
}
mSpeculativeService->SpeculativeConnect(targetURI, nullptr);
if (verifier) {
PREDICTOR_LOG((" sending verification"));
verifier->OnPredictPreconnect(targetURI);
}
}
@@ -910,8 +962,10 @@ Predictor::PredictForPageload(nsICacheEntry *entry, uint8_t stackCount,
{
MOZ_ASSERT(NS_IsMainThread());
PREDICTOR_LOG(("Predictor::PredictForPageload"));
if (stackCount > MAX_PAGELOAD_DEPTH) {
PREDICTOR_LOG(("PredictForPageload exceeded recursion depth!"));
PREDICTOR_LOG((" exceeded recursion depth!"));
return false;
}
@@ -937,7 +991,7 @@ Predictor::PredictForPageload(nsICacheEntry *entry, uint8_t stackCount,
nullptr, verifier, this, stackCount + 1);
nsAutoCString redirectUriString;
redirectURI->GetAsciiSpec(redirectUriString);
PREDICTOR_LOG(("Predict redirect uri=%s action=%p", redirectUriString.get(),
PREDICTOR_LOG((" Predict redirect uri=%s action=%p", redirectUriString.get(),
redirectAction.get()));
uint32_t openFlags = nsICacheStorage::OPEN_READONLY |
nsICacheStorage::OPEN_SECRETLY |
@@ -961,6 +1015,7 @@ Predictor::PredictForStartup(nsICacheEntry *entry,
{
MOZ_ASSERT(NS_IsMainThread());
PREDICTOR_LOG(("Predictor::PredictForStartup"));
int32_t globalDegradation = CalculateGlobalDegradation(mLastStartupTime);
CalculatePredictions(entry, mLastStartupTime, mStartupCount,
globalDegradation);
@@ -1107,6 +1162,8 @@ Predictor::RunPredictions(nsINetworkPredictorVerifier *verifier)
{
MOZ_ASSERT(NS_IsMainThread(), "Running prediction off main thread");
PREDICTOR_LOG(("Predictor::RunPredictions"));
bool predicted = false;
uint32_t len, i;
@@ -1116,10 +1173,12 @@ Predictor::RunPredictions(nsINetworkPredictorVerifier *verifier)
len = preconnects.Length();
for (i = 0; i < len; ++i) {
PREDICTOR_LOG((" doing preconnect"));
nsCOMPtr<nsIURI> uri = preconnects[i];
mSpeculativeService->SpeculativeConnect(uri, this);
predicted = true;
if (verifier) {
PREDICTOR_LOG((" sending preconnect verification"));
verifier->OnPredictPreconnect(uri);
}
}
@@ -1130,6 +1189,7 @@ Predictor::RunPredictions(nsINetworkPredictorVerifier *verifier)
nsCOMPtr<nsIURI> uri = preresolves[i];
nsAutoCString hostname;
uri->GetAsciiHost(hostname);
PREDICTOR_LOG((" doing preresolve %s", hostname.get()));
nsCOMPtr<nsICancelable> tmpCancelable;
mDnsService->AsyncResolve(hostname,
(nsIDNSService::RESOLVE_PRIORITY_MEDIUM |
@@ -1138,6 +1198,7 @@ Predictor::RunPredictions(nsINetworkPredictorVerifier *verifier)
getter_AddRefs(tmpCancelable));
predicted = true;
if (verifier) {
PREDICTOR_LOG((" sending preresolve verification"));
verifier->OnPredictDNS(uri);
}
}
@@ -1163,28 +1224,51 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
PredictorLearnReason reason,
nsILoadContext *loadContext)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread(),
"Predictor interface methods must be called on the main thread");
PREDICTOR_LOG(("Predictor::Learn"));
if (IsNeckoChild()) {
MOZ_DIAGNOSTIC_ASSERT(gNeckoChild);
PREDICTOR_LOG((" called on child process"));
ipc::URIParams serTargetURI;
SerializeURI(targetURI, serTargetURI);
ipc::OptionalURIParams serSourceURI;
SerializeURI(sourceURI, serSourceURI);
IPC::SerializedLoadContext serLoadContext;
serLoadContext.Init(loadContext);
PREDICTOR_LOG((" forwarding to parent"));
gNeckoChild->SendPredLearn(serTargetURI, serSourceURI, reason,
serLoadContext);
return NS_OK;
}
PREDICTOR_LOG((" called on parent process"));
if (!mInitialized) {
PREDICTOR_LOG((" not initialized"));
return NS_OK;
}
if (!mEnabled) {
PREDICTOR_LOG((" not enabled"));
return NS_OK;
}
if (loadContext && loadContext->UsePrivateBrowsing()) {
// Don't want to do anything in PB mode
PREDICTOR_LOG((" in PB mode"));
return NS_OK;
}
if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
PREDICTOR_LOG((" got non-HTTP[S] URI"));
return NS_ERROR_INVALID_ARG;
}
@@ -1197,6 +1281,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
switch (reason) {
case nsINetworkPredictor::LEARN_LOAD_TOPLEVEL:
if (!targetURI || sourceURI) {
PREDICTOR_LOG((" load toplevel invalid URI state"));
return NS_ERROR_INVALID_ARG;
}
rv = ExtractOrigin(targetURI, getter_AddRefs(targetOrigin), mIOService);
@@ -1206,6 +1291,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
break;
case nsINetworkPredictor::LEARN_STARTUP:
if (!targetURI || sourceURI) {
PREDICTOR_LOG((" startup invalid URI state"));
return NS_ERROR_INVALID_ARG;
}
rv = ExtractOrigin(targetURI, getter_AddRefs(targetOrigin), mIOService);
@@ -1216,6 +1302,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
case nsINetworkPredictor::LEARN_LOAD_REDIRECT:
case nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE:
if (!targetURI || !sourceURI) {
PREDICTOR_LOG((" redirect/subresource invalid URI state"));
return NS_ERROR_INVALID_ARG;
}
rv = ExtractOrigin(targetURI, getter_AddRefs(targetOrigin), mIOService);
@@ -1226,6 +1313,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
originKey = sourceOrigin;
break;
default:
PREDICTOR_LOG((" invalid reason"));
return NS_ERROR_INVALID_ARG;
}
@@ -1244,7 +1332,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
if (sourceURI) {
sourceURI->GetAsciiSpec(sourceUriStr);
}
PREDICTOR_LOG(("Learn uriKey=%s targetURI=%s sourceURI=%s reason=%d "
PREDICTOR_LOG((" Learn uriKey=%s targetURI=%s sourceURI=%s reason=%d "
"action=%p", uriKeyStr.get(), targetUriStr.get(),
sourceUriStr.get(), reason, uriAction.get()));
// For learning full URI things, we *always* open readonly and secretly, as we
@@ -1272,7 +1360,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
if (sourceOrigin) {
sourceOrigin->GetAsciiSpec(sourceOriginStr);
}
PREDICTOR_LOG(("Learn originKey=%s targetOrigin=%s sourceOrigin=%s reason=%d "
PREDICTOR_LOG((" Learn originKey=%s targetOrigin=%s sourceOrigin=%s reason=%d "
"action=%p", originKeyStr.get(), targetOriginStr.get(),
sourceOriginStr.get(), reason, originAction.get()));
uint32_t originOpenFlags;
@@ -1291,6 +1379,7 @@ Predictor::Learn(nsIURI *targetURI, nsIURI *sourceURI,
NS_LITERAL_CSTRING(PREDICTOR_ORIGIN_EXTENSION),
originOpenFlags, originAction);
PREDICTOR_LOG(("Predictor::Learn returning"));
return NS_OK;
}
@@ -1301,11 +1390,14 @@ Predictor::LearnInternal(PredictorLearnReason reason, nsICacheEntry *entry,
{
MOZ_ASSERT(NS_IsMainThread());
PREDICTOR_LOG(("Predictor::LearnInternal"));
nsCString junk;
if (!fullUri && reason == nsINetworkPredictor::LEARN_LOAD_TOPLEVEL &&
NS_FAILED(entry->GetMetaDataElement(SEEN_META_DATA, getter_Copies(junk)))) {
// This is an origin-only entry that we haven't seen before. Let's mark it
// as seen.
PREDICTOR_LOG((" marking new origin entry as seen"));
entry->SetMetaDataElement(SEEN_META_DATA, "1");
// Need to ensure someone else can get to the entry if necessary
@@ -1318,6 +1410,7 @@ Predictor::LearnInternal(PredictorLearnReason reason, nsICacheEntry *entry,
// This actually has no work associated with it, since all we need to do
// is update the timestamps and fetch count, and that's done for us by
// opening the cache entry.
PREDICTOR_LOG((" nothing to do for toplevel"));
break;
case nsINetworkPredictor::LEARN_LOAD_REDIRECT:
if (fullUri) {
@@ -1331,6 +1424,7 @@ Predictor::LearnInternal(PredictorLearnReason reason, nsICacheEntry *entry,
LearnForStartup(entry, targetURI);
break;
default:
PREDICTOR_LOG((" unexpected reason value"));
MOZ_ASSERT(false, "Got unexpected value for learn reason!");
}
}
@@ -1378,6 +1472,8 @@ Predictor::LearnForSubresource(nsICacheEntry *entry, nsIURI *targetURI)
{
MOZ_ASSERT(NS_IsMainThread());
PREDICTOR_LOG(("Predictor::LearnForSubresource"));
uint32_t lastLoad;
nsresult rv = entry->GetLastFetched(&lastLoad);
RETURN_IF_FAILED(rv);
@@ -1402,6 +1498,7 @@ Predictor::LearnForSubresource(nsICacheEntry *entry, nsIURI *targetURI)
if (isNewResource) {
// This is a new addition
PREDICTOR_LOG((" new resource"));
int32_t resourceCount;
nsCString s;
rv = entry->GetMetaDataElement("predictor::resource-count",
@@ -1424,6 +1521,7 @@ Predictor::LearnForSubresource(nsICacheEntry *entry, nsIURI *targetURI)
entry->SetMetaDataElement("predictor::resource-count", count.BeginReading());
hitCount = 1;
} else {
PREDICTOR_LOG((" existing resource"));
hitCount = std::min(hitCount + 1, static_cast<uint32_t>(loadCount));
}
@@ -1448,6 +1546,7 @@ Predictor::LearnForRedirect(nsICacheEntry *entry, nsIURI *targetURI)
MOZ_ASSERT(NS_IsMainThread());
// TODO - not doing redirects for first go around
PREDICTOR_LOG(("Predictor::LearnForRedirect"));
}
// This will add a page to our list of startup pages if it's being loaded
@@ -1458,6 +1557,7 @@ Predictor::MaybeLearnForStartup(nsIURI *uri, bool fullUri)
MOZ_ASSERT(NS_IsMainThread());
// TODO - not doing startup for first go around
PREDICTOR_LOG(("Predictor::MaybeLearnForStartup"));
}
// Add information about a top-level load to our list of startup pages
@@ -1468,6 +1568,7 @@ Predictor::LearnForStartup(nsICacheEntry *entry, nsIURI *targetURI)
// These actually do the same set of work, just on different entries, so we
// can pass through to get the real work done here
PREDICTOR_LOG(("Predictor::LearnForStartup"));
LearnForSubresource(entry, targetURI);
}
@@ -1536,24 +1637,35 @@ Predictor::ParseMetaDataEntry(const char *key, const char *value, nsIURI **uri,
NS_IMETHODIMP
Predictor::Reset()
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread(),
"Predictor interface methods must be called on the main thread");
PREDICTOR_LOG(("Predictor::Reset"));
if (IsNeckoChild()) {
MOZ_DIAGNOSTIC_ASSERT(gNeckoChild);
PREDICTOR_LOG((" forwarding to parent process"));
gNeckoChild->SendPredReset();
return NS_OK;
}
PREDICTOR_LOG((" called on parent process"));
if (!mInitialized) {
PREDICTOR_LOG((" not initialized"));
return NS_OK;
}
if (!mEnabled) {
PREDICTOR_LOG((" not enabled"));
return NS_OK;
}
nsRefPtr<Predictor::Resetter> reset = new Predictor::Resetter(this);
PREDICTOR_LOG((" created a resetter"));
mCacheDiskStorage->AsyncVisitStorage(reset, true);
PREDICTOR_LOG((" Cache async launched, returning now"));
return NS_OK;
}
@@ -1728,11 +1840,6 @@ PredictorPredict(nsIURI *targetURI, nsIURI *sourceURI,
PredictorPredictReason reason, nsILoadContext *loadContext,
nsINetworkPredictorVerifier *verifier)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
@@ -1752,11 +1859,6 @@ PredictorLearn(nsIURI *targetURI, nsIURI *sourceURI,
PredictorLearnReason reason,
nsILoadContext *loadContext)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
@@ -1775,11 +1877,6 @@ PredictorLearn(nsIURI *targetURI, nsIURI *sourceURI,
PredictorLearnReason reason,
nsILoadGroup *loadGroup)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
@@ -1808,11 +1905,6 @@ PredictorLearn(nsIURI *targetURI, nsIURI *sourceURI,
PredictorLearnReason reason,
nsIDocument *document)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
@@ -1836,11 +1928,6 @@ nsresult
PredictorLearnRedirect(nsIURI *targetURI, nsIChannel *channel,
nsILoadContext *loadContext)
{
if (IsNeckoChild()) {
// TODO - e10s-ify the predictor
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIURI> sourceURI;
@@ -1868,5 +1955,51 @@ PredictorLearnRedirect(nsIURI *targetURI, nsIChannel *channel,
loadContext);
}
// nsINetworkPredictorVerifier
/**
* Call through to the child's verifier (only during tests).
*/
NS_IMETHODIMP
Predictor::OnPredictPreconnect(nsIURI *aURI) {
if (IsNeckoChild()) {
MOZ_DIAGNOSTIC_ASSERT(mChildVerifier);
return mChildVerifier->OnPredictPreconnect(aURI);
}
MOZ_DIAGNOSTIC_ASSERT(gNeckoParent);
ipc::URIParams serURI;
SerializeURI(aURI, serURI);
if (!gNeckoParent->SendPredOnPredictPreconnect(serURI)) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
/**
* Call through to the child's verifier (only during tests)
*/
NS_IMETHODIMP
Predictor::OnPredictDNS(nsIURI *aURI) {
if (IsNeckoChild()) {
MOZ_DIAGNOSTIC_ASSERT(mChildVerifier);
return mChildVerifier->OnPredictDNS(aURI);
}
MOZ_DIAGNOSTIC_ASSERT(gNeckoParent);
ipc::URIParams serURI;
SerializeURI(aURI, serURI);
if (!gNeckoParent->SendPredOnPredictDNS(serURI)) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
} // namespace net
} // namespace mozilla
+6 -1
View File
@@ -7,6 +7,7 @@
#define mozilla_net_Predictor_h
#include "nsINetworkPredictor.h"
#include "nsINetworkPredictorVerifier.h"
#include "nsCOMPtr.h"
#include "nsICacheEntry.h"
@@ -25,7 +26,6 @@
class nsICacheStorage;
class nsIDNSService;
class nsIIOService;
class nsINetworkPredictorVerifier;
class nsITimer;
namespace mozilla {
@@ -36,6 +36,7 @@ class Predictor : public nsINetworkPredictor
, public nsISpeculativeConnectionOverrider
, public nsIInterfaceRequestor
, public nsICacheEntryMetaDataVisitor
, public nsINetworkPredictorVerifier
{
public:
NS_DECL_ISUPPORTS
@@ -44,6 +45,7 @@ public:
NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICACHEENTRYMETADATAVISITOR
NS_DECL_NSINETWORKPREDICTORVERIFIER
Predictor();
@@ -54,6 +56,9 @@ public:
private:
virtual ~Predictor();
// Stores callbacks for a child process predictor (for test purposes)
nsCOMPtr<nsINetworkPredictorVerifier> mChildVerifier;
union Reason {
PredictorLearnReason mLearn;
PredictorPredictReason mPredict;
+5
View File
@@ -225,6 +225,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFtpProtocolHandler, Init)
#ifdef NECKO_PROTOCOL_http
// http/https
#include "nsHttpHandler.h"
#include "Http2Compression.h"
#undef LOG
#undef LOG_ENABLED
#include "nsHttpAuthManager.h"
@@ -657,6 +658,10 @@ static void nsNetShutdown()
mozilla::net::WebSocketChannel::Shutdown();
#endif // NECKO_PROTOCOL_websocket
#ifdef NECKO_PROTOCOL_http
mozilla::net::Http2CompressionCleanup();
#endif // NECKO_PROTOCOL_http
delete gNetSniffers;
gNetSniffers = nullptr;
delete gDataSniffers;
+40
View File
@@ -27,6 +27,9 @@
#endif
#include "SerializedLoadContext.h"
#include "nsIOService.h"
#include "nsINetworkPredictor.h"
#include "nsINetworkPredictorVerifier.h"
#include "mozilla/ipc/URIUtils.h"
using mozilla::dom::TCPSocketChild;
using mozilla::dom::TCPServerSocketChild;
@@ -333,6 +336,43 @@ NeckoChild::RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
return true;
}
/* Predictor Messages */
bool
NeckoChild::RecvPredOnPredictPreconnect(const URIParams& aURI)
{
MOZ_ASSERT(NS_IsMainThread(), "PredictorChild::RecvOnPredictPreconnect "
"off main thread.");
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
// Get the current predictor
nsresult rv = NS_OK;
nsCOMPtr<nsINetworkPredictorVerifier> predictor =
do_GetService("@mozilla.org/network/predictor;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
predictor->OnPredictPreconnect(uri);
return true;
}
bool
NeckoChild::RecvPredOnPredictDNS(const URIParams& aURI)
{
MOZ_ASSERT(NS_IsMainThread(), "PredictorChild::RecvOnPredictDNS off "
"main thread.");
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
// Get the current predictor
nsresult rv = NS_OK;
nsCOMPtr<nsINetworkPredictorVerifier> predictor =
do_GetService("@mozilla.org/network/predictor;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
predictor->OnPredictDNS(uri);
return true;
}
bool
NeckoChild::RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline)
{
+4
View File
@@ -80,6 +80,10 @@ protected:
const nsString& aRealm,
const uint64_t& aCallbackId) override;
virtual bool RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline) override;
/* Predictor Messsages */
virtual bool RecvPredOnPredictPreconnect(const URIParams& aURI) override;
virtual bool RecvPredOnPredictDNS(const URIParams& aURI) override;
};
/**
+77
View File
@@ -40,6 +40,7 @@
#include "nsIAuthPromptCallback.h"
#include "nsPrincipal.h"
#include "nsIOService.h"
#include "nsINetworkPredictor.h"
#include "mozilla/net/OfflineObserver.h"
#include "nsISpeculativeConnect.h"
@@ -57,6 +58,8 @@ using IPC::SerializedLoadContext;
namespace mozilla {
namespace net {
PNeckoParent *gNeckoParent = nullptr;
// C++ file contents
NeckoParent::NeckoParent()
{
@@ -82,6 +85,7 @@ NeckoParent::NeckoParent()
}
mObserver = new OfflineObserver(this);
gNeckoParent = this;
}
NeckoParent::~NeckoParent()
@@ -853,6 +857,79 @@ NeckoParent::RecvOnAuthCancelled(const uint64_t& aCallbackId,
return true;
}
/* Predictor Messages */
bool
NeckoParent::RecvPredPredict(const ipc::OptionalURIParams& aTargetURI,
const ipc::OptionalURIParams& aSourceURI,
const uint32_t& aReason,
const SerializedLoadContext& aLoadContext,
const bool& hasVerifier)
{
nsCOMPtr<nsIURI> targetURI = DeserializeURI(aTargetURI);
nsCOMPtr<nsIURI> sourceURI = DeserializeURI(aSourceURI);
// We only actually care about the loadContext.mPrivateBrowsing, so we'll just
// pass dummy params for nestFrameId, inBrowser and appId
uint64_t nestedFrameId = 0;
nsCOMPtr<nsILoadContext> loadContext;
if (aLoadContext.IsNotNull()) {
loadContext = new LoadContext(aLoadContext, nestedFrameId, NECKO_UNKNOWN_APP_ID, false);
}
// Get the current predictor
nsresult rv = NS_OK;
nsCOMPtr<nsINetworkPredictor> predictor =
do_GetService("@mozilla.org/network/predictor;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsINetworkPredictorVerifier> verifier;
if (hasVerifier) {
verifier = do_QueryInterface(predictor);
}
predictor->Predict(targetURI, sourceURI, aReason, loadContext, verifier);
return true;
}
bool
NeckoParent::RecvPredLearn(const ipc::URIParams& aTargetURI,
const ipc::OptionalURIParams& aSourceURI,
const uint32_t& aReason,
const SerializedLoadContext& aLoadContext)
{
nsCOMPtr<nsIURI> targetURI = DeserializeURI(aTargetURI);
nsCOMPtr<nsIURI> sourceURI = DeserializeURI(aSourceURI);
// We only actually care about the loadContext.mPrivateBrowsing, so we'll just
// pass dummy params for nestFrameId, inBrowser and appId
uint64_t nestedFrameId = 0;
nsCOMPtr<nsILoadContext> loadContext;
if (aLoadContext.IsNotNull()) {
loadContext = new LoadContext(aLoadContext, nestedFrameId, NECKO_UNKNOWN_APP_ID, false);
}
// Get the current predictor
nsresult rv = NS_OK;
nsCOMPtr<nsINetworkPredictor> predictor =
do_GetService("@mozilla.org/network/predictor;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
predictor->Learn(targetURI, sourceURI, aReason, loadContext);
return true;
}
bool
NeckoParent::RecvPredReset()
{
// Get the current predictor
nsresult rv = NS_OK;
nsCOMPtr<nsINetworkPredictor> predictor =
do_GetService("@mozilla.org/network/predictor;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
predictor->Reset();
return true;
}
nsresult
NeckoParent::OfflineNotification(nsISupports *aSubject)
{
+19
View File
@@ -8,6 +8,7 @@
#include "mozilla/net/PNeckoParent.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/OfflineObserver.h"
#include "nsINetworkPredictor.h"
#ifndef mozilla_net_NeckoParent_h
#define mozilla_net_NeckoParent_h
@@ -208,12 +209,30 @@ protected:
virtual bool RecvOnAuthCancelled(const uint64_t& aCallbackId,
const bool& aUserCancel) override;
/* Predictor Messages */
virtual bool RecvPredPredict(const ipc::OptionalURIParams& aTargetURI,
const ipc::OptionalURIParams& aSourceURI,
const PredictorPredictReason& aReason,
const IPC::SerializedLoadContext& aLoadContext,
const bool& hasVerifier) override;
virtual bool RecvPredLearn(const ipc::URIParams& aTargetURI,
const ipc::OptionalURIParams& aSourceURI,
const PredictorPredictReason& aReason,
const IPC::SerializedLoadContext& aLoadContext) override;
virtual bool RecvPredReset() override;
private:
nsCString mCoreAppsBasePath;
nsCString mWebAppsBasePath;
nsRefPtr<OfflineObserver> mObserver;
};
/**
* Reference to the PNecko Parent protocol.
*/
extern PNeckoParent *gNeckoParent;
} // namespace net
} // namespace mozilla
+13
View File
@@ -72,6 +72,15 @@ parent:
PDNSRequest(nsCString hostName, uint32_t flags, nsCString networkInterface);
/* Predictor Methods */
PredPredict(OptionalURIParams targetURI, OptionalURIParams sourceURI,
uint32_t reason, SerializedLoadContext loadContext,
bool hasVerifier);
PredLearn(URIParams targetURI, OptionalURIParams sourceURI,
uint32_t reason, SerializedLoadContext loadContext);
PredReset();
PRemoteOpenFile(SerializedLoadContext loadContext,
URIParams fileuri,
OptionalURIParams appuri);
@@ -110,6 +119,10 @@ child:
// Notifies child that a given app is now offline (or online)
AppOfflineStatus(uint32_t appId, bool offline);
/* Predictor Methods */
PredOnPredictPreconnect(URIParams uri);
PredOnPredictDNS(URIParams uri);
both:
// Actually we need PTCPSocket() for parent. But ipdl disallows us having different
// signatures on parent and child. So when constructing the parent side object, we just
@@ -228,6 +228,10 @@ Http2BaseCompressor::MakeRoom(uint32_t amount, const char *direction)
void
Http2BaseCompressor::DumpState()
{
if (!LOG_ENABLED()) {
return;
}
LOG(("Header Table"));
uint32_t i;
uint32_t length = mHeaderTable.Length();
@@ -29,7 +29,6 @@
#include "nsITransport.h"
#include "nsISocketTransportService.h"
#include <algorithm>
#include "Http2Compression.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/unused.h"
@@ -174,7 +173,6 @@ nsHttpConnectionMgr::Shutdown()
// wait for shutdown event to complete
while (!shutdown)
NS_ProcessNextEvent(NS_GetCurrentThread());
Http2CompressionCleanup();
return NS_OK;
}
+147 -93
View File
@@ -4,11 +4,14 @@ var Cu = Components.utils;
var Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
var running_single_process = false;
var predictor = null;
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var profile = null;
function is_child_process() {
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
}
function extract_origin(uri) {
var o = uri.scheme + "://" + uri.asciiHost;
@@ -100,11 +103,15 @@ Verifier.prototype = {
};
function reset_predictor() {
predictor.reset();
if (running_single_process || is_child_process()) {
predictor.reset();
} else {
sendCommand("predictor.reset();");
}
}
function newURI(s) {
return ios.newURI(s, null, null);
return Services.io.newURI(s, null, null);
}
var prepListener = {
@@ -155,9 +162,7 @@ function open_and_continue(uris, continueCallback) {
isAnonymous: false
};
var css = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Ci.nsICacheStorageService);
var ds = css.diskCacheStorage(lci, false);
var ds = Services.cache2.diskCacheStorage(lci, false);
prepListener.init(uris.length, continueCallback);
for (var i = 0; i < uris.length; ++i) {
@@ -167,6 +172,13 @@ function open_and_continue(uris, continueCallback) {
}
function test_link_hover() {
if (!running_single_process && !is_child_process()) {
// This one we can just proxy to the child and be done with, no extra setup
// is necessary.
sendCommand("test_link_hover();");
return;
}
var uri = newURI("http://localhost:4444/foo/bar");
var referrer = newURI("http://localhost:4444/foo");
var preconns = ["http://localhost:4444"];
@@ -175,60 +187,82 @@ function test_link_hover() {
predictor.predict(uri, referrer, predictor.PREDICT_LINK, load_context, verifier);
}
function test_pageload() {
var toplevel = "http://localhost:4444/index.html";
const pageload_toplevel = newURI("http://localhost:4444/index.html");
function continue_test_pageload() {
var subresources = [
"http://localhost:4444/style.css",
"http://localhost:4443/jquery.js",
"http://localhost:4444/image.png"
];
var tluri = newURI(toplevel);
open_and_continue([tluri], function () {
// This is necessary to learn the origin stuff
predictor.learn(tluri, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
var preconns = [];
for (var i = 0; i < subresources.length; i++) {
var sruri = newURI(subresources[i]);
predictor.learn(sruri, tluri, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
preconns.push(extract_origin(sruri));
}
// This is necessary to learn the origin stuff
predictor.learn(pageload_toplevel, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
var preconns = [];
for (var i = 0; i < subresources.length; i++) {
var sruri = newURI(subresources[i]);
predictor.learn(sruri, pageload_toplevel, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
preconns.push(extract_origin(sruri));
}
var verifier = new Verifier("pageload", preconns, []);
predictor.predict(tluri, null, predictor.PREDICT_LOAD, load_context, verifier);
var verifier = new Verifier("pageload", preconns, []);
predictor.predict(pageload_toplevel, null, predictor.PREDICT_LOAD, load_context, verifier);
}
function test_pageload() {
open_and_continue([pageload_toplevel], function () {
if (running_single_process) {
continue_test_pageload();
} else {
sendCommand("continue_test_pageload();");
}
});
}
function test_redirect() {
var initial = "http://localhost:4443/redirect";
var target = "http://localhost:4444/index.html";
const redirect_inituri = newURI("http://localhost:4443/redirect");
const redirect_targeturi = newURI("http://localhost:4444/index.html");
function continue_test_redrect() {
var subresources = [
"http://localhost:4444/style.css",
"http://localhost:4443/jquery.js",
"http://localhost:4444/image.png"
];
var inituri = newURI(initial);
var targeturi = newURI(target);
open_and_continue([inituri, targeturi], function () {
predictor.learn(inituri, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
predictor.learn(targeturi, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
predictor.learn(targeturi, inituri, predictor.LEARN_LOAD_REDIRECT, load_context);
predictor.learn(redirect_inituri, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
predictor.learn(redirect_targeturi, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
predictor.learn(redirect_targeturi, redirect_inituri, predictor.LEARN_LOAD_REDIRECT, load_context);
var preconns = [];
preconns.push(extract_origin(targeturi));
for (var i = 0; i < subresources.length; i++) {
var sruri = newURI(subresources[i]);
predictor.learn(sruri, targeturi, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
preconns.push(extract_origin(sruri));
var preconns = [];
preconns.push(extract_origin(redirect_targeturi));
for (var i = 0; i < subresources.length; i++) {
var sruri = newURI(subresources[i]);
predictor.learn(sruri, redirect_targeturi, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
preconns.push(extract_origin(sruri));
}
var verifier = new Verifier("redirect", preconns, []);
predictor.predict(redirect_inituri, null, predictor.PREDICT_LOAD, load_context, verifier);
}
function test_redirect() {
open_and_continue([redirect_inituri, redirect_targeturi], function () {
if (running_single_process) {
continue_test_redirect();
} else {
sendCommand("continue_test_redirect();");
}
var verifier = new Verifier("redirect", preconns, []);
predictor.predict(inituri, null, predictor.PREDICT_LOAD, load_context, verifier);
});
}
function test_startup() {
if (!running_single_process && !is_child_process()) {
// This one we can just proxy to the child and be done with, no extra setup
// is necessary.
sendCommand("test_startup();");
return;
}
var uris = [
"http://localhost:4444/startup",
"http://localhost:4443/startup"
@@ -244,57 +278,69 @@ function test_startup() {
predictor.predict(null, null, predictor.PREDICT_STARTUP, load_context, verifier);
}
function test_dns() {
var toplevel = "http://localhost:4444/index.html";
const dns_toplevel = newURI("http://localhost:4444/index.html");
function continue_test_dns() {
var subresource = "http://localhost:4443/jquery.js";
var tluri = newURI(toplevel);
open_and_continue([tluri], function () {
predictor.learn(tluri, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
var sruri = newURI(subresource);
predictor.learn(sruri, tluri, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
predictor.learn(dns_toplevel, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
var sruri = newURI(subresource);
predictor.learn(sruri, dns_toplevel, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
var preresolves = [extract_origin(sruri)];
var verifier = new Verifier("dns", [], preresolves);
predictor.predict(dns_toplevel, null, predictor.PREDICT_LOAD, load_context, verifier);
}
function test_dns() {
open_and_continue([dns_toplevel], function () {
// Ensure that this will do preresolves
prefs.setIntPref("network.predictor.preconnect-min-confidence", 101);
var preresolves = [extract_origin(sruri)];
var verifier = new Verifier("dns", [], preresolves);
predictor.predict(tluri, null, predictor.PREDICT_LOAD, load_context, verifier);
Services.prefs.setIntPref("network.predictor.preconnect-min-confidence", 101);
if (running_single_process) {
continue_test_dns();
} else {
sendCommand("continue_test_dns();");
}
});
}
function test_origin() {
var toplevel = "http://localhost:4444/index.html";
const origin_toplevel = newURI("http://localhost:4444/index.html");
function continue_test_origin() {
var subresources = [
"http://localhost:4444/style.css",
"http://localhost:4443/jquery.js",
"http://localhost:4444/image.png"
];
var tluri = newURI(toplevel);
open_and_continue([tluri], function () {
predictor.learn(tluri, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
var preconns = [];
for (var i = 0; i < subresources.length; i++) {
var sruri = newURI(subresources[i]);
predictor.learn(sruri, tluri, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
var origin = extract_origin(sruri);
if (preconns.indexOf(origin) === -1) {
preconns.push(origin);
}
predictor.learn(origin_toplevel, null, predictor.LEARN_LOAD_TOPLEVEL, load_context);
var preconns = [];
for (var i = 0; i < subresources.length; i++) {
var sruri = newURI(subresources[i]);
predictor.learn(sruri, origin_toplevel, predictor.LEARN_LOAD_SUBRESOURCE, load_context);
var origin = extract_origin(sruri);
if (preconns.indexOf(origin) === -1) {
preconns.push(origin);
}
}
var loaduri = newURI("http://localhost:4444/anotherpage.html");
var verifier = new Verifier("origin", preconns, []);
predictor.predict(loaduri, null, predictor.PREDICT_LOAD, load_context, verifier);
var loaduri = newURI("http://localhost:4444/anotherpage.html");
var verifier = new Verifier("origin", preconns, []);
predictor.predict(loaduri, null, predictor.PREDICT_LOAD, load_context, verifier);
}
function test_origin() {
open_and_continue([origin_toplevel], function () {
if (running_single_process) {
continue_test_origin();
} else {
sendCommand("continue_test_origin();");
}
});
}
var prefs;
function cleanup() {
observer.cleaningUp = true;
predictor.reset();
reset_predictor();
}
var tests = [
@@ -328,39 +374,47 @@ var observer = {
if (topic != "predictor-reset-complete") {
return;
}
if (this.cleaningUp) {
unregisterObserver();
}
run_next_test();
}
};
function registerObserver() {
var svc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
svc.addObserver(observer, "predictor-reset-complete", false);
Services.obs.addObserver(observer, "predictor-reset-complete", false);
}
function unregisterObserver() {
var svc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
svc.removeObserver(observer, "predictor-reset-complete");
Services.obs.removeObserver(observer, "predictor-reset-complete");
}
function run_test_real() {
tests.forEach(add_test);
do_get_profile()
predictor = Cc["@mozilla.org/network/predictor;1"].getService(Ci.nsINetworkPredictor);
registerObserver();
Services.prefs.setBoolPref("network.predictor.enabled", true);
Services.prefs.setBoolPref("network.predictor.cleaned-up", true);
Services.prefs.setBoolPref("browser.cache.use_new_backend_temp", true);
Services.prefs.setIntPref("browser.cache.use_new_backend", 1);
do_register_cleanup(() => {
Services.prefs.clearUserPref("network.predictor.preconnect-min-confidence");
Services.prefs.clearUserPref("network.predictor.enabled");
Services.prefs.clearUserPref("network.predictor.cleaned-up");
Services.prefs.clearUserPref("browser.cache.use_new_backend_temp");
Services.prefs.clearUserPref("browser.cache.use_new_backend");
});
run_next_test();
}
function run_test() {
tests.forEach(add_test);
profile = do_get_profile();
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
prefs.setBoolPref("network.predictor.enabled", true);
prefs.setBoolPref("network.predictor.cleaned-up", true);
prefs.setBoolPref("browser.cache.use_new_backend_temp", true);
prefs.setIntPref("browser.cache.use_new_backend", 1);
do_register_cleanup(() => {
prefs.clearUserPref("network.predictor.preconnect-min-confidence");
prefs.clearUserPref("network.predictor.enabled");
prefs.clearUserPref("network.predictor.cleaned-up");
prefs.clearUserPref("browser.cache.use_new_backend_temp");
prefs.clearUserPref("browser.cache.use_new_backend");
});
predictor = Cc["@mozilla.org/network/predictor;1"].getService(Ci.nsINetworkPredictor);
registerObserver();
run_next_test();
// This indirection is necessary to make e10s tests work as expected
running_single_process = true;
run_test_real();
}
@@ -0,0 +1,12 @@
function run_test() {
var test_path = do_get_file("../unit/test_predictor.js").path.replace(/\\/g, "/");
load(test_path);
do_load_child_test_harness();
do_test_pending();
sendCommand("load(\"" + test_path + "\");", function () {
sendCommand("predictor = Cc[\"@mozilla.org/network/predictor;1\"].getService(Ci.nsINetworkPredictor);", function() {
run_test_real();
do_test_finished();
});
});
}
+1
View File
@@ -20,6 +20,7 @@ support-files = child_app_offline.js
[test_headers_wrap.js]
[test_httpsuspend_wrap.js]
[test_post_wrap.js]
[test_predictor_wrap.js]
[test_progress_wrap.js]
[test_redirect-caching_canceled_wrap.js]
[test_redirect-caching_failure_wrap.js]
@@ -18,6 +18,7 @@
#include "nsIScriptSecurityManager.h"
#include "nsIStreamListener.h"
#include "nsIStringStream.h"
#include "nsITimer.h"
#include "nsIUploadChannel2.h"
#include "nsIURI.h"
#include "nsIUrlClassifierDBService.h"
@@ -60,6 +61,7 @@ using safe_browsing::ClientDownloadRequest_SignatureInfo;
#define PREF_SB_MALWARE_ENABLED "browser.safebrowsing.malware.enabled"
#define PREF_SB_DOWNLOADS_ENABLED "browser.safebrowsing.downloads.enabled"
#define PREF_SB_DOWNLOADS_REMOTE_ENABLED "browser.safebrowsing.downloads.remote.enabled"
#define PREF_SB_DOWNLOADS_REMOTE_TIMEOUT "browser.safebrowsing.downloads.remote.timeout_ms"
#define PREF_GENERAL_LOCALE "general.useragent.locale"
#define PREF_DOWNLOAD_BLOCK_TABLE "urlclassifier.downloadBlockTable"
#define PREF_DOWNLOAD_ALLOW_TABLE "urlclassifier.downloadAllowTable"
@@ -75,12 +77,14 @@ class PendingDBLookup;
// nsIApplicationReputationQuery and an nsIApplicationReputationCallback. Once
// created by ApplicationReputationService, it is guaranteed to call mCallback.
// This class is private to ApplicationReputationService.
class PendingLookup final : public nsIStreamListener
class PendingLookup final : public nsIStreamListener,
public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSITIMERCALLBACK
// Constructor and destructor.
PendingLookup(nsIApplicationReputationQuery* aQuery,
@@ -125,6 +129,12 @@ private:
// When we started this query
TimeStamp mStartTime;
// The channel used to talk to the remote lookup server
nsCOMPtr<nsIChannel> mChannel;
// Timer to abort this lookup if it takes too long
nsCOMPtr<nsITimer> mTimeoutTimer;
// A protocol buffer for storing things we need in the remote request. We
// store the resource chain (redirect information) as well as signature
// information extracted using the Windows Authenticode API, if the binary is
@@ -739,6 +749,11 @@ PendingLookup::DoLookupInternal()
nsresult
PendingLookup::OnComplete(bool shouldBlock, nsresult rv)
{
if (mTimeoutTimer) {
mTimeoutTimer->Cancel();
mTimeoutTimer = nullptr;
}
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SHOULD_BLOCK,
shouldBlock);
double t = (TimeStamp::Now() - mStartTime).ToMilliseconds();
@@ -927,7 +942,6 @@ PendingLookup::SendRemoteQueryInternal()
NS_ENSURE_SUCCESS(rv, rv);
// Set up the channel to transmit the request to the service.
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
rv = ios->NewChannel2(serviceUrl,
nullptr,
@@ -937,14 +951,14 @@ PendingLookup::SendRemoteQueryInternal()
nullptr, // aTriggeringPrincipal
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
getter_AddRefs(channel));
getter_AddRefs(mChannel));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel, &rv));
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// Upload the protobuf to the application reputation service.
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel, &rv);
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(mChannel, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = uploadChannel->ExplicitSetUploadStream(sstream,
@@ -956,15 +970,29 @@ PendingLookup::SendRemoteQueryInternal()
// sent with this request. See bug 897516.
nsCOMPtr<nsIInterfaceRequestor> loadContext =
new mozilla::LoadContext(NECKO_SAFEBROWSING_APP_ID);
rv = channel->SetNotificationCallbacks(loadContext);
rv = mChannel->SetNotificationCallbacks(loadContext);
NS_ENSURE_SUCCESS(rv, rv);
rv = channel->AsyncOpen(this, nullptr);
uint32_t timeoutMs = Preferences::GetUint(PREF_SB_DOWNLOADS_REMOTE_TIMEOUT, 10000);
mTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
mTimeoutTimer->InitWithCallback(this, timeoutMs, nsITimer::TYPE_ONE_SHOT);
rv = mChannel->AsyncOpen(this, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
PendingLookup::Notify(nsITimer* aTimer)
{
LOG(("Remote lookup timed out [this = %p]", this));
MOZ_ASSERT(aTimer == mTimeoutTimer);
mChannel->Cancel(NS_ERROR_NET_TIMEOUT);
mTimeoutTimer->Cancel();
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// nsIStreamListener
static NS_METHOD