mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import change from rmottola/Arctic-Fox:
- Bug 1149987 - Part 2: Make ErrorResult unassignable; r=bzbarsky (32661559b) - Bug 1149987 - Part 3: Give ErrorResult a move constructor and a move assignment operator; (27f4c6125) - Bug 1149987 - Part 4: Do not attempt to delete ErrorResult::mMessage when deserializing the object from IPDL; r=bzbarsky (0f9dcc603) - Bug 1110485 P0 Add an ErrorResult constructor that takes nsresult. (72a779666) - Bug 1110485 P1 Refactor Cache IPC requests to use a separate actor. (a7e4c1959) - Bug 1127914 - Part 1 - Duplicate keyed histograms for double submission. (78673277f) - Bug 1127914 - Part 2 - Duplicate normal histograms for double submission. (55c302057) - Bug 1127914 - Part 3 - Submit duplicate histogram data for 'non-classic' telemetry sessions. r=vladan (bb3e49c43) - Bug 1120362 - Part 1 - Enable snapshotting and clearing subsession histograms. (14378a6e5) - Bug 1120362 - Part 2 - Enable snapshotting and clearing keyed subsession histograms. r=vladan (c0e0bfb3e) - partial apply of Bug 1119281 - Fix missing telemetry client id (ae0dc0194) - Bug 1122047 - Part 1 - Sketch out Telemetry environment module. (0419391b0) - Bug 1122047 - Part 2 - Make TelemetryPing shutdown properly on delayed initialization (0102cef09) - Bug 1122061 - Give TelemetryPing a common API for sending pings. (999cb825d) - Bug 1122061 - Move TelemetrySession tests out of test_telemetryPing.js. (2d5b61de1) - Bug 1120362 - Part 3 - Reset subsession histograms on telemetry payload collections. r=vladan (0d3f04df1) - Bug 1120362 - Part 4 - Start new telemetry subsessions on local midnight. r=vladan (93eb9ca21) - Bug 1120363 - Break up Telemetry sessions on environment changes. (a7c8d70c7) - Bug 1122052 - Remove duplicated data from TelemetrySession. (bb905d602) - Bug 1122050 - Remove persona and experiment data from TelemetrySession. (40ca59a9e) - Bug 1134268 - Part 1 - Fix and order Telemetry shutdown for TelemetryPing and TelemetrySession. r=yoric (30d0f0656) - Bug 1134268 - Part 2 - Fixup TelemetryEnvironment shutdown if the module wasnt initialized. r=vladan (ec2875fea) - Bug 1135076 - Missing histograms in childPayloads. r=vladan (9f317cf9d) - Bug 1134279 - Make TelemetryPing and TelemetrySession code use the "FHR enabled" & "Telemetry enabled" prefs properly. r=vladan (4050d7f24) - Bug 1128768: Part 1 - Modify IPC to allow retrieval of topmost routing id on the stack; (cd2e8a2f0) - Bug 1129249 - Add a "restyle" feature to profiler and split the style label in Cleopatra based on the restyleSource, r=dholbert,mstange (b37df94d1) - Bug 1150684: Remove XPCOM.h from IOInterposer.h (5b7e1cef3) - Bug 1093934 - Create a XPCOM library that can be used to support standalone WebRTC. (9ec8a819f) - Merge branch 'master' of https://github.com/rmottola/Arctic-Fox (d0f05eea4) - Bug 1128768: Part 2,3,4 - Refactor hang annotation code; (f5086aba9) (with xpcom/threads/ fixes for my tele-removed tree) - Bug 1128768: Part 5 - Update plugin code to retrieve SWF file for hang annotations; (774a47aec) - Bug 1110485 P2 Remove 'P' prefix from non-protocol IPC types in Cache API. r=baku (ea29a10cf) - Bug 1110485 P3 Move Fetch IPC PHeaderEntry type to Cache. Rename HeadesEntry. (9eba0aca0) - Bug 1110485 P4 Keep Cache Actors alive during async operations. (eb75f2316) - Bug 1110485 P5 Replace useless DBSchema class type with namespace. (159b902db) - Bug 1110485 P6 Remove useless cache::FileUtils type (1bdf00fc3) - Bug 1110485 P7 Rename DeleteCache() to DeleteCacheId() better distinguish it from CacheDelete(). (5199f9d6f) - Bug 1110485 P8 Correctly set the Feature on the stream control child actor. (c8673cb13) - Bug 1150691 Fix Cache API race with storage invalidation. (2723dff50) - Bug 1151892 Refactor Cache Manager Context usage to be more sane and fix shutdown assert. r=ehsan (ea96381cf) - Bug 1136331 - OdinMonkey: allow stdlib calls in heap expressions (2fc5e2bfd) - Bug 1141439 - Exit with an error code instead of falling through the REMOTE_NOT_FOUND code path when the X-remote returns an explicit command line handler error. (afcf9b1aa) - Bug 1135825: Add missing MOZ_OVERRIDE annotation in RTCIdentityProviderRegistrar.h (e8beec4e8) - (Bug 1135138 is not merged due to broken build)
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "AccessCheck.h"
|
||||
#include "jsfriendapi.h"
|
||||
@@ -147,6 +148,9 @@ ErrorResult::ThrowErrorWithMessage(va_list ap, const dom::ErrNum errorNumber,
|
||||
message->mArgs.AppendElement(*va_arg(ap, nsString*));
|
||||
}
|
||||
mMessage = message;
|
||||
#ifdef DEBUG
|
||||
mHasMessage = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -154,6 +158,7 @@ ErrorResult::SerializeMessage(IPC::Message* aMsg) const
|
||||
{
|
||||
using namespace IPC;
|
||||
MOZ_ASSERT(mMessage);
|
||||
MOZ_ASSERT(mHasMessage);
|
||||
WriteParam(aMsg, mMessage->mArgs);
|
||||
WriteParam(aMsg, mMessage->mErrorNumber);
|
||||
}
|
||||
@@ -167,10 +172,11 @@ ErrorResult::DeserializeMessage(const IPC::Message* aMsg, void** aIter)
|
||||
!ReadParam(aMsg, aIter, &readMessage->mErrorNumber)) {
|
||||
return false;
|
||||
}
|
||||
if (mMessage) {
|
||||
delete mMessage;
|
||||
}
|
||||
MOZ_ASSERT(!mHasMessage);
|
||||
mMessage = readMessage.forget();
|
||||
#ifdef DEBUG
|
||||
mHasMessage = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -196,6 +202,7 @@ void
|
||||
ErrorResult::ReportErrorWithMessage(JSContext* aCx)
|
||||
{
|
||||
MOZ_ASSERT(mMessage, "ReportErrorWithMessage() can be called only once");
|
||||
MOZ_ASSERT(mHasMessage);
|
||||
|
||||
Message* message = mMessage;
|
||||
const uint32_t argCount = message->mArgs.Length();
|
||||
@@ -218,6 +225,9 @@ ErrorResult::ClearMessage()
|
||||
if (IsErrorWithMessage()) {
|
||||
delete mMessage;
|
||||
mMessage = nullptr;
|
||||
#ifdef DEBUG
|
||||
mHasMessage = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,6 +239,9 @@ ErrorResult::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn)
|
||||
|
||||
if (IsErrorWithMessage()) {
|
||||
delete mMessage;
|
||||
#ifdef DEBUG
|
||||
mHasMessage = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Make sure mJSException is initialized _before_ we try to root it. But
|
||||
@@ -375,6 +388,44 @@ ErrorResult::SuppressException()
|
||||
mResult = NS_OK;
|
||||
}
|
||||
|
||||
ErrorResult&
|
||||
ErrorResult::operator=(ErrorResult&& aRHS)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mMightHaveUnreportedJSException = aRHS.mMightHaveUnreportedJSException;
|
||||
aRHS.mMightHaveUnreportedJSException = false;
|
||||
#endif
|
||||
if (aRHS.IsErrorWithMessage()) {
|
||||
mMessage = aRHS.mMessage;
|
||||
aRHS.mMessage = nullptr;
|
||||
#ifdef DEBUG
|
||||
mHasMessage = aRHS.mHasMessage;
|
||||
aRHS.mHasMessage = false;
|
||||
#endif
|
||||
} else if (aRHS.IsJSException()) {
|
||||
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
MOZ_ASSERT(cx);
|
||||
mJSException.setUndefined();
|
||||
if (!js::AddRawValueRoot(cx, &mJSException, "ErrorResult::mJSException")) {
|
||||
MOZ_CRASH("Could not root mJSException, we're about to OOM");
|
||||
}
|
||||
mJSException = aRHS.mJSException;
|
||||
aRHS.mJSException.setUndefined();
|
||||
js::RemoveRawValueRoot(cx, &aRHS.mJSException);
|
||||
} else {
|
||||
// Null out the union on both sides for hygiene purposes.
|
||||
mMessage = aRHS.mMessage = nullptr;
|
||||
#ifdef DEBUG
|
||||
mHasMessage = aRHS.mHasMessage = false;
|
||||
#endif
|
||||
}
|
||||
// Note: It's important to do this last, since this affects the condition
|
||||
// checks above!
|
||||
mResult = aRHS.mResult;
|
||||
aRHS.mResult = NS_OK;
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
bool
|
||||
|
||||
+40
-22
@@ -17,6 +17,7 @@
|
||||
#include "nscore.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
@@ -47,6 +48,7 @@ public:
|
||||
|
||||
#ifdef DEBUG
|
||||
mMightHaveUnreportedJSException = false;
|
||||
mHasMessage = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -54,19 +56,25 @@ public:
|
||||
~ErrorResult() {
|
||||
MOZ_ASSERT_IF(IsErrorWithMessage(), !mMessage);
|
||||
MOZ_ASSERT(!mMightHaveUnreportedJSException);
|
||||
MOZ_ASSERT(!mHasMessage);
|
||||
}
|
||||
#endif
|
||||
|
||||
ErrorResult(ErrorResult&& aRHS)
|
||||
{
|
||||
*this = Move(aRHS);
|
||||
}
|
||||
ErrorResult& operator=(ErrorResult&& aRHS);
|
||||
|
||||
explicit ErrorResult(nsresult aRv)
|
||||
: ErrorResult()
|
||||
{
|
||||
AssignErrorCode(aRv);
|
||||
}
|
||||
|
||||
void Throw(nsresult rv) {
|
||||
MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
|
||||
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
||||
MOZ_ASSERT(rv != NS_ERROR_RANGE_ERR, "Use ThrowRangeError()");
|
||||
MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
|
||||
MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
|
||||
MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
|
||||
MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
|
||||
MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
|
||||
mResult = rv;
|
||||
AssignErrorCode(rv);
|
||||
}
|
||||
|
||||
// Use SuppressException when you want to suppress any exception that might be
|
||||
@@ -147,14 +155,7 @@ public:
|
||||
// Throw() here because people can easily pass success codes to
|
||||
// this.
|
||||
void operator=(nsresult rv) {
|
||||
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
||||
MOZ_ASSERT(rv != NS_ERROR_RANGE_ERR, "Use ThrowRangeError()");
|
||||
MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
|
||||
MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
|
||||
MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
|
||||
MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
|
||||
MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
|
||||
mResult = rv;
|
||||
AssignErrorCode(rv);
|
||||
}
|
||||
|
||||
bool Failed() const {
|
||||
@@ -166,6 +167,24 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct IPC::ParamTraits<ErrorResult>;
|
||||
void SerializeMessage(IPC::Message* aMsg) const;
|
||||
bool DeserializeMessage(const IPC::Message* aMsg, void** aIter);
|
||||
|
||||
void ThrowErrorWithMessage(va_list ap, const dom::ErrNum errorNumber,
|
||||
nsresult errorType);
|
||||
|
||||
void AssignErrorCode(nsresult aRv) {
|
||||
MOZ_ASSERT(aRv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_RANGE_ERR, "Use ThrowRangeError()");
|
||||
MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
|
||||
MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
|
||||
MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
|
||||
mResult = aRv;
|
||||
}
|
||||
|
||||
nsresult mResult;
|
||||
struct Message;
|
||||
// mMessage is set by ThrowErrorWithMessage and cleared (and deallocated) by
|
||||
@@ -177,21 +196,20 @@ private:
|
||||
JS::Value mJSException; // valid when IsJSException()
|
||||
};
|
||||
|
||||
friend struct IPC::ParamTraits<ErrorResult>;
|
||||
void SerializeMessage(IPC::Message* aMsg) const;
|
||||
bool DeserializeMessage(const IPC::Message* aMsg, void** aIter);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Used to keep track of codepaths that might throw JS exceptions,
|
||||
// for assertion purposes.
|
||||
bool mMightHaveUnreportedJSException;
|
||||
// Used to keep track of whether mMessage has ever been assigned to.
|
||||
// We need to check this in order to ensure that not attempting to
|
||||
// delete mMessage in DeserializeMessage doesn't leak memory.
|
||||
bool mHasMessage;
|
||||
#endif
|
||||
|
||||
// Not to be implemented, to make sure people always pass this by
|
||||
// reference, not by value.
|
||||
ErrorResult(const ErrorResult&) = delete;
|
||||
void ThrowErrorWithMessage(va_list ap, const dom::ErrNum errorNumber,
|
||||
nsresult errorType);
|
||||
void operator=(const ErrorResult&) = delete;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Vendored
+2
@@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/cache/ActorChild.h"
|
||||
|
||||
#include "mozilla/dom/cache/Feature.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -25,6 +26,7 @@ ActorChild::SetFeature(Feature* aFeature)
|
||||
void
|
||||
ActorChild::RemoveFeature()
|
||||
{
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), mFeature);
|
||||
if (mFeature) {
|
||||
mFeature->RemoveActor(this);
|
||||
mFeature = nullptr;
|
||||
|
||||
Vendored
+349
-271
@@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/CacheParent.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
@@ -21,8 +22,8 @@ namespace {
|
||||
|
||||
using mozilla::unused;
|
||||
using mozilla::dom::cache::CachePushStreamChild;
|
||||
using mozilla::dom::cache::PCacheReadStream;
|
||||
using mozilla::dom::cache::PCacheReadStreamOrVoid;
|
||||
using mozilla::dom::cache::CacheReadStream;
|
||||
using mozilla::dom::cache::CacheReadStreamOrVoid;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::FileDescriptorSetChild;
|
||||
using mozilla::ipc::FileDescriptorSetParent;
|
||||
@@ -35,7 +36,7 @@ enum CleanupAction
|
||||
};
|
||||
|
||||
void
|
||||
CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
CleanupChildFds(CacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
if (aReadStream.fds().type() !=
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
@@ -59,7 +60,7 @@ CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
}
|
||||
|
||||
void
|
||||
CleanupChildPushStream(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
CleanupChildPushStream(CacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
if (!aReadStream.pushStreamChild()) {
|
||||
return;
|
||||
@@ -78,24 +79,24 @@ CleanupChildPushStream(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
}
|
||||
|
||||
void
|
||||
CleanupChild(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
CleanupChild(CacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
CleanupChildFds(aReadStream, aAction);
|
||||
CleanupChildPushStream(aReadStream, aAction);
|
||||
}
|
||||
|
||||
void
|
||||
CleanupChild(PCacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
|
||||
CleanupChild(CacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
|
||||
{
|
||||
if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupChild(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
|
||||
CleanupChild(aReadStreamOrVoid.get_CacheReadStream(), aAction);
|
||||
}
|
||||
|
||||
void
|
||||
CleanupParentFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
CleanupParentFds(CacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
if (aReadStream.fds().type() !=
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
|
||||
@@ -119,13 +120,13 @@ CleanupParentFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
}
|
||||
|
||||
void
|
||||
CleanupParentFds(PCacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
|
||||
CleanupParentFds(CacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
|
||||
{
|
||||
if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupParentFds(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
|
||||
CleanupParentFds(aReadStreamOrVoid.get_CacheReadStream(), aAction);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@@ -136,171 +137,381 @@ namespace cache {
|
||||
|
||||
using mozilla::ipc::PBackgroundParent;
|
||||
|
||||
AutoChildBase::AutoChildBase(TypeUtils* aTypeUtils)
|
||||
// --------------------------------------------
|
||||
|
||||
AutoChildOpArgs::AutoChildOpArgs(TypeUtils* aTypeUtils,
|
||||
const CacheOpArgs& aOpArgs)
|
||||
: mTypeUtils(aTypeUtils)
|
||||
, mOpArgs(aOpArgs)
|
||||
, mSent(false)
|
||||
{
|
||||
MOZ_ASSERT(mTypeUtils);
|
||||
}
|
||||
|
||||
AutoChildBase::~AutoChildBase()
|
||||
{
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoChildRequest::AutoChildRequest(TypeUtils* aTypeUtils)
|
||||
: AutoChildBase(aTypeUtils)
|
||||
{
|
||||
mRequestOrVoid = void_t();
|
||||
}
|
||||
|
||||
AutoChildRequest::~AutoChildRequest()
|
||||
{
|
||||
if (mRequestOrVoid.type() != PCacheRequestOrVoid::TPCacheRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
CleanupChild(mRequestOrVoid.get_PCacheRequest().body(), action);
|
||||
}
|
||||
|
||||
void
|
||||
AutoChildRequest::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
MOZ_ASSERT(mRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t);
|
||||
mRequestOrVoid = PCacheRequest();
|
||||
mTypeUtils->ToPCacheRequest(mRequestOrVoid.get_PCacheRequest(), aRequest,
|
||||
aBodyAction, aReferrerAction, aSchemeAction, aRv);
|
||||
}
|
||||
|
||||
const PCacheRequest&
|
||||
AutoChildRequest::SendAsRequest()
|
||||
{
|
||||
MOZ_ASSERT(mRequestOrVoid.type() == PCacheRequestOrVoid::TPCacheRequest);
|
||||
return mRequestOrVoid.get_PCacheRequest();
|
||||
}
|
||||
|
||||
const PCacheRequestOrVoid&
|
||||
AutoChildRequest::SendAsRequestOrVoid()
|
||||
{
|
||||
return mRequestOrVoid;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoChildRequestList::AutoChildRequestList(TypeUtils* aTypeUtils,
|
||||
uint32_t aCapacity)
|
||||
: AutoChildBase(aTypeUtils)
|
||||
{
|
||||
mRequestList.SetCapacity(aCapacity);
|
||||
}
|
||||
|
||||
AutoChildRequestList::~AutoChildRequestList()
|
||||
AutoChildOpArgs::~AutoChildOpArgs()
|
||||
{
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
|
||||
CleanupChild(mRequestList[i].body(), action);
|
||||
|
||||
switch(mOpArgs.type()) {
|
||||
case CacheOpArgs::TCacheMatchArgs:
|
||||
{
|
||||
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
|
||||
CleanupChild(args.request().body(), action);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheMatchAllArgs:
|
||||
{
|
||||
CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
|
||||
if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) {
|
||||
break;
|
||||
}
|
||||
CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheAddAllArgs:
|
||||
{
|
||||
CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
|
||||
auto& list = args.requestList();
|
||||
for (uint32_t i = 0; i < list.Length(); ++i) {
|
||||
CleanupChild(list[i].body(), action);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCachePutAllArgs:
|
||||
{
|
||||
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
||||
auto& list = args.requestResponseList();
|
||||
for (uint32_t i = 0; i < list.Length(); ++i) {
|
||||
CleanupChild(list[i].request().body(), action);
|
||||
CleanupChild(list[i].response().body(), action);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheDeleteArgs:
|
||||
{
|
||||
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
|
||||
CleanupChild(args.request().body(), action);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheKeysArgs:
|
||||
{
|
||||
CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
|
||||
if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) {
|
||||
break;
|
||||
}
|
||||
CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TStorageMatchArgs:
|
||||
{
|
||||
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
|
||||
CleanupChild(args.request().body(), action);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Other types do not need cleanup
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoChildRequestList::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
// The FileDescriptorSetChild asserts in its destructor that all fds have
|
||||
// been removed. The copy constructor, however, simply duplicates the
|
||||
// fds without removing any. This means each temporary and copy must be
|
||||
// explicitly cleaned up.
|
||||
//
|
||||
// Avoid a lot of this hassle by making sure we only create one here. On
|
||||
// error we remove it.
|
||||
switch(mOpArgs.type()) {
|
||||
case CacheOpArgs::TCacheMatchArgs:
|
||||
{
|
||||
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
|
||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheMatchAllArgs:
|
||||
{
|
||||
CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
|
||||
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
||||
args.requestOrVoid() = CacheRequest();
|
||||
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
||||
aRequest, aBodyAction, aReferrerAction,
|
||||
aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheAddAllArgs:
|
||||
{
|
||||
CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
|
||||
|
||||
PCacheRequest* request = mRequestList.AppendElement();
|
||||
mTypeUtils->ToPCacheRequest(*request, aRequest, aBodyAction, aReferrerAction,
|
||||
aSchemeAction, aRv);
|
||||
if (aRv.Failed()) {
|
||||
mRequestList.RemoveElementAt(mRequestList.Length() - 1);
|
||||
// The FileDescriptorSetChild asserts in its destructor that all fds have
|
||||
// been removed. The copy constructor, however, simply duplicates the
|
||||
// fds without removing any. This means each temporary and copy must be
|
||||
// explicitly cleaned up.
|
||||
//
|
||||
// Avoid a lot of this hassle by making sure we only create one here. On
|
||||
// error we remove it.
|
||||
CacheRequest& request = *args.requestList().AppendElement();
|
||||
|
||||
mTypeUtils->ToCacheRequest(request, aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
if (aRv.Failed()) {
|
||||
args.requestList().RemoveElementAt(args.requestList().Length() - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheDeleteArgs:
|
||||
{
|
||||
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
|
||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheKeysArgs:
|
||||
{
|
||||
CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
|
||||
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
||||
args.requestOrVoid() = CacheRequest();
|
||||
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
||||
aRequest, aBodyAction, aReferrerAction,
|
||||
aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TStorageMatchArgs:
|
||||
{
|
||||
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
|
||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Cache args type cannot send a Request!");
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray<PCacheRequest>&
|
||||
AutoChildRequestList::SendAsRequestList()
|
||||
void
|
||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
switch(mOpArgs.type()) {
|
||||
case CacheOpArgs::TCachePutAllArgs:
|
||||
{
|
||||
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
||||
|
||||
// The FileDescriptorSetChild asserts in its destructor that all fds have
|
||||
// been removed. The copy constructor, however, simply duplicates the
|
||||
// fds without removing any. This means each temporary and copy must be
|
||||
// explicitly cleaned up.
|
||||
//
|
||||
// Avoid a lot of this hassle by making sure we only create one here. On
|
||||
// error we remove it.
|
||||
CacheRequestResponse& pair = *args.requestResponseList().AppendElement();
|
||||
pair.request().body() = void_t();
|
||||
pair.response().body() = void_t();
|
||||
|
||||
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
mTypeUtils->ToCacheResponse(pair.response(), aResponse, aRv);
|
||||
}
|
||||
|
||||
if (aRv.Failed()) {
|
||||
CleanupChild(pair.request().body(), Delete);
|
||||
args.requestResponseList().RemoveElementAt(
|
||||
args.requestResponseList().Length() - 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Cache args type cannot send a Request/Response pair!");
|
||||
}
|
||||
}
|
||||
|
||||
const CacheOpArgs&
|
||||
AutoChildOpArgs::SendAsOpArgs()
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mSent = true;
|
||||
return mRequestList;
|
||||
return mOpArgs;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoChildRequestResponse::AutoChildRequestResponse(TypeUtils* aTypeUtils)
|
||||
: AutoChildBase(aTypeUtils)
|
||||
{
|
||||
// Default IPC-generated constructor does not initialize these correctly
|
||||
// and we check them later when cleaning up.
|
||||
mRequestResponse.request().body() = void_t();
|
||||
mRequestResponse.response().body() = void_t();
|
||||
}
|
||||
|
||||
AutoChildRequestResponse::~AutoChildRequestResponse()
|
||||
{
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
CleanupChild(mRequestResponse.request().body(), action);
|
||||
CleanupChild(mRequestResponse.response().body(), action);
|
||||
}
|
||||
|
||||
void
|
||||
AutoChildRequestResponse::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mTypeUtils->ToPCacheRequest(mRequestResponse.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
AutoChildRequestResponse::Add(Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mTypeUtils->ToPCacheResponse(mRequestResponse.response(), aResponse, aRv);
|
||||
}
|
||||
|
||||
const CacheRequestResponse&
|
||||
AutoChildRequestResponse::SendAsRequestResponse()
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mSent = true;
|
||||
return mRequestResponse;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoParentBase::AutoParentBase(PBackgroundParent* aManager)
|
||||
AutoParentOpResult::AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager,
|
||||
const CacheOpResult& aOpResult)
|
||||
: mManager(aManager)
|
||||
, mOpResult(aOpResult)
|
||||
, mStreamControl(nullptr)
|
||||
, mSent(false)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
}
|
||||
|
||||
AutoParentBase::~AutoParentBase()
|
||||
AutoParentOpResult::~AutoParentOpResult()
|
||||
{
|
||||
if (!mSent && mStreamControl) {
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
|
||||
switch (mOpResult.type()) {
|
||||
case CacheOpResult::TCacheMatchResult:
|
||||
{
|
||||
CacheMatchResult& result = mOpResult.get_CacheMatchResult();
|
||||
if (result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t) {
|
||||
break;
|
||||
}
|
||||
CleanupParentFds(result.responseOrVoid().get_CacheResponse().body(),
|
||||
action);
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheMatchAllResult:
|
||||
{
|
||||
CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
|
||||
for (uint32_t i = 0; i < result.responseList().Length(); ++i) {
|
||||
CleanupParentFds(result.responseList()[i].body(), action);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheKeysResult:
|
||||
{
|
||||
CacheKeysResult& result = mOpResult.get_CacheKeysResult();
|
||||
for (uint32_t i = 0; i < result.requestList().Length(); ++i) {
|
||||
CleanupParentFds(result.requestList()[i].body(), action);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageMatchResult:
|
||||
{
|
||||
StorageMatchResult& result = mOpResult.get_StorageMatchResult();
|
||||
if (result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t) {
|
||||
break;
|
||||
}
|
||||
CleanupParentFds(result.responseOrVoid().get_CacheResponse().body(),
|
||||
action);
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageOpenResult:
|
||||
{
|
||||
StorageOpenResult& result = mOpResult.get_StorageOpenResult();
|
||||
if (action == Forget || result.actorParent() == nullptr) {
|
||||
break;
|
||||
}
|
||||
unused << PCacheParent::Send__delete__(result.actorParent());
|
||||
}
|
||||
default:
|
||||
// other types do not need clean up
|
||||
break;
|
||||
}
|
||||
|
||||
if (action == Delete && mStreamControl) {
|
||||
unused << PCacheStreamControlParent::Send__delete__(mStreamControl);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentBase::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
|
||||
PCacheReadStream* aReadStreamOut)
|
||||
AutoParentOpResult::Add(CacheId aOpenedCacheId, Manager* aManager)
|
||||
{
|
||||
MOZ_ASSERT(mOpResult.type() == CacheOpResult::TStorageOpenResult);
|
||||
MOZ_ASSERT(mOpResult.get_StorageOpenResult().actorParent() == nullptr);
|
||||
mOpResult.get_StorageOpenResult().actorParent() =
|
||||
mManager->SendPCacheConstructor(new CacheParent(aManager, aOpenedCacheId));
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentOpResult::Add(const SavedResponse& aSavedResponse,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
switch (mOpResult.type()) {
|
||||
case CacheOpResult::TCacheMatchResult:
|
||||
{
|
||||
CacheMatchResult& result = mOpResult.get_CacheMatchResult();
|
||||
MOZ_ASSERT(result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t);
|
||||
result.responseOrVoid() = aSavedResponse.mValue;
|
||||
SerializeResponseBody(aSavedResponse, aStreamList,
|
||||
&result.responseOrVoid().get_CacheResponse());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheMatchAllResult:
|
||||
{
|
||||
CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
|
||||
result.responseList().AppendElement(aSavedResponse.mValue);
|
||||
SerializeResponseBody(aSavedResponse, aStreamList,
|
||||
&result.responseList().LastElement());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageMatchResult:
|
||||
{
|
||||
StorageMatchResult& result = mOpResult.get_StorageMatchResult();
|
||||
MOZ_ASSERT(result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t);
|
||||
result.responseOrVoid() = aSavedResponse.mValue;
|
||||
SerializeResponseBody(aSavedResponse, aStreamList,
|
||||
&result.responseOrVoid().get_CacheResponse());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Cache result type cannot handle returning a Response!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentOpResult::Add(const SavedRequest& aSavedRequest,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
switch (mOpResult.type()) {
|
||||
case CacheOpResult::TCacheKeysResult:
|
||||
{
|
||||
CacheKeysResult& result = mOpResult.get_CacheKeysResult();
|
||||
result.requestList().AppendElement(aSavedRequest.mValue);
|
||||
CacheRequest& request = result.requestList().LastElement();
|
||||
|
||||
if (!aSavedRequest.mHasBodyId) {
|
||||
request.body() = void_t();
|
||||
break;
|
||||
}
|
||||
|
||||
request.body() = CacheReadStream();
|
||||
SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
|
||||
&request.body().get_CacheReadStream());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Cache result type cannot handle returning a Request!");
|
||||
}
|
||||
}
|
||||
|
||||
const CacheOpResult&
|
||||
AutoParentOpResult::SendAsOpResult()
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mSent = true;
|
||||
return mOpResult;
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentOpResult::SerializeResponseBody(const SavedResponse& aSavedResponse,
|
||||
StreamList* aStreamList,
|
||||
CacheResponse* aResponseOut)
|
||||
{
|
||||
MOZ_ASSERT(aResponseOut);
|
||||
|
||||
if (!aSavedResponse.mHasBodyId) {
|
||||
aResponseOut->body() = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
aResponseOut->body() = CacheReadStream();
|
||||
SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
|
||||
&aResponseOut->body().get_CacheReadStream());
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentOpResult::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
|
||||
CacheReadStream* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(aStreamList);
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
@@ -328,139 +539,6 @@ AutoParentBase::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
|
||||
readStream->Serialize(aReadStreamOut);
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoParentRequestList::AutoParentRequestList(PBackgroundParent* aManager,
|
||||
uint32_t aCapacity)
|
||||
: AutoParentBase(aManager)
|
||||
{
|
||||
mRequestList.SetCapacity(aCapacity);
|
||||
}
|
||||
|
||||
AutoParentRequestList::~AutoParentRequestList()
|
||||
{
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
|
||||
CleanupParentFds(mRequestList[i].body(), action);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentRequestList::Add(const SavedRequest& aSavedRequest,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
mRequestList.AppendElement(aSavedRequest.mValue);
|
||||
PCacheRequest& request = mRequestList.LastElement();
|
||||
|
||||
if (!aSavedRequest.mHasBodyId) {
|
||||
request.body() = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
request.body() = PCacheReadStream();
|
||||
SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
|
||||
&request.body().get_PCacheReadStream());
|
||||
}
|
||||
|
||||
const nsTArray<PCacheRequest>&
|
||||
AutoParentRequestList::SendAsRequestList()
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mSent = true;
|
||||
return mRequestList;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoParentResponseList::AutoParentResponseList(PBackgroundParent* aManager,
|
||||
uint32_t aCapacity)
|
||||
: AutoParentBase(aManager)
|
||||
{
|
||||
mResponseList.SetCapacity(aCapacity);
|
||||
}
|
||||
|
||||
AutoParentResponseList::~AutoParentResponseList()
|
||||
{
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
for (uint32_t i = 0; i < mResponseList.Length(); ++i) {
|
||||
CleanupParentFds(mResponseList[i].body(), action);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentResponseList::Add(const SavedResponse& aSavedResponse,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
mResponseList.AppendElement(aSavedResponse.mValue);
|
||||
PCacheResponse& response = mResponseList.LastElement();
|
||||
|
||||
if (!aSavedResponse.mHasBodyId) {
|
||||
response.body() = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
response.body() = PCacheReadStream();
|
||||
SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
|
||||
&response.body().get_PCacheReadStream());
|
||||
}
|
||||
|
||||
const nsTArray<PCacheResponse>&
|
||||
AutoParentResponseList::SendAsResponseList()
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mSent = true;
|
||||
return mResponseList;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
AutoParentResponseOrVoid::AutoParentResponseOrVoid(ipc::PBackgroundParent* aManager)
|
||||
: AutoParentBase(aManager)
|
||||
{
|
||||
mResponseOrVoid = void_t();
|
||||
}
|
||||
|
||||
AutoParentResponseOrVoid::~AutoParentResponseOrVoid()
|
||||
{
|
||||
if (mResponseOrVoid.type() != PCacheResponseOrVoid::TPCacheResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
CleanupParentFds(mResponseOrVoid.get_PCacheResponse().body(), action);
|
||||
}
|
||||
|
||||
void
|
||||
AutoParentResponseOrVoid::Add(const SavedResponse& aSavedResponse,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
mResponseOrVoid = aSavedResponse.mValue;
|
||||
PCacheResponse& response = mResponseOrVoid.get_PCacheResponse();
|
||||
|
||||
if (!aSavedResponse.mHasBodyId) {
|
||||
response.body() = void_t();
|
||||
return;
|
||||
}
|
||||
|
||||
response.body() = PCacheReadStream();
|
||||
SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
|
||||
&response.body().get_PCacheReadStream());
|
||||
}
|
||||
|
||||
const PCacheResponseOrVoid&
|
||||
AutoParentResponseOrVoid::SendAsResponseOrVoid()
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
mSent = true;
|
||||
return mResponseOrVoid;
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+34
-105
@@ -8,7 +8,8 @@
|
||||
#define mozilla_dom_cache_AutoUtils_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@@ -29,6 +30,7 @@ class InternalRequest;
|
||||
namespace cache {
|
||||
|
||||
class CacheStreamControlParent;
|
||||
class Manager;
|
||||
struct SavedRequest;
|
||||
struct SavedResponse;
|
||||
class StreamList;
|
||||
@@ -41,129 +43,56 @@ class StreamList;
|
||||
// Note, these should only be used when *sending* streams across IPC. The
|
||||
// deserialization case is handled by creating a ReadStream object.
|
||||
|
||||
class MOZ_STACK_CLASS AutoChildBase
|
||||
class MOZ_STACK_CLASS AutoChildOpArgs final
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
typedef TypeUtils::BodyAction BodyAction;
|
||||
typedef TypeUtils::ReferrerAction ReferrerAction;
|
||||
typedef TypeUtils::SchemeAction SchemeAction;
|
||||
|
||||
AutoChildBase(TypeUtils* aTypeUtils);
|
||||
virtual ~AutoChildBase() = 0;
|
||||
AutoChildOpArgs(TypeUtils* aTypeUtils, const CacheOpArgs& aOpArgs);
|
||||
~AutoChildOpArgs();
|
||||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv);
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
Response& aResponse, ErrorResult& aRv);
|
||||
|
||||
const CacheOpArgs& SendAsOpArgs();
|
||||
|
||||
private:
|
||||
TypeUtils* mTypeUtils;
|
||||
CacheOpArgs mOpArgs;
|
||||
bool mSent;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoChildRequest final : public AutoChildBase
|
||||
class MOZ_STACK_CLASS AutoParentOpResult final
|
||||
{
|
||||
public:
|
||||
explicit AutoChildRequest(TypeUtils* aTypeUtils);
|
||||
~AutoChildRequest();
|
||||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
const PCacheRequest& SendAsRequest();
|
||||
const PCacheRequestOrVoid& SendAsRequestOrVoid();
|
||||
|
||||
private:
|
||||
PCacheRequestOrVoid mRequestOrVoid;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoChildRequestList final : public AutoChildBase
|
||||
{
|
||||
public:
|
||||
AutoChildRequestList(TypeUtils* aTypeUtils, uint32_t aCapacity);
|
||||
~AutoChildRequestList();
|
||||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
const nsTArray<PCacheRequest>& SendAsRequestList();
|
||||
|
||||
private:
|
||||
// Allocates ~5k inline in the stack-only class
|
||||
nsAutoTArray<PCacheRequest, 32> mRequestList;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoChildRequestResponse final : public AutoChildBase
|
||||
{
|
||||
public:
|
||||
explicit AutoChildRequestResponse(TypeUtils* aTypeUtils);
|
||||
~AutoChildRequestResponse();
|
||||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv);
|
||||
void Add(Response& aResponse, ErrorResult& aRv);
|
||||
|
||||
const CacheRequestResponse& SendAsRequestResponse();
|
||||
|
||||
private:
|
||||
CacheRequestResponse mRequestResponse;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoParentBase
|
||||
{
|
||||
protected:
|
||||
explicit AutoParentBase(mozilla::ipc::PBackgroundParent* aManager);
|
||||
virtual ~AutoParentBase() = 0;
|
||||
|
||||
void SerializeReadStream(const nsID& aId, StreamList* aStreamList,
|
||||
PCacheReadStream* aReadStreamOut);
|
||||
|
||||
mozilla::ipc::PBackgroundParent* mManager;
|
||||
CacheStreamControlParent* mStreamControl;
|
||||
bool mSent;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoParentRequestList final : public AutoParentBase
|
||||
{
|
||||
public:
|
||||
AutoParentRequestList(mozilla::ipc::PBackgroundParent* aManager,
|
||||
uint32_t aCapacity);
|
||||
~AutoParentRequestList();
|
||||
AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager,
|
||||
const CacheOpResult& aOpResult);
|
||||
~AutoParentOpResult();
|
||||
|
||||
void Add(CacheId aOpenedCacheId, Manager* aManager);
|
||||
void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
|
||||
void Add(const SavedRequest& aSavedRequest, StreamList* aStreamList);
|
||||
|
||||
const nsTArray<PCacheRequest>& SendAsRequestList();
|
||||
const CacheOpResult& SendAsOpResult();
|
||||
|
||||
private:
|
||||
// Allocates ~5k inline in the stack-only class
|
||||
nsAutoTArray<PCacheRequest, 32> mRequestList;
|
||||
};
|
||||
void SerializeResponseBody(const SavedResponse& aSavedResponse,
|
||||
StreamList* aStreamList,
|
||||
CacheResponse* aResponseOut);
|
||||
|
||||
class MOZ_STACK_CLASS AutoParentResponseList final : public AutoParentBase
|
||||
{
|
||||
public:
|
||||
AutoParentResponseList(mozilla::ipc::PBackgroundParent* aManager,
|
||||
uint32_t aCapacity);
|
||||
~AutoParentResponseList();
|
||||
void SerializeReadStream(const nsID& aId, StreamList* aStreamList,
|
||||
CacheReadStream* aReadStreamOut);
|
||||
|
||||
void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
|
||||
|
||||
const nsTArray<PCacheResponse>& SendAsResponseList();
|
||||
|
||||
private:
|
||||
// Allocates ~4k inline in the stack-only class
|
||||
nsAutoTArray<PCacheResponse, 32> mResponseList;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoParentResponseOrVoid final : public AutoParentBase
|
||||
{
|
||||
public:
|
||||
explicit AutoParentResponseOrVoid(mozilla::ipc::PBackgroundParent* aManager);
|
||||
~AutoParentResponseOrVoid();
|
||||
|
||||
void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
|
||||
|
||||
const PCacheResponseOrVoid& SendAsResponseOrVoid();
|
||||
|
||||
private:
|
||||
PCacheResponseOrVoid mResponseOrVoid;
|
||||
mozilla::ipc::PBackgroundParent* mManager;
|
||||
CacheOpResult mOpResult;
|
||||
CacheStreamControlParent* mStreamControl;
|
||||
bool mSent;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
|
||||
Vendored
+52
-292
@@ -16,7 +16,6 @@
|
||||
#include "mozilla/dom/cache/CacheChild.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/unused.h"
|
||||
@@ -79,17 +78,7 @@ using mozilla::dom::workers::WorkerPrivate;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::Cache);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::Cache);
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(mozilla::dom::cache::Cache)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(mozilla::dom::cache::Cache)
|
||||
tmp->DisconnectFromActor();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mRequestPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(mozilla::dom::cache::Cache)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mRequestPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::Cache)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::Cache, mGlobal);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Cache)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
@@ -111,31 +100,22 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildRequest request(this);
|
||||
CacheQueryParams params;
|
||||
ToCacheQueryParams(params, aOptions);
|
||||
|
||||
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
AutoChildOpArgs args(this, CacheMatchArgs(CacheRequest(), params));
|
||||
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PCacheQueryParams params;
|
||||
ToPCacheQueryParams(params, aOptions);
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendMatch(requestId, request.SendAsRequest(), params);
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -144,12 +124,10 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
CacheQueryParams params;
|
||||
ToCacheQueryParams(params, aOptions);
|
||||
|
||||
AutoChildRequest request(this);
|
||||
AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params));
|
||||
|
||||
if (aRequest.WasPassed()) {
|
||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||
@@ -158,21 +136,13 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PCacheQueryParams params;
|
||||
ToPCacheQueryParams(params, aOptions);
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendMatchAll(requestId, request.SendAsRequestOrVoid(),
|
||||
params);
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -184,27 +154,19 @@ Cache::Add(const RequestOrUSVString& aRequest, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildRequestList requests(this, 1);
|
||||
requests.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
||||
AutoChildOpArgs args(this, CacheAddAllArgs());
|
||||
|
||||
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendAddAll(requestId, requests.SendAsRequestList());
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -213,18 +175,18 @@ Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If there is no work to do, then resolve immediately
|
||||
if (aRequests.IsEmpty()) {
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
AutoChildRequestList requests(this, aRequests.Length());
|
||||
AutoChildOpArgs args(this, CacheAddAllArgs());
|
||||
|
||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
||||
if (!IsValidPutRequestMethod(aRequests[i], aRv)) {
|
||||
@@ -237,18 +199,13 @@ Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
requests.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme,
|
||||
aRv);
|
||||
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendAddAll(requestId, requests.SendAsRequestList());
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -261,32 +218,20 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildRequestResponse put(this);
|
||||
put.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme, aRv);
|
||||
AutoChildOpArgs args(this, CachePutAllArgs());
|
||||
|
||||
args.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme,
|
||||
aResponse, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
put.Add(aResponse, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendPut(requestId, put.SendAsRequestResponse());
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -295,30 +240,22 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildRequest request(this);
|
||||
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
CacheQueryParams params;
|
||||
ToCacheQueryParams(params, aOptions);
|
||||
|
||||
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
|
||||
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PCacheQueryParams params;
|
||||
ToPCacheQueryParams(params, aOptions);
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendDelete(requestId, request.SendAsRequest(), params);
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -327,12 +264,10 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
CacheQueryParams params;
|
||||
ToCacheQueryParams(params, aOptions);
|
||||
|
||||
AutoChildRequest request(this);
|
||||
AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params));
|
||||
|
||||
if (aRequest.WasPassed()) {
|
||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||
@@ -341,20 +276,13 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PCacheQueryParams params;
|
||||
ToPCacheQueryParams(params, aOptions);
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
unused << mActor->SendKeys(requestId, request.SendAsRequestOrVoid(), params);
|
||||
|
||||
return promise.forget();
|
||||
return ExecuteOp(args, aRv);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -401,123 +329,6 @@ Cache::DestroyInternal(CacheChild* aActor)
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RecvMatchResponse(RequestId aRequestId, nsresult aRv,
|
||||
const PCacheResponseOrVoid& aResponse)
|
||||
{
|
||||
// Convert the response immediately if its present. This ensures that
|
||||
// any stream actors are cleaned up, even if we error out below.
|
||||
nsRefPtr<Response> response;
|
||||
if (aResponse.type() == PCacheResponseOrVoid::TPCacheResponse) {
|
||||
response = ToResponse(aResponse);
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(response);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RecvMatchAllResponse(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<PCacheResponse>& aResponses)
|
||||
{
|
||||
// Convert responses immediately. This ensures that any stream actors are
|
||||
// cleaned up, even if we error out below.
|
||||
nsAutoTArray<nsRefPtr<Response>, 256> responses;
|
||||
responses.SetCapacity(aResponses.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aResponses.Length(); ++i) {
|
||||
nsRefPtr<Response> response = ToResponse(aResponses[i]);
|
||||
responses.AppendElement(response.forget());
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(responses);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RecvAddAllResponse(RequestId aRequestId,
|
||||
const mozilla::ErrorResult& aError)
|
||||
{
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (aError.Failed()) {
|
||||
// TODO: Remove this const_cast (bug 1152078).
|
||||
// It is safe for now since this ErrorResult is handed off to us by IPDL
|
||||
// and is thrown into the trash afterwards.
|
||||
promise->MaybeReject(const_cast<ErrorResult&>(aError));
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RecvPutResponse(RequestId aRequestId, nsresult aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RecvDeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess)
|
||||
{
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(aSuccess);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RecvKeysResponse(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<PCacheRequest>& aRequests)
|
||||
{
|
||||
// Convert requests immediately. This ensures that any stream actors are
|
||||
// cleaned up, even if we error out below.
|
||||
nsAutoTArray<nsRefPtr<Request>, 256> requests;
|
||||
requests.SetCapacity(aRequests.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
||||
nsRefPtr<Request> request = ToRequest(aRequests[i]);
|
||||
requests.AppendElement(request.forget());
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(requests);
|
||||
}
|
||||
|
||||
nsIGlobalObject*
|
||||
Cache::GetGlobalObject() const
|
||||
{
|
||||
@@ -538,36 +349,12 @@ Cache::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
NS_ASSERT_OWNINGTHREAD(Cache);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(aStream);
|
||||
auto actor = mActor->SendPCachePushStreamConstructor(
|
||||
new CachePushStreamChild(mActor->GetFeature(), aStream));
|
||||
MOZ_ASSERT(actor);
|
||||
return static_cast<CachePushStreamChild*>(actor);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
// Do nothing. The Promise will automatically drop the ref to us after
|
||||
// calling the callback. This is what we want as we only registered in order
|
||||
// to be held alive via the Promise handle.
|
||||
}
|
||||
|
||||
void
|
||||
Cache::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
// Do nothing. The Promise will automatically drop the ref to us after
|
||||
// calling the callback. This is what we want as we only registered in order
|
||||
// to be held alive via the Promise handle.
|
||||
return mActor->CreatePushStream(aStream);
|
||||
}
|
||||
|
||||
Cache::~Cache()
|
||||
{
|
||||
DisconnectFromActor();
|
||||
}
|
||||
|
||||
void
|
||||
Cache::DisconnectFromActor()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Cache);
|
||||
if (mActor) {
|
||||
mActor->StartDestroy();
|
||||
// DestroyInternal() is called synchronously by StartDestroy(). So we
|
||||
@@ -576,43 +363,16 @@ Cache::DisconnectFromActor()
|
||||
}
|
||||
}
|
||||
|
||||
RequestId
|
||||
Cache::AddRequestPromise(Promise* aPromise, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(!mRequestPromises.Contains(aPromise));
|
||||
|
||||
// Register ourself as a promise handler so that the promise will hold us
|
||||
// alive. This allows the client code to drop the ref to the Cache
|
||||
// object and just keep their promise. This is fairly common in promise
|
||||
// chaining code.
|
||||
aPromise->AppendNativeHandler(this);
|
||||
|
||||
mRequestPromises.AppendElement(aPromise);
|
||||
|
||||
// (Ab)use the promise pointer as our request ID. This is a fast, thread-safe
|
||||
// way to get a unique ID for the promise to be resolved later.
|
||||
return reinterpret_cast<RequestId>(aPromise);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::RemoveRequestPromise(RequestId aRequestId)
|
||||
Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aRequestId != INVALID_REQUEST_ID);
|
||||
|
||||
for (uint32_t i = 0; i < mRequestPromises.Length(); ++i) {
|
||||
nsRefPtr<Promise>& promise = mRequestPromises.ElementAt(i);
|
||||
// To be safe, only cast promise pointers to our integer RequestId
|
||||
// type and never cast an integer to a pointer.
|
||||
if (aRequestId == reinterpret_cast<RequestId>(promise.get())) {
|
||||
nsRefPtr<Promise> ref;
|
||||
ref.swap(promise);
|
||||
mRequestPromises.RemoveElementAt(i);
|
||||
return ref.forget();
|
||||
}
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("Received response without a matching promise!");
|
||||
return nullptr;
|
||||
|
||||
mActor->ExecuteOp(mGlobal, promise, aOpArgs.SendAsOpArgs());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
||||
Vendored
+4
-30
@@ -7,7 +7,6 @@
|
||||
#ifndef mozilla_dom_cache_Cache_h
|
||||
#define mozilla_dom_cache_Cache_h
|
||||
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@@ -33,12 +32,10 @@ template<typename T> class Sequence;
|
||||
|
||||
namespace cache {
|
||||
|
||||
class AutoChildOpArgs;
|
||||
class CacheChild;
|
||||
class PCacheRequest;
|
||||
class PCacheResponse;
|
||||
class PCacheResponseOrVoid;
|
||||
|
||||
class Cache final : public PromiseNativeHandler
|
||||
class Cache final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
, public TypeUtils
|
||||
{
|
||||
@@ -76,20 +73,6 @@ public:
|
||||
// Called when CacheChild actor is being destroyed
|
||||
void DestroyInternal(CacheChild* aActor);
|
||||
|
||||
// methods forwarded from CacheChild
|
||||
void RecvMatchResponse(RequestId aRequestId, nsresult aRv,
|
||||
const PCacheResponseOrVoid& aResponse);
|
||||
void RecvMatchAllResponse(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<PCacheResponse>& aResponses);
|
||||
void RecvAddAllResponse(RequestId aRequestId,
|
||||
const mozilla::ErrorResult& aError);
|
||||
void RecvPutResponse(RequestId aRequestId, nsresult aRv);
|
||||
|
||||
void RecvDeleteResponse(RequestId aRequestId, nsresult aRv,
|
||||
bool aSuccess);
|
||||
void RecvKeysResponse(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<PCacheRequest>& aRequests);
|
||||
|
||||
// TypeUtils methods
|
||||
virtual nsIGlobalObject*
|
||||
GetGlobalObject() const override;
|
||||
@@ -101,26 +84,17 @@ public:
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
// PromiseNativeHandler methods
|
||||
virtual void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
virtual void
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
private:
|
||||
~Cache();
|
||||
|
||||
// Called when we're destroyed or CCed.
|
||||
void DisconnectFromActor();
|
||||
|
||||
// TODO: Replace with actor-per-request model during refactor (bug 1110485)
|
||||
RequestId AddRequestPromise(Promise* aPromise, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> RemoveRequestPromise(RequestId aRequestId);
|
||||
already_AddRefed<Promise>
|
||||
ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
CacheChild* mActor;
|
||||
nsTArray<nsRefPtr<Promise>> mRequestPromises;
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
Vendored
+52
-87
@@ -9,8 +9,8 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/cache/Cache.h"
|
||||
#include "mozilla/dom/cache/PCachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/StreamUtils.h"
|
||||
#include "mozilla/dom/cache/CacheOpChild.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -32,6 +32,7 @@ DeallocPCacheChild(PCacheChild* aActor)
|
||||
|
||||
CacheChild::CacheChild()
|
||||
: mListener(nullptr)
|
||||
, mNumChildActors(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(cache::CacheChild);
|
||||
}
|
||||
@@ -41,6 +42,7 @@ CacheChild::~CacheChild()
|
||||
MOZ_COUNT_DTOR(cache::CacheChild);
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
MOZ_ASSERT(!mListener);
|
||||
MOZ_ASSERT(!mNumChildActors);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -60,6 +62,25 @@ CacheChild::ClearListener()
|
||||
mListener = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||
const CacheOpArgs& aArgs)
|
||||
{
|
||||
mNumChildActors += 1;
|
||||
MOZ_ALWAYS_TRUE(SendPCacheOpConstructor(
|
||||
new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs));
|
||||
}
|
||||
|
||||
CachePushStreamChild*
|
||||
CacheChild::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
mNumChildActors += 1;
|
||||
auto actor = SendPCachePushStreamConstructor(
|
||||
new CachePushStreamChild(GetFeature(), aStream));
|
||||
MOZ_ASSERT(actor);
|
||||
return static_cast<CachePushStreamChild*>(actor);
|
||||
}
|
||||
|
||||
void
|
||||
CacheChild::StartDestroy()
|
||||
{
|
||||
@@ -77,6 +98,14 @@ CacheChild::StartDestroy()
|
||||
// Cache listener should call ClearListener() in DestroyInternal()
|
||||
MOZ_ASSERT(!mListener);
|
||||
|
||||
// If we have outstanding child actors, then don't destroy ourself yet.
|
||||
// The child actors should be short lived and we should allow them to complete
|
||||
// if possible. SendTeardown() will be called when the count drops to zero
|
||||
// in NoteDeletedActor().
|
||||
if (mNumChildActors) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start actor destruction from parent process
|
||||
unused << SendTeardown();
|
||||
}
|
||||
@@ -95,6 +124,21 @@ CacheChild::ActorDestroy(ActorDestroyReason aReason)
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
PCacheOpChild*
|
||||
CacheChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs)
|
||||
{
|
||||
MOZ_CRASH("CacheOpChild should be manually constructed.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::DeallocPCacheOpChild(PCacheOpChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
NoteDeletedActor();
|
||||
return true;
|
||||
}
|
||||
|
||||
PCachePushStreamChild*
|
||||
CacheChild::AllocPCachePushStreamChild()
|
||||
{
|
||||
@@ -106,96 +150,17 @@ bool
|
||||
CacheChild::DeallocPCachePushStreamChild(PCachePushStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
NoteDeletedActor();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& aResponse)
|
||||
void
|
||||
CacheChild::NoteDeletedActor()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
|
||||
AddFeatureToStreamChild(aResponse, GetFeature());
|
||||
|
||||
nsRefPtr<Cache> listener = mListener;
|
||||
if (!listener) {
|
||||
StartDestroyStreamChild(aResponse);
|
||||
return true;
|
||||
mNumChildActors -= 1;
|
||||
if (!mNumChildActors && !mListener) {
|
||||
unused << SendTeardown();
|
||||
}
|
||||
|
||||
listener->RecvMatchResponse(requestId, aRv, aResponse);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvMatchAllResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
nsTArray<PCacheResponse>&& aResponses)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
|
||||
AddFeatureToStreamChild(aResponses, GetFeature());
|
||||
|
||||
nsRefPtr<Cache> listener = mListener;
|
||||
if (!listener) {
|
||||
StartDestroyStreamChild(aResponses);
|
||||
return true;
|
||||
}
|
||||
|
||||
listener->RecvMatchAllResponse(requestId, aRv, aResponses);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvAddAllResponse(const RequestId& requestId,
|
||||
const mozilla::ErrorResult& aError)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
nsRefPtr<Cache> listener = mListener;
|
||||
if (listener) {
|
||||
listener->RecvAddAllResponse(requestId, aError);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvPutResponse(const RequestId& aRequestId, const nsresult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
nsRefPtr<Cache> listener = mListener;
|
||||
if (listener) {
|
||||
listener->RecvPutResponse(aRequestId, aRv);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvDeleteResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
const bool& result)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
nsRefPtr<Cache> listener = mListener;
|
||||
if (listener) {
|
||||
listener->RecvDeleteResponse(requestId, aRv, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvKeysResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
nsTArray<PCacheRequest>&& aRequests)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheChild);
|
||||
|
||||
AddFeatureToStreamChild(aRequests, GetFeature());
|
||||
|
||||
nsRefPtr<Cache> listener = mListener;
|
||||
if (!listener) {
|
||||
StartDestroyStreamChild(aRequests);
|
||||
return true;
|
||||
}
|
||||
|
||||
listener->RecvKeysResponse(requestId, aRv, aRequests);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
||||
Vendored
+25
-18
@@ -10,11 +10,19 @@
|
||||
#include "mozilla/dom/cache/ActorChild.h"
|
||||
#include "mozilla/dom/cache/PCacheChild.h"
|
||||
|
||||
class nsIAsyncInputStream;
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
|
||||
namespace cache {
|
||||
|
||||
class Cache;
|
||||
class CacheOpArgs;
|
||||
class CachePushStreamChild;
|
||||
|
||||
class CacheChild final : public PCacheChild
|
||||
, public ActorChild
|
||||
@@ -30,6 +38,13 @@ public:
|
||||
// trigger ActorDestroy() if it has not been called yet.
|
||||
void ClearListener();
|
||||
|
||||
void
|
||||
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||
const CacheOpArgs& aArgs);
|
||||
|
||||
CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream);
|
||||
|
||||
// ActorChild methods
|
||||
|
||||
// Synchronously call ActorDestroy on our Cache listener and then start the
|
||||
@@ -41,35 +56,27 @@ private:
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual PCacheOpChild*
|
||||
AllocPCacheOpChild(const CacheOpArgs& aOpArgs) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCacheOpChild(PCacheOpChild* aActor) override;
|
||||
|
||||
virtual PCachePushStreamChild*
|
||||
AllocPCachePushStreamChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCachePushStreamChild(PCachePushStreamChild* aActor) override;
|
||||
|
||||
virtual bool
|
||||
RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& aResponse) override;
|
||||
virtual bool
|
||||
RecvMatchAllResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
nsTArray<PCacheResponse>&& responses) override;
|
||||
virtual bool
|
||||
RecvAddAllResponse(const RequestId& requestId,
|
||||
const mozilla::ErrorResult& aError) override;
|
||||
virtual bool
|
||||
RecvPutResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv) override;
|
||||
virtual bool
|
||||
RecvDeleteResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
const bool& result) override;
|
||||
virtual bool
|
||||
RecvKeysResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
nsTArray<PCacheRequest>&& requests) override;
|
||||
// utility methods
|
||||
void
|
||||
NoteDeletedActor();
|
||||
|
||||
// Use a weak ref so actor does not hold DOM object alive past content use.
|
||||
// The Cache object must call ClearListener() to null this before its
|
||||
// destroyed.
|
||||
Cache* MOZ_NON_OWNING_REF mListener;
|
||||
uint32_t mNumChildActors;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
Vendored
-24
@@ -1,24 +0,0 @@
|
||||
/* 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 PBackgroundSharedTypes;
|
||||
|
||||
using mozilla::dom::cache::Namespace from "mozilla/dom/cache/Types.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
// Data needed to initialize a CacheStorage or Cache backend. Don't put
|
||||
// this with the other types in PCacheTypes.ipdlh since we want to import
|
||||
// it into PBackground.ipdl.
|
||||
struct CacheInitData
|
||||
{
|
||||
Namespace namespaceEnum;
|
||||
PrincipalInfo principalInfo;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+248
@@ -0,0 +1,248 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/cache/CacheOpChild.h"
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/cache/Cache.h"
|
||||
#include "mozilla/dom/cache/CacheChild.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const CacheReadStream& aReadStream, Feature* aFeature)
|
||||
{
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
||||
CacheStreamControlChild* cacheControl =
|
||||
static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
|
||||
if (cacheControl) {
|
||||
cacheControl->SetFeature(aFeature);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const CacheResponse& aResponse, Feature* aFeature)
|
||||
{
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
||||
|
||||
if (aResponse.body().type() == CacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddFeatureToStreamChild(aResponse.body().get_CacheReadStream(), aFeature);
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const CacheRequest& aRequest, Feature* aFeature)
|
||||
{
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
||||
|
||||
if (aRequest.body().type() == CacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddFeatureToStreamChild(aRequest.body().get_CacheReadStream(), aFeature);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CacheOpChild::CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
|
||||
Promise* aPromise)
|
||||
: mGlobal(aGlobal)
|
||||
, mPromise(aPromise)
|
||||
{
|
||||
MOZ_ASSERT(mGlobal);
|
||||
MOZ_ASSERT(mPromise);
|
||||
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
||||
SetFeature(aFeature);
|
||||
}
|
||||
|
||||
CacheOpChild::~CacheOpChild()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
||||
MOZ_ASSERT(!mPromise);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpChild::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
||||
|
||||
// If the actor was terminated for some unknown reason, then indicate the
|
||||
// operation is dead.
|
||||
if (mPromise) {
|
||||
mPromise->MaybeReject(NS_ERROR_FAILURE);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
bool
|
||||
CacheOpChild::Recv__delete__(const ErrorResult& aRv,
|
||||
const CacheOpResult& aResult)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
||||
|
||||
if (aRv.Failed()) {
|
||||
MOZ_ASSERT(aResult.type() == CacheOpResult::Tvoid_t);
|
||||
// TODO: Remove this const_cast (bug 1152078).
|
||||
// It is safe for now since this ErrorResult is handed off to us by IPDL
|
||||
// and is thrown into the trash afterwards.
|
||||
mPromise->MaybeReject(const_cast<ErrorResult&>(aRv));
|
||||
mPromise = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (aResult.type()) {
|
||||
case CacheOpResult::TCacheMatchResult:
|
||||
{
|
||||
HandleResponse(aResult.get_CacheMatchResult().responseOrVoid());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheMatchAllResult:
|
||||
{
|
||||
HandleResponseList(aResult.get_CacheMatchAllResult().responseList());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheAddAllResult:
|
||||
case CacheOpResult::TCachePutAllResult:
|
||||
{
|
||||
mPromise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheDeleteResult:
|
||||
{
|
||||
mPromise->MaybeResolve(aResult.get_CacheDeleteResult().success());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheKeysResult:
|
||||
{
|
||||
HandleRequestList(aResult.get_CacheKeysResult().requestList());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageMatchResult:
|
||||
{
|
||||
HandleResponse(aResult.get_StorageMatchResult().responseOrVoid());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageHasResult:
|
||||
{
|
||||
mPromise->MaybeResolve(aResult.get_StorageHasResult().success());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageOpenResult:
|
||||
{
|
||||
auto actor = static_cast<CacheChild*>(
|
||||
aResult.get_StorageOpenResult().actorChild());
|
||||
actor->SetFeature(GetFeature());
|
||||
nsRefPtr<Cache> cache = new Cache(mGlobal, actor);
|
||||
mPromise->MaybeResolve(cache);
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageDeleteResult:
|
||||
{
|
||||
mPromise->MaybeResolve(aResult.get_StorageDeleteResult().success());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TStorageKeysResult:
|
||||
{
|
||||
mPromise->MaybeResolve(aResult.get_StorageKeysResult().keyList());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unknown Cache op result type!");
|
||||
}
|
||||
|
||||
mPromise = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpChild::StartDestroy()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
||||
|
||||
// Do not cancel on-going operations when Feature calls this. Instead, keep
|
||||
// the Worker alive until we are done.
|
||||
}
|
||||
|
||||
nsIGlobalObject*
|
||||
CacheOpChild::GetGlobalObject() const
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
CacheOpChild::AssertOwningThread() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
|
||||
}
|
||||
#endif
|
||||
|
||||
CachePushStreamChild*
|
||||
CacheOpChild::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
MOZ_CRASH("CacheOpChild should never create a push stream actor!");
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpChild::HandleResponse(const CacheResponseOrVoid& aResponseOrVoid)
|
||||
{
|
||||
if (aResponseOrVoid.type() == CacheResponseOrVoid::Tvoid_t) {
|
||||
mPromise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return;
|
||||
}
|
||||
|
||||
const CacheResponse& cacheResponse = aResponseOrVoid.get_CacheResponse();
|
||||
|
||||
AddFeatureToStreamChild(cacheResponse, GetFeature());
|
||||
nsRefPtr<Response> response = ToResponse(cacheResponse);
|
||||
|
||||
mPromise->MaybeResolve(response);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpChild::HandleResponseList(const nsTArray<CacheResponse>& aResponseList)
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<Response>, 256> responses;
|
||||
responses.SetCapacity(aResponseList.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aResponseList.Length(); ++i) {
|
||||
AddFeatureToStreamChild(aResponseList[i], GetFeature());
|
||||
responses.AppendElement(ToResponse(aResponseList[i]));
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(responses);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpChild::HandleRequestList(const nsTArray<CacheRequest>& aRequestList)
|
||||
{
|
||||
nsAutoTArray<nsRefPtr<Request>, 256> requests;
|
||||
requests.SetCapacity(aRequestList.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||
AddFeatureToStreamChild(aRequestList[i], GetFeature());
|
||||
requests.AppendElement(ToRequest(aRequestList[i]));
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(requests);
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Vendored
+80
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_cache_CacheOpChild_h
|
||||
#define mozilla_dom_cache_CacheOpChild_h
|
||||
|
||||
#include "mozilla/dom/cache/ActorChild.h"
|
||||
#include "mozilla/dom/cache/PCacheOpChild.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
|
||||
namespace cache {
|
||||
|
||||
class CacheOpChild final : public PCacheOpChild
|
||||
, public ActorChild
|
||||
, public TypeUtils
|
||||
{
|
||||
friend class CacheChild;
|
||||
friend class CacheStorageChild;
|
||||
|
||||
private:
|
||||
// This class must be constructed by CacheChild or CacheStorageChild using
|
||||
// their ExecuteOp() factory method.
|
||||
CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal, Promise* aPromise);
|
||||
~CacheOpChild();
|
||||
|
||||
// PCacheOpChild methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual bool
|
||||
Recv__delete__(const ErrorResult& aRv, const CacheOpResult& aResult) override;
|
||||
|
||||
// ActorChild methods
|
||||
virtual void
|
||||
StartDestroy() override;
|
||||
|
||||
// TypeUtils methods
|
||||
virtual nsIGlobalObject*
|
||||
GetGlobalObject() const override;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void
|
||||
AssertOwningThread() const override;
|
||||
#endif
|
||||
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
// Utility methods
|
||||
void
|
||||
HandleResponse(const CacheResponseOrVoid& aResponseOrVoid);
|
||||
|
||||
void
|
||||
HandleResponseList(const nsTArray<CacheResponse>& aResponseList);
|
||||
|
||||
void
|
||||
HandleRequestList(const nsTArray<CacheRequest>& aRequestList);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<Promise> mPromise;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_cache_CacheOpChild_h
|
||||
Vendored
+287
@@ -0,0 +1,287 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/cache/CacheOpParent.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamParent.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::ipc::FileDescriptorSetParent;
|
||||
using mozilla::ipc::PBackgroundParent;
|
||||
|
||||
CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager, CacheId aCacheId,
|
||||
const CacheOpArgs& aOpArgs)
|
||||
: mIpcManager(aIpcManager)
|
||||
, mCacheId(aCacheId)
|
||||
, mNamespace(INVALID_NAMESPACE)
|
||||
, mOpArgs(aOpArgs)
|
||||
{
|
||||
MOZ_ASSERT(mIpcManager);
|
||||
}
|
||||
|
||||
CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager,
|
||||
Namespace aNamespace, const CacheOpArgs& aOpArgs)
|
||||
: mIpcManager(aIpcManager)
|
||||
, mCacheId(INVALID_CACHE_ID)
|
||||
, mNamespace(aNamespace)
|
||||
, mOpArgs(aOpArgs)
|
||||
{
|
||||
MOZ_ASSERT(mIpcManager);
|
||||
}
|
||||
|
||||
CacheOpParent::~CacheOpParent()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::Execute(ManagerId* aManagerId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
MOZ_ASSERT(!mManager);
|
||||
MOZ_ASSERT(!mVerifier);
|
||||
|
||||
nsRefPtr<Manager> manager;
|
||||
nsresult rv = Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
unused << Send__delete__(this, ErrorResult(rv), void_t());
|
||||
return;
|
||||
}
|
||||
|
||||
Execute(manager);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::Execute(Manager* aManager)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
MOZ_ASSERT(!mManager);
|
||||
MOZ_ASSERT(!mVerifier);
|
||||
|
||||
mManager = aManager;
|
||||
|
||||
// Handle add/addAll op with a FetchPut object
|
||||
if (mOpArgs.type() == CacheOpArgs::TCacheAddAllArgs) {
|
||||
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
|
||||
|
||||
const CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
|
||||
const nsTArray<CacheRequest>& list = args.requestList();
|
||||
|
||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
|
||||
for (uint32_t i = 0; i < list.Length(); ++i) {
|
||||
requestStreamList.AppendElement(DeserializeCacheStream(list[i].body()));
|
||||
}
|
||||
|
||||
nsRefPtr<FetchPut> fetchPut;
|
||||
nsresult rv = FetchPut::Create(this, mManager, mCacheId, list,
|
||||
requestStreamList, getter_AddRefs(fetchPut));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
OnOpComplete(ErrorResult(rv), CacheAddAllResult());
|
||||
return;
|
||||
}
|
||||
|
||||
mFetchPutList.AppendElement(fetchPut.forget());
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle put op
|
||||
if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
|
||||
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
|
||||
|
||||
const CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
||||
const nsTArray<CacheRequestResponse>& list = args.requestResponseList();
|
||||
|
||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
|
||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> responseStreamList;
|
||||
|
||||
for (uint32_t i = 0; i < list.Length(); ++i) {
|
||||
requestStreamList.AppendElement(
|
||||
DeserializeCacheStream(list[i].request().body()));
|
||||
responseStreamList.AppendElement(
|
||||
DeserializeCacheStream(list[i].response().body()));
|
||||
}
|
||||
|
||||
mManager->ExecutePutAll(this, mCacheId, args.requestResponseList(),
|
||||
requestStreamList, responseStreamList);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle all other cache ops
|
||||
if (mCacheId != INVALID_CACHE_ID) {
|
||||
MOZ_ASSERT(mNamespace == INVALID_NAMESPACE);
|
||||
mManager->ExecuteCacheOp(this, mCacheId, mOpArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle all storage ops
|
||||
MOZ_ASSERT(mNamespace != INVALID_NAMESPACE);
|
||||
mManager->ExecuteStorageOp(this, mNamespace, mOpArgs);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::WaitForVerification(PrincipalVerifier* aVerifier)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
MOZ_ASSERT(!mManager);
|
||||
MOZ_ASSERT(!mVerifier);
|
||||
|
||||
mVerifier = aVerifier;
|
||||
mVerifier->AddListener(this);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
|
||||
if (mVerifier) {
|
||||
mVerifier->RemoveListener(this);
|
||||
mVerifier = nullptr;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
|
||||
mFetchPutList[i]->ClearListener();
|
||||
}
|
||||
mFetchPutList.Clear();
|
||||
|
||||
if (mManager) {
|
||||
mManager->RemoveListener(this);
|
||||
mManager = nullptr;
|
||||
}
|
||||
|
||||
mIpcManager = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
|
||||
mVerifier->RemoveListener(this);
|
||||
mVerifier = nullptr;
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aRv))) {
|
||||
unused << Send__delete__(this, ErrorResult(aRv), void_t());
|
||||
return;
|
||||
}
|
||||
|
||||
Execute(aManagerId);
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
CacheId aOpenedCacheId,
|
||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
MOZ_ASSERT(mIpcManager);
|
||||
MOZ_ASSERT(mManager);
|
||||
|
||||
// Never send an op-specific result if we have an error. Instead, send
|
||||
// void_t() to ensure that we don't leak actors on the child side.
|
||||
if (aRv.Failed()) {
|
||||
unused << Send__delete__(this, aRv, void_t());
|
||||
aRv.ClearMessage(); // This may contain a TypeError.
|
||||
return;
|
||||
}
|
||||
|
||||
// The result must contain the appropriate type at this point. It may
|
||||
// or may not contain the additional result data yet. For types that
|
||||
// do not need special processing, it should already be set. If the
|
||||
// result requires actor-specific operations, then we do that below.
|
||||
// If the type and data types don't match, then we will trigger an
|
||||
// assertion in AutoParentOpResult::Add().
|
||||
AutoParentOpResult result(mIpcManager, aResult);
|
||||
|
||||
if (aOpenedCacheId != INVALID_CACHE_ID) {
|
||||
result.Add(aOpenedCacheId, mManager);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aSavedResponseList.Length(); ++i) {
|
||||
result.Add(aSavedResponseList[i], aStreamList);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aSavedRequestList.Length(); ++i) {
|
||||
result.Add(aSavedRequestList[i], aStreamList);
|
||||
}
|
||||
|
||||
unused << Send__delete__(this, aRv, result.SendAsOpResult());
|
||||
}
|
||||
|
||||
void
|
||||
CacheOpParent::OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
||||
MOZ_ASSERT(aFetchPut);
|
||||
|
||||
aFetchPut->ClearListener();
|
||||
MOZ_ALWAYS_TRUE(mFetchPutList.RemoveElement(aFetchPut));
|
||||
|
||||
OnOpComplete(Move(aRv), CacheAddAllResult());
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
CacheOpParent::DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid)
|
||||
{
|
||||
if (aStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
const CacheReadStream& readStream = aStreamOrVoid.get_CacheReadStream();
|
||||
|
||||
// Option 1: A push stream actor was sent for nsPipe data
|
||||
if (readStream.pushStreamParent()) {
|
||||
MOZ_ASSERT(!readStream.controlParent());
|
||||
CachePushStreamParent* pushStream =
|
||||
static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
|
||||
stream = pushStream->TakeReader();
|
||||
MOZ_ASSERT(stream);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// Option 2: One of our own ReadStreams was passed back to us with a stream
|
||||
// control actor.
|
||||
stream = ReadStream::Create(readStream);
|
||||
if (stream) {
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// Option 3: A stream was serialized using normal methods.
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
if (readStream.fds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
|
||||
FileDescriptorSetParent* fdSetActor =
|
||||
static_cast<FileDescriptorSetParent*>(readStream.fds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
if (!fdSetActor->Send__delete__(fdSetActor)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to delete fd set actor.");
|
||||
}
|
||||
}
|
||||
|
||||
return DeserializeInputStream(readStream.params(), fds);
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_cache_CacheOpParent_h
|
||||
#define mozilla_dom_cache_CacheOpParent_h
|
||||
|
||||
#include "mozilla/dom/cache/FetchPut.h"
|
||||
#include "mozilla/dom/cache/Manager.h"
|
||||
#include "mozilla/dom/cache/PCacheOpParent.h"
|
||||
#include "mozilla/dom/cache/PrincipalVerifier.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PBackgroundParent;
|
||||
}
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CacheOpParent final : public PCacheOpParent
|
||||
, public PrincipalVerifier::Listener
|
||||
, public Manager::Listener
|
||||
, public FetchPut::Listener
|
||||
{
|
||||
// to allow use of convenience overrides
|
||||
using Manager::Listener::OnOpComplete;
|
||||
|
||||
public:
|
||||
CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager, CacheId aCacheId,
|
||||
const CacheOpArgs& aOpArgs);
|
||||
CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager,
|
||||
Namespace aNamespace, const CacheOpArgs& aOpArgs);
|
||||
~CacheOpParent();
|
||||
|
||||
void
|
||||
Execute(ManagerId* aManagerId);
|
||||
|
||||
void
|
||||
Execute(Manager* aManager);
|
||||
|
||||
void
|
||||
WaitForVerification(PrincipalVerifier* aVerifier);
|
||||
|
||||
private:
|
||||
// PCacheOpParent methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
// PrincipalVerifier::Listener methods
|
||||
virtual void
|
||||
OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId) override;
|
||||
|
||||
// Manager::Listener methods
|
||||
virtual void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
CacheId aOpenedCacheId,
|
||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList) override;
|
||||
|
||||
// FetchPut::Listener methods
|
||||
virtual void
|
||||
OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) override;
|
||||
|
||||
// utility methods
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
|
||||
|
||||
mozilla::ipc::PBackgroundParent* mIpcManager;
|
||||
const CacheId mCacheId;
|
||||
const Namespace mNamespace;
|
||||
const CacheOpArgs mOpArgs;
|
||||
nsRefPtr<Manager> mManager;
|
||||
nsRefPtr<PrincipalVerifier> mVerifier;
|
||||
nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_cache_CacheOpParent_h
|
||||
Vendored
+33
-252
@@ -6,27 +6,14 @@
|
||||
|
||||
#include "mozilla/dom/cache/CacheParent.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
#include "mozilla/dom/cache/CacheOpParent.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamParent.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
#include "mozilla/dom/cache/StreamList.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetParent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::dom::ErrNum;
|
||||
using mozilla::ipc::FileDescriptorSetParent;
|
||||
using mozilla::ipc::PFileDescriptorSetParent;
|
||||
|
||||
// Declared in ActorUtils.h
|
||||
void
|
||||
DeallocPCacheParent(PCacheParent* aActor)
|
||||
@@ -47,22 +34,48 @@ CacheParent::~CacheParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(cache::CacheParent);
|
||||
MOZ_ASSERT(!mManager);
|
||||
MOZ_ASSERT(mFetchPutList.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
|
||||
mFetchPutList[i]->ClearListener();
|
||||
}
|
||||
mFetchPutList.Clear();
|
||||
mManager->RemoveListener(this);
|
||||
mManager->ReleaseCacheId(mCacheId);
|
||||
mManager = nullptr;
|
||||
}
|
||||
|
||||
PCacheOpParent*
|
||||
CacheParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
|
||||
{
|
||||
if (aOpArgs.type() != CacheOpArgs::TCacheMatchArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheMatchAllArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCachePutAllArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheDeleteArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheKeysArgs)
|
||||
{
|
||||
MOZ_CRASH("Invalid operation sent to Cache actor!");
|
||||
}
|
||||
|
||||
return new CacheOpParent(Manager(), mCacheId, aOpArgs);
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::DeallocPCacheOpParent(PCacheOpParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
|
||||
const CacheOpArgs& aOpArgs)
|
||||
{
|
||||
auto actor = static_cast<CacheOpParent*>(aActor);
|
||||
actor->Execute(mManager);
|
||||
return true;
|
||||
}
|
||||
|
||||
PCachePushStreamParent*
|
||||
CacheParent::AllocPCachePushStreamParent()
|
||||
{
|
||||
@@ -86,238 +99,6 @@ CacheParent::RecvTeardown()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
mManager->CacheMatch(this, aRequestId, mCacheId, aRequest,
|
||||
aParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvMatchAll(const RequestId& aRequestId,
|
||||
const PCacheRequestOrVoid& aRequest,
|
||||
const PCacheQueryParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
mManager->CacheMatchAll(this, aRequestId, mCacheId, aRequest, aParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvAddAll(const RequestId& aRequestId,
|
||||
nsTArray<PCacheRequest>&& aRequests)
|
||||
{
|
||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreams;
|
||||
requestStreams.SetCapacity(aRequests.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
||||
requestStreams.AppendElement(DeserializeCacheStream(aRequests[i].body()));
|
||||
}
|
||||
|
||||
nsRefPtr<FetchPut> fetchPut;
|
||||
nsresult rv = FetchPut::Create(this, mManager, aRequestId, mCacheId,
|
||||
aRequests, requestStreams,
|
||||
getter_AddRefs(fetchPut));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR);
|
||||
ErrorResult error;
|
||||
error.Throw(rv);
|
||||
if (!SendAddAllResponse(aRequestId, error)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send AddAll response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
mFetchPutList.AppendElement(fetchPut.forget());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvPut(const RequestId& aRequestId,
|
||||
const CacheRequestResponse& aPut)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
|
||||
nsAutoTArray<CacheRequestResponse, 1> putList;
|
||||
putList.AppendElement(aPut);
|
||||
|
||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 1> requestStreamList;
|
||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 1> responseStreamList;
|
||||
|
||||
requestStreamList.AppendElement(
|
||||
DeserializeCacheStream(aPut.request().body()));
|
||||
responseStreamList.AppendElement(
|
||||
DeserializeCacheStream(aPut.response().body()));
|
||||
|
||||
|
||||
mManager->CachePutAll(this, aRequestId, mCacheId, putList, requestStreamList,
|
||||
responseStreamList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvDelete(const RequestId& aRequestId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
mManager->CacheDelete(this, aRequestId, mCacheId, aRequest, aParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvKeys(const RequestId& aRequestId,
|
||||
const PCacheRequestOrVoid& aRequest,
|
||||
const PCacheQueryParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(mManager);
|
||||
mManager->CacheKeys(this, aRequestId, mCacheId, aRequest, aParams);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::OnCacheMatch(RequestId aRequestId, nsresult aRv,
|
||||
const SavedResponse* aSavedResponse,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
AutoParentResponseOrVoid response(Manager());
|
||||
|
||||
// no match
|
||||
if (NS_FAILED(aRv) || !aSavedResponse || !aStreamList) {
|
||||
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send Match response.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSavedResponse) {
|
||||
response.Add(*aSavedResponse, aStreamList);
|
||||
}
|
||||
|
||||
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send Match response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<SavedResponse>& aSavedResponses,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
AutoParentResponseList responses(Manager(), aSavedResponses.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aSavedResponses.Length(); ++i) {
|
||||
responses.Add(aSavedResponses[i], aStreamList);
|
||||
}
|
||||
|
||||
if (!SendMatchAllResponse(aRequestId, aRv, responses.SendAsResponseList())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send MatchAll response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::OnCachePutAll(RequestId aRequestId, nsresult aRv)
|
||||
{
|
||||
if (!SendPutResponse(aRequestId, aRv)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send Put response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::OnCacheDelete(RequestId aRequestId, nsresult aRv, bool aSuccess)
|
||||
{
|
||||
if (!SendDeleteResponse(aRequestId, aRv, aSuccess)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send Delete response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::OnCacheKeys(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<SavedRequest>& aSavedRequests,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
AutoParentRequestList requests(Manager(), aSavedRequests.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aSavedRequests.Length(); ++i) {
|
||||
requests.Add(aSavedRequests[i], aStreamList);
|
||||
}
|
||||
|
||||
if (!SendKeysResponse(aRequestId, aRv, requests.SendAsRequestList())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send Keys response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheParent::OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId, const ErrorResult& aRv)
|
||||
{
|
||||
aFetchPut->ClearListener();
|
||||
mFetchPutList.RemoveElement(aFetchPut);
|
||||
if (!SendAddAllResponse(aRequestId, aRv)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to send AddAll response.");
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
CacheParent::DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid)
|
||||
{
|
||||
if (aStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
const PCacheReadStream& readStream = aStreamOrVoid.get_PCacheReadStream();
|
||||
|
||||
// Option 1: A push stream actor was sent for nsPipe data
|
||||
if (readStream.pushStreamParent()) {
|
||||
MOZ_ASSERT(!readStream.controlParent());
|
||||
CachePushStreamParent* pushStream =
|
||||
static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
|
||||
stream = pushStream->TakeReader();
|
||||
MOZ_ASSERT(stream);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// Option 2: One of our own ReadStreams was passed back to us with a stream
|
||||
// control actor.
|
||||
stream = ReadStream::Create(readStream);
|
||||
if (stream) {
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// Option 3: A stream was serialized using normal methods.
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
if (readStream.fds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
|
||||
FileDescriptorSetParent* fdSetActor =
|
||||
static_cast<FileDescriptorSetParent*>(readStream.fds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
if (!fdSetActor->Send__delete__(fdSetActor)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("Cache failed to delete fd set actor.");
|
||||
}
|
||||
}
|
||||
|
||||
return DeserializeInputStream(readStream.params(), fds);
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namesapce mozilla
|
||||
|
||||
Vendored
+18
-49
@@ -7,77 +7,46 @@
|
||||
#ifndef mozilla_dom_cache_CacheParent_h
|
||||
#define mozilla_dom_cache_CacheParent_h
|
||||
|
||||
#include "mozilla/dom/cache/FetchPut.h"
|
||||
#include "mozilla/dom/cache/Manager.h"
|
||||
#include "mozilla/dom/cache/PCacheParent.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
|
||||
struct nsID;
|
||||
template <class T> class nsRefPtr;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
struct SavedResponse;
|
||||
class Manager;
|
||||
|
||||
class CacheParent final : public PCacheParent
|
||||
, public Manager::Listener
|
||||
, public FetchPut::Listener
|
||||
{
|
||||
public:
|
||||
CacheParent(cache::Manager* aManager, CacheId aCacheId);
|
||||
virtual ~CacheParent();
|
||||
|
||||
private:
|
||||
// PCacheParent method
|
||||
// PCacheParent methods
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
virtual PCachePushStreamParent* AllocPCachePushStreamParent() override;
|
||||
virtual bool DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
|
||||
virtual bool RecvTeardown() override;
|
||||
virtual bool
|
||||
RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams) override;
|
||||
virtual bool
|
||||
RecvMatchAll(const RequestId& aRequestId, const PCacheRequestOrVoid& aRequest,
|
||||
const PCacheQueryParams& aParams) override;
|
||||
virtual bool
|
||||
RecvAddAll(const RequestId& aRequestId,
|
||||
nsTArray<PCacheRequest>&& aRequests) override;
|
||||
virtual bool
|
||||
RecvPut(const RequestId& aRequestId,
|
||||
const CacheRequestResponse& aPut) override;
|
||||
virtual bool
|
||||
RecvDelete(const RequestId& aRequestId, const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams) override;
|
||||
virtual bool
|
||||
RecvKeys(const RequestId& aRequestId, const PCacheRequestOrVoid& aRequest,
|
||||
const PCacheQueryParams& aParams) override;
|
||||
|
||||
// Manager::Listener methods
|
||||
virtual void OnCacheMatch(RequestId aRequestId, nsresult aRv,
|
||||
const SavedResponse* aSavedResponse,
|
||||
StreamList* aStreamList) override;
|
||||
virtual void OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<SavedResponse>& aSavedResponses,
|
||||
StreamList* aStreamList) override;
|
||||
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) override;
|
||||
virtual void OnCacheDelete(RequestId aRequestId, nsresult aRv,
|
||||
bool aSuccess) override;
|
||||
virtual void OnCacheKeys(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<SavedRequest>& aSavedRequests,
|
||||
StreamList* aStreamList) override;
|
||||
virtual PCacheOpParent*
|
||||
AllocPCacheOpParent(const CacheOpArgs& aOpArgs) override;
|
||||
|
||||
// FetchPut::Listener methods
|
||||
virtual void OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId,
|
||||
const mozilla::ErrorResult& aRv) override;
|
||||
virtual bool
|
||||
DeallocPCacheOpParent(PCacheOpParent* aActor) override;
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid);
|
||||
virtual bool
|
||||
RecvPCacheOpConstructor(PCacheOpParent* actor,
|
||||
const CacheOpArgs& aOpArgs) override;
|
||||
|
||||
virtual PCachePushStreamParent*
|
||||
AllocPCachePushStreamParent() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
|
||||
|
||||
virtual bool
|
||||
RecvTeardown() override;
|
||||
|
||||
nsRefPtr<cache::Manager> mManager;
|
||||
const CacheId mCacheId;
|
||||
nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
|
||||
Vendored
+7
-4
@@ -20,17 +20,20 @@ namespace cache {
|
||||
class CachePushStreamChild final : public PCachePushStreamChild
|
||||
, public ActorChild
|
||||
{
|
||||
friend class CacheChild;
|
||||
|
||||
public:
|
||||
CachePushStreamChild(Feature* aFeature, nsIAsyncInputStream* aStream);
|
||||
~CachePushStreamChild();
|
||||
void Start();
|
||||
|
||||
virtual void StartDestroy() override;
|
||||
|
||||
void Start();
|
||||
|
||||
private:
|
||||
class Callback;
|
||||
|
||||
// This class must be constructed using CacheChild::CreatePushStream()
|
||||
CachePushStreamChild(Feature* aFeature, nsIAsyncInputStream* aStream);
|
||||
~CachePushStreamChild();
|
||||
|
||||
// PCachePushStreamChild methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
Vendored
+81
-286
@@ -41,24 +41,26 @@ using mozilla::ipc::PrincipalToPrincipalInfo;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::CacheStorage);
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::CacheStorage);
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(mozilla::dom::cache::CacheStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(mozilla::dom::cache::CacheStorage)
|
||||
tmp->DisconnectFromActor();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mRequestPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(mozilla::dom::cache::CacheStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mRequestPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::CacheStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::CacheStorage,
|
||||
mGlobal);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CacheStorage)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIPCBackgroundChildCreateCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// We cannot reference IPC types in a webidl binding implementation header. So
|
||||
// define this in the .cpp and use heap storage in the mPendingRequests list.
|
||||
struct CacheStorage::Entry final
|
||||
{
|
||||
nsRefPtr<Promise> mPromise;
|
||||
CacheOpArgs mArgs;
|
||||
// We cannot add the requests until after the actor is present. So store
|
||||
// the request data separately for now.
|
||||
nsRefPtr<InternalRequest> mRequest;
|
||||
};
|
||||
|
||||
// static
|
||||
already_AddRefed<CacheStorage>
|
||||
CacheStorage::CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
@@ -175,29 +177,31 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
if (mFailedActor) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody,
|
||||
aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFailedActor) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return promise.forget();
|
||||
}
|
||||
CacheQueryParams params;
|
||||
ToCacheQueryParams(params, aOptions);
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
Entry entry;
|
||||
entry.mRequestId = requestId;
|
||||
entry.mOp = OP_MATCH;
|
||||
entry.mOptions = aOptions;
|
||||
entry.mRequest = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mPendingRequests.AppendElement(entry);
|
||||
nsAutoPtr<Entry> entry(new Entry());
|
||||
entry->mPromise = promise;
|
||||
entry->mArgs = StorageMatchArgs(CacheRequest(), params);
|
||||
entry->mRequest = request;
|
||||
|
||||
mPendingRequests.AppendElement(entry.forget());
|
||||
MaybeRunPendingRequests();
|
||||
|
||||
return promise.forget();
|
||||
@@ -208,23 +212,21 @@ CacheStorage::Has(const nsAString& aKey, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
if (mFailedActor) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFailedActor) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mRequestId = requestId;
|
||||
entry->mOp = OP_HAS;
|
||||
entry->mKey = aKey;
|
||||
nsAutoPtr<Entry> entry(new Entry());
|
||||
entry->mPromise = promise;
|
||||
entry->mArgs = StorageHasArgs(nsString(aKey));
|
||||
|
||||
mPendingRequests.AppendElement(entry.forget());
|
||||
MaybeRunPendingRequests();
|
||||
|
||||
return promise.forget();
|
||||
@@ -235,23 +237,21 @@ CacheStorage::Open(const nsAString& aKey, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
if (mFailedActor) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFailedActor) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mRequestId = requestId;
|
||||
entry->mOp = OP_OPEN;
|
||||
entry->mKey = aKey;
|
||||
nsAutoPtr<Entry> entry(new Entry());
|
||||
entry->mPromise = promise;
|
||||
entry->mArgs = StorageOpenArgs(nsString(aKey));
|
||||
|
||||
mPendingRequests.AppendElement(entry.forget());
|
||||
MaybeRunPendingRequests();
|
||||
|
||||
return promise.forget();
|
||||
@@ -262,23 +262,21 @@ CacheStorage::Delete(const nsAString& aKey, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
if (mFailedActor) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFailedActor) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mRequestId = requestId;
|
||||
entry->mOp = OP_DELETE;
|
||||
entry->mKey = aKey;
|
||||
nsAutoPtr<Entry> entry(new Entry());
|
||||
entry->mPromise = promise;
|
||||
entry->mArgs = StorageDeleteArgs(nsString(aKey));
|
||||
|
||||
mPendingRequests.AppendElement(entry.forget());
|
||||
MaybeRunPendingRequests();
|
||||
|
||||
return promise.forget();
|
||||
@@ -289,22 +287,21 @@ CacheStorage::Keys(ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
if (mFailedActor) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mFailedActor) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RequestId requestId = AddRequestPromise(promise, aRv);
|
||||
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mRequestId = requestId;
|
||||
entry->mOp = OP_KEYS;
|
||||
nsAutoPtr<Entry> entry(new Entry());
|
||||
entry->mPromise = promise;
|
||||
entry->mArgs = StorageKeysArgs();
|
||||
|
||||
mPendingRequests.AppendElement(entry.forget());
|
||||
MaybeRunPendingRequests();
|
||||
|
||||
return promise.forget();
|
||||
@@ -371,9 +368,8 @@ CacheStorage::ActorFailed()
|
||||
mFeature = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
|
||||
RequestId requestId = mPendingRequests[i].mRequestId;
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(requestId);
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
|
||||
entry->mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
mPendingRequests.Clear();
|
||||
}
|
||||
@@ -392,117 +388,6 @@ CacheStorage::DestroyInternal(CacheStorageChild* aActor)
|
||||
ActorFailed();
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::RecvMatchResponse(RequestId aRequestId, nsresult aRv,
|
||||
const PCacheResponseOrVoid& aResponse)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
// Convert the response immediately if its present. This ensures that
|
||||
// any stream actors are cleaned up, even if we error out below.
|
||||
nsRefPtr<Response> response;
|
||||
if (aResponse.type() == PCacheResponseOrVoid::TPCacheResponse) {
|
||||
response = ToResponse(aResponse);
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
// If cache name was specified in the request options and the cache does
|
||||
// not exist, then an error code will already have been set. If we
|
||||
// still do not have a response, then we just resolve undefined like a
|
||||
// normal Cache::Match.
|
||||
if (!response) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(response);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::RecvHasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
promise->MaybeResolve(aSuccess);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::RecvOpenResponse(RequestId aRequestId, nsresult aRv,
|
||||
CacheChild* aActor)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
// Unlike most of our async callback Recv*() methods, this one gets back
|
||||
// an actor. We need to make sure to clean it up in case of error.
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
if (aActor) {
|
||||
// We cannot use the CacheChild::StartDestroy() method because there
|
||||
// is no Cache object associated with the actor yet. Instead, just
|
||||
// send the underlying Teardown message.
|
||||
unused << aActor->SendTeardown();
|
||||
}
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aActor) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Cache> cache = new Cache(mGlobal, aActor);
|
||||
promise->MaybeResolve(cache);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::RecvDeleteResponse(RequestId aRequestId, nsresult aRv,
|
||||
bool aSuccess)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(aSuccess);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::RecvKeysResponse(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<nsString>& aKeys)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
|
||||
|
||||
if (NS_FAILED(aRv)) {
|
||||
promise->MaybeReject(aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(aKeys);
|
||||
}
|
||||
|
||||
nsIGlobalObject*
|
||||
CacheStorage::GetGlobalObject() const
|
||||
{
|
||||
@@ -524,32 +409,9 @@ CacheStorage::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
MOZ_CRASH("CacheStorage should never create a push stream.");
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
// Do nothing. The Promise will automatically drop the ref to us after
|
||||
// calling the callback. This is what we want as we only registered in order
|
||||
// to be held alive via the Promise handle.
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
// Do nothing. The Promise will automatically drop the ref to us after
|
||||
// calling the callback. This is what we want as we only registered in order
|
||||
// to be held alive via the Promise handle.
|
||||
}
|
||||
|
||||
CacheStorage::~CacheStorage()
|
||||
{
|
||||
DisconnectFromActor();
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::DisconnectFromActor()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
||||
if (mActor) {
|
||||
mActor->StartDestroy();
|
||||
// DestroyInternal() is called synchronously by StartDestroy(). So we
|
||||
@@ -566,89 +428,22 @@ CacheStorage::MaybeRunPendingRequests()
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
|
||||
// Note, the entry can be modified below due to Request/Response body
|
||||
// being marked used.
|
||||
Entry& entry = mPendingRequests[i];
|
||||
RequestId requestId = entry.mRequestId;
|
||||
switch(entry.mOp) {
|
||||
case OP_MATCH:
|
||||
{
|
||||
AutoChildRequest request(this);
|
||||
ErrorResult rv;
|
||||
request.Add(entry.mRequest, IgnoreBody, PassThroughReferrer,
|
||||
IgnoreInvalidScheme, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
nsRefPtr<Promise> promise = RemoveRequestPromise(requestId);
|
||||
promise->MaybeReject(rv);
|
||||
break;
|
||||
}
|
||||
|
||||
PCacheQueryParams params;
|
||||
ToPCacheQueryParams(params, entry.mOptions);
|
||||
|
||||
unused << mActor->SendMatch(requestId, request.SendAsRequest(), params);
|
||||
break;
|
||||
}
|
||||
case OP_HAS:
|
||||
unused << mActor->SendHas(requestId, entry.mKey);
|
||||
break;
|
||||
case OP_OPEN:
|
||||
unused << mActor->SendOpen(requestId, entry.mKey);
|
||||
break;
|
||||
case OP_DELETE:
|
||||
unused << mActor->SendDelete(requestId, entry.mKey);
|
||||
break;
|
||||
case OP_KEYS:
|
||||
unused << mActor->SendKeys(requestId);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown pending CacheStorage op.");
|
||||
ErrorResult rv;
|
||||
nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
|
||||
AutoChildOpArgs args(this, entry->mArgs);
|
||||
if (entry->mRequest) {
|
||||
args.Add(entry->mRequest, IgnoreBody, PassThroughReferrer,
|
||||
IgnoreInvalidScheme, rv);
|
||||
}
|
||||
if (rv.Failed()) {
|
||||
entry->mPromise->MaybeReject(rv);
|
||||
continue;
|
||||
}
|
||||
mActor->ExecuteOp(mGlobal, entry->mPromise, args.SendAsOpArgs());
|
||||
}
|
||||
mPendingRequests.Clear();
|
||||
}
|
||||
|
||||
RequestId
|
||||
CacheStorage::AddRequestPromise(Promise* aPromise, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(!mRequestPromises.Contains(aPromise));
|
||||
|
||||
// Register ourself as a promise handler so that the promise will hold us
|
||||
// alive. This allows the client code to drop the ref to the CacheStorage
|
||||
// object and just keep their promise. This is fairly common in promise
|
||||
// chaining code.
|
||||
aPromise->AppendNativeHandler(this);
|
||||
|
||||
mRequestPromises.AppendElement(aPromise);
|
||||
|
||||
// (Ab)use the promise pointer as our request ID. This is a fast, thread-safe
|
||||
// way to get a unique ID for the promise to be resolved later.
|
||||
return reinterpret_cast<RequestId>(aPromise);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CacheStorage::RemoveRequestPromise(RequestId aRequestId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
MOZ_ASSERT(aRequestId != INVALID_REQUEST_ID);
|
||||
|
||||
for (uint32_t i = 0; i < mRequestPromises.Length(); ++i) {
|
||||
nsRefPtr<Promise>& promise = mRequestPromises.ElementAt(i);
|
||||
// To be safe, only cast promise pointers to our integer RequestId
|
||||
// type and never cast an integer to a pointer.
|
||||
if (aRequestId == reinterpret_cast<RequestId>(promise.get())) {
|
||||
nsRefPtr<Promise> ref;
|
||||
ref.swap(promise);
|
||||
mRequestPromises.RemoveElementAt(i);
|
||||
return ref.forget();
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("Received response without a matching promise!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+4
-54
@@ -8,7 +8,6 @@
|
||||
#define mozilla_dom_cache_CacheStorage_h
|
||||
|
||||
#include "mozilla/dom/CacheBinding.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
@@ -38,15 +37,12 @@ namespace workers {
|
||||
|
||||
namespace cache {
|
||||
|
||||
class CacheChild;
|
||||
class CacheStorageChild;
|
||||
class Feature;
|
||||
class PCacheResponseOrVoid;
|
||||
|
||||
class CacheStorage final : public nsIIPCBackgroundChildCreateCallback
|
||||
, public nsWrapperCache
|
||||
, public TypeUtils
|
||||
, public PromiseNativeHandler
|
||||
{
|
||||
typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
|
||||
|
||||
@@ -81,16 +77,6 @@ public:
|
||||
// Called when CacheStorageChild actor is being destroyed
|
||||
void DestroyInternal(CacheStorageChild* aActor);
|
||||
|
||||
// Methods forwarded from CacheStorageChild
|
||||
void RecvMatchResponse(RequestId aRequestId, nsresult aRv,
|
||||
const PCacheResponseOrVoid& aResponse);
|
||||
void RecvHasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
|
||||
void RecvOpenResponse(RequestId aRequestId, nsresult aRv,
|
||||
CacheChild* aActor);
|
||||
void RecvDeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
|
||||
void RecvKeysResponse(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<nsString>& aKeys);
|
||||
|
||||
// TypeUtils methods
|
||||
virtual nsIGlobalObject* GetGlobalObject() const override;
|
||||
#ifdef DEBUG
|
||||
@@ -100,60 +86,24 @@ public:
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
// PromiseNativeHandler methods
|
||||
virtual void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
virtual void
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
private:
|
||||
CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo, Feature* aFeature);
|
||||
~CacheStorage();
|
||||
|
||||
// Called when we're destroyed or CCed.
|
||||
void DisconnectFromActor();
|
||||
|
||||
void MaybeRunPendingRequests();
|
||||
|
||||
RequestId AddRequestPromise(Promise* aPromise, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> RemoveRequestPromise(RequestId aRequestId);
|
||||
|
||||
// Would like to use CacheInitData here, but we cannot because
|
||||
// its an IPC struct which breaks webidl by including windows.h.
|
||||
const Namespace mNamespace;
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
nsRefPtr<Feature> mFeature;
|
||||
|
||||
// weak ref cleared in DestroyInternal
|
||||
CacheStorageChild* mActor;
|
||||
nsTArray<nsRefPtr<Promise>> mRequestPromises;
|
||||
|
||||
enum Op
|
||||
{
|
||||
OP_MATCH,
|
||||
OP_HAS,
|
||||
OP_OPEN,
|
||||
OP_DELETE,
|
||||
OP_KEYS
|
||||
};
|
||||
struct Entry;
|
||||
nsTArray<nsAutoPtr<Entry>> mPendingRequests;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
RequestId mRequestId;
|
||||
Op mOp;
|
||||
// Would prefer to use PCacheRequest/PCacheCacheQueryOptions, but can't
|
||||
// because they introduce a header dependency on windows.h which
|
||||
// breaks the bindings build.
|
||||
nsRefPtr<InternalRequest> mRequest;
|
||||
CacheQueryOptions mOptions;
|
||||
// It would also be nice to union the key with the match args above,
|
||||
// but VS2013 doesn't like these types in unions because of copy
|
||||
// constructors.
|
||||
nsString mKey;
|
||||
};
|
||||
|
||||
nsTArray<Entry> mPendingRequests;
|
||||
bool mFailedActor;
|
||||
|
||||
public:
|
||||
|
||||
Vendored
+32
-77
@@ -8,8 +8,8 @@
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/CacheChild.h"
|
||||
#include "mozilla/dom/cache/CacheOpChild.h"
|
||||
#include "mozilla/dom/cache/CacheStorage.h"
|
||||
#include "mozilla/dom/cache/StreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -24,6 +24,7 @@ DeallocPCacheStorageChild(PCacheStorageChild* aActor)
|
||||
|
||||
CacheStorageChild::CacheStorageChild(CacheStorage* aListener, Feature* aFeature)
|
||||
: mListener(aListener)
|
||||
, mNumChildActors(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(cache::CacheStorageChild);
|
||||
MOZ_ASSERT(mListener);
|
||||
@@ -46,6 +47,15 @@ CacheStorageChild::ClearListener()
|
||||
mListener = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||
const CacheOpArgs& aArgs)
|
||||
{
|
||||
mNumChildActors += 1;
|
||||
unused << SendPCacheOpConstructor(
|
||||
new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageChild::StartDestroy()
|
||||
{
|
||||
@@ -65,6 +75,14 @@ CacheStorageChild::StartDestroy()
|
||||
// CacheStorage listener should call ClearListener() in DestroyInternal()
|
||||
MOZ_ASSERT(!mListener);
|
||||
|
||||
// If we have outstanding child actors, then don't destroy ourself yet.
|
||||
// The child actors should be short lived and we should allow them to complete
|
||||
// if possible. SendTeardown() will be called when the count drops to zero
|
||||
// in NoteDeletedActor().
|
||||
if (mNumChildActors) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start actor destruction from parent process
|
||||
unused << SendTeardown();
|
||||
}
|
||||
@@ -83,92 +101,29 @@ CacheStorageChild::ActorDestroy(ActorDestroyReason aReason)
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageChild::RecvMatchResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& aResponseOrVoid)
|
||||
PCacheOpChild*
|
||||
CacheStorageChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
|
||||
|
||||
AddFeatureToStreamChild(aResponseOrVoid, GetFeature());
|
||||
|
||||
nsRefPtr<CacheStorage> listener = mListener;
|
||||
if (!listener) {
|
||||
StartDestroyStreamChild(aResponseOrVoid);
|
||||
return true;
|
||||
}
|
||||
|
||||
listener->RecvMatchResponse(aRequestId, aRv, aResponseOrVoid);
|
||||
|
||||
return true;
|
||||
MOZ_CRASH("CacheOpChild should be manually constructed.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageChild::RecvHasResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const bool& aSuccess)
|
||||
CacheStorageChild::DeallocPCacheOpChild(PCacheOpChild* aActor)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
|
||||
nsRefPtr<CacheStorage> listener = mListener;
|
||||
if (listener) {
|
||||
listener->RecvHasResponse(aRequestId, aRv, aSuccess);
|
||||
}
|
||||
delete aActor;
|
||||
NoteDeletedActor();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageChild::RecvOpenResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
PCacheChild* aActor)
|
||||
void
|
||||
CacheStorageChild::NoteDeletedActor()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
|
||||
|
||||
nsRefPtr<CacheStorage> listener = mListener;
|
||||
if (!listener || FeatureNotified()) {
|
||||
if (aActor) {
|
||||
unused << aActor->SendTeardown();
|
||||
}
|
||||
return true;
|
||||
MOZ_ASSERT(mNumChildActors);
|
||||
mNumChildActors -= 1;
|
||||
if (!mNumChildActors && !mListener) {
|
||||
unused << SendTeardown();
|
||||
}
|
||||
|
||||
CacheChild* cacheChild = static_cast<CacheChild*>(aActor);
|
||||
|
||||
// Since FeatureNotified() returned false above, we are guaranteed that
|
||||
// the feature won't try to shutdown the actor until after we create the
|
||||
// Cache DOM object in the listener's RecvOpenResponse() method. This
|
||||
// is important because StartShutdown() expects a Cache object listener.
|
||||
if (cacheChild) {
|
||||
cacheChild->SetFeature(GetFeature());
|
||||
}
|
||||
|
||||
listener->RecvOpenResponse(aRequestId, aRv, cacheChild);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageChild::RecvDeleteResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const bool& aResult)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
|
||||
nsRefPtr<CacheStorage> listener = mListener;
|
||||
if (listener) {
|
||||
listener->RecvDeleteResponse(aRequestId, aRv, aResult);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageChild::RecvKeysResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
nsTArray<nsString>&& aKeys)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
|
||||
nsRefPtr<CacheStorage> listener = mListener;
|
||||
if (listener) {
|
||||
listener->RecvKeysResponse(aRequestId, aRv, aKeys);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
||||
Vendored
+21
-16
@@ -11,10 +11,16 @@
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/dom/cache/PCacheStorageChild.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
|
||||
namespace cache {
|
||||
|
||||
class CacheOpArgs;
|
||||
class CacheStorage;
|
||||
class PCacheChild;
|
||||
class Feature;
|
||||
@@ -27,11 +33,15 @@ public:
|
||||
~CacheStorageChild();
|
||||
|
||||
// Must be called by the associated CacheStorage listener in its
|
||||
// ActorDestroy() method. Also, CacheStorage must Send__delete__() the
|
||||
// ActorDestroy() method. Also, CacheStorage must call SendDestroy() on the
|
||||
// actor in its destructor to trigger ActorDestroy() if it has not been
|
||||
// called yet.
|
||||
void ClearListener();
|
||||
|
||||
void
|
||||
ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
|
||||
const CacheOpArgs& aArgs);
|
||||
|
||||
// ActorChild methods
|
||||
|
||||
// Synchronously call ActorDestroy on our CacheStorage listener and then start
|
||||
@@ -42,26 +52,21 @@ private:
|
||||
// PCacheStorageChild methods
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual bool RecvMatchResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& response) override;
|
||||
virtual bool RecvHasResponse(const cache::RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const bool& aSuccess) override;
|
||||
virtual bool RecvOpenResponse(const cache::RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
PCacheChild* aActor) override;
|
||||
virtual bool RecvDeleteResponse(const cache::RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const bool& aResult) override;
|
||||
virtual bool RecvKeysResponse(const cache::RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
nsTArray<nsString>&& aKeys) override;
|
||||
virtual PCacheOpChild*
|
||||
AllocPCacheOpChild(const CacheOpArgs& aOpArgs) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCacheOpChild(PCacheOpChild* aActor) override;
|
||||
|
||||
// utility methods
|
||||
void
|
||||
NoteDeletedActor();
|
||||
|
||||
// Use a weak ref so actor does not hold DOM object alive past content use.
|
||||
// The CacheStorage object must call ClearListener() to null this before its
|
||||
// destroyed.
|
||||
CacheStorage* MOZ_NON_OWNING_REF mListener;
|
||||
uint32_t mNumChildActors;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
Vendored
+47
-355
@@ -6,28 +6,18 @@
|
||||
|
||||
#include "mozilla/dom/cache/CacheStorageParent.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
#include "mozilla/dom/cache/CacheParent.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/Manager.h"
|
||||
#include "mozilla/dom/cache/CacheOpParent.h"
|
||||
#include "mozilla/dom/cache/ManagerId.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
#include "mozilla/dom/cache/StreamList.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetParent.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::ipc::PBackgroundParent;
|
||||
using mozilla::ipc::PFileDescriptorSetParent;
|
||||
using mozilla::ipc::PrincipalInfo;
|
||||
|
||||
// declared in ActorUtils.h
|
||||
@@ -65,22 +55,60 @@ CacheStorageParent::~CacheStorageParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(cache::CacheStorageParent);
|
||||
MOZ_ASSERT(!mVerifier);
|
||||
MOZ_ASSERT(!mManager);
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
if (mVerifier) {
|
||||
mVerifier->ClearListener();
|
||||
mVerifier->RemoveListener(this);
|
||||
mVerifier = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mManager) {
|
||||
MOZ_ASSERT(!mActiveRequests.IsEmpty());
|
||||
mManager->RemoveListener(this);
|
||||
mManager = nullptr;
|
||||
PCacheOpParent*
|
||||
CacheStorageParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
|
||||
{
|
||||
if (aOpArgs.type() != CacheOpArgs::TStorageMatchArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TStorageHasArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TStorageOpenArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TStorageDeleteArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TStorageKeysArgs)
|
||||
{
|
||||
MOZ_CRASH("Invalid operation sent to CacheStorage actor!");
|
||||
}
|
||||
|
||||
return new CacheOpParent(Manager(), mNamespace, aOpArgs);
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::DeallocPCacheOpParent(PCacheOpParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
|
||||
const CacheOpArgs& aOpArgs)
|
||||
{
|
||||
auto actor = static_cast<CacheOpParent*>(aActor);
|
||||
|
||||
if (mVerifier) {
|
||||
MOZ_ASSERT(!mManagerId);
|
||||
actor->WaitForVerification(mVerifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mVerifiedStatus)) {
|
||||
unused << CacheOpParent::Send__delete__(actor, ErrorResult(mVerifiedStatus),
|
||||
void_t());
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mManagerId);
|
||||
actor->Execute(mManagerId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -93,190 +121,11 @@ CacheStorageParent::RecvTeardown()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::RecvMatch(const RequestId& aRequestId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams)
|
||||
{
|
||||
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
|
||||
if (!SendMatchResponse(aRequestId, mVerifiedStatus, void_t())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Match response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// queue requests if we are still waiting for principal verification
|
||||
if (!mManagerId) {
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mOp = OP_MATCH;
|
||||
entry->mRequestId = aRequestId;
|
||||
entry->mRequest = aRequest;
|
||||
entry->mParams = aParams;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<cache::Manager> manager;
|
||||
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!SendMatchResponse(aRequestId, rv, void_t())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Match response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
manager->StorageMatch(this, aRequestId, mNamespace, aRequest,
|
||||
aParams);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::RecvHas(const RequestId& aRequestId, const nsString& aKey)
|
||||
{
|
||||
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
|
||||
if (!SendHasResponse(aRequestId, mVerifiedStatus, false)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Has response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// queue requests if we are still waiting for principal verification
|
||||
if (!mManagerId) {
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mOp = OP_HAS;
|
||||
entry->mRequestId = aRequestId;
|
||||
entry->mKey = aKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<cache::Manager> manager;
|
||||
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!SendHasResponse(aRequestId, rv, false)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Has response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
manager->StorageHas(this, aRequestId, mNamespace, aKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::RecvOpen(const RequestId& aRequestId, const nsString& aKey)
|
||||
{
|
||||
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
|
||||
if (!SendOpenResponse(aRequestId, mVerifiedStatus, nullptr)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Open response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// queue requests if we are still waiting for principal verification
|
||||
if (!mManagerId) {
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mOp = OP_OPEN;
|
||||
entry->mRequestId = aRequestId;
|
||||
entry->mKey = aKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<cache::Manager> manager;
|
||||
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!SendOpenResponse(aRequestId, rv, nullptr)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Open response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
manager->StorageOpen(this, aRequestId, mNamespace, aKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::RecvDelete(const RequestId& aRequestId,
|
||||
const nsString& aKey)
|
||||
{
|
||||
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
|
||||
if (!SendDeleteResponse(aRequestId, mVerifiedStatus, false)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Delete response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// queue requests if we are still waiting for principal verification
|
||||
if (!mManagerId) {
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mOp = OP_DELETE;
|
||||
entry->mRequestId = aRequestId;
|
||||
entry->mKey = aKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<cache::Manager> manager;
|
||||
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!SendDeleteResponse(aRequestId, rv, false)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Delete response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
manager->StorageDelete(this, aRequestId, mNamespace, aKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheStorageParent::RecvKeys(const RequestId& aRequestId)
|
||||
{
|
||||
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
|
||||
if (!SendKeysResponse(aRequestId, mVerifiedStatus, nsTArray<nsString>())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Keys response.");
|
||||
}
|
||||
}
|
||||
|
||||
// queue requests if we are still waiting for principal verification
|
||||
if (!mManagerId) {
|
||||
Entry* entry = mPendingRequests.AppendElement();
|
||||
entry->mOp = OP_DELETE;
|
||||
entry->mRequestId = aRequestId;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<cache::Manager> manager;
|
||||
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!SendKeysResponse(aRequestId, rv, nsTArray<nsString>())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Keys response.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
manager->StorageKeys(this, aRequestId, mNamespace);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
|
||||
{
|
||||
MOZ_ASSERT(mVerifier);
|
||||
MOZ_ASSERT(!mManagerId);
|
||||
MOZ_ASSERT(!mManager);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(mVerifiedStatus));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aRv))) {
|
||||
@@ -284,165 +133,8 @@ CacheStorageParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
|
||||
}
|
||||
|
||||
mManagerId = aManagerId;
|
||||
mVerifier->ClearListener();
|
||||
mVerifier->RemoveListener(this);
|
||||
mVerifier = nullptr;
|
||||
|
||||
RetryPendingRequests();
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::OnStorageMatch(RequestId aRequestId, nsresult aRv,
|
||||
const SavedResponse* aSavedResponse,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
PCacheResponseOrVoid responseOrVoid;
|
||||
|
||||
ReleaseManager(aRequestId);
|
||||
|
||||
AutoParentResponseOrVoid response(Manager());
|
||||
|
||||
// no match
|
||||
if (NS_FAILED(aRv) || !aSavedResponse) {
|
||||
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Match response.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSavedResponse) {
|
||||
response.Add(*aSavedResponse, aStreamList);
|
||||
}
|
||||
|
||||
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Match response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::OnStorageHas(RequestId aRequestId, nsresult aRv,
|
||||
bool aCacheFound)
|
||||
{
|
||||
ReleaseManager(aRequestId);
|
||||
if (!SendHasResponse(aRequestId, aRv, aCacheFound)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Has response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::OnStorageOpen(RequestId aRequestId, nsresult aRv,
|
||||
CacheId aCacheId)
|
||||
{
|
||||
if (NS_FAILED(aRv)) {
|
||||
ReleaseManager(aRequestId);
|
||||
if (!SendOpenResponse(aRequestId, aRv, nullptr)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Open response.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mManager);
|
||||
CacheParent* actor = new CacheParent(mManager, aCacheId);
|
||||
|
||||
ReleaseManager(aRequestId);
|
||||
|
||||
PCacheParent* base = Manager()->SendPCacheConstructor(actor);
|
||||
actor = static_cast<CacheParent*>(base);
|
||||
if (!SendOpenResponse(aRequestId, aRv, actor)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Open response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::OnStorageDelete(RequestId aRequestId, nsresult aRv,
|
||||
bool aCacheDeleted)
|
||||
{
|
||||
ReleaseManager(aRequestId);
|
||||
if (!SendDeleteResponse(aRequestId, aRv, aCacheDeleted)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Delete response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::OnStorageKeys(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<nsString>& aKeys)
|
||||
{
|
||||
ReleaseManager(aRequestId);
|
||||
if (!SendKeysResponse(aRequestId, aRv, aKeys)) {
|
||||
// child process is gone, warn and allow actor to clean up normally
|
||||
NS_WARNING("CacheStorage failed to send Keys response.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::RetryPendingRequests()
|
||||
{
|
||||
MOZ_ASSERT(mManagerId || NS_FAILED(mVerifiedStatus));
|
||||
for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
|
||||
const Entry& entry = mPendingRequests[i];
|
||||
switch(entry.mOp) {
|
||||
case OP_MATCH:
|
||||
RecvMatch(entry.mRequestId, entry.mRequest, entry.mParams);
|
||||
break;
|
||||
case OP_HAS:
|
||||
RecvHas(entry.mRequestId, entry.mKey);
|
||||
break;
|
||||
case OP_OPEN:
|
||||
RecvOpen(entry.mRequestId, entry.mKey);
|
||||
break;
|
||||
case OP_DELETE:
|
||||
RecvDelete(entry.mRequestId, entry.mKey);
|
||||
break;
|
||||
case OP_KEYS:
|
||||
RecvKeys(entry.mRequestId);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Pending request within unknown op");
|
||||
}
|
||||
}
|
||||
mPendingRequests.Clear();
|
||||
mPendingRequests.Compact();
|
||||
}
|
||||
|
||||
nsresult
|
||||
CacheStorageParent::RequestManager(RequestId aRequestId,
|
||||
cache::Manager** aManagerOut)
|
||||
{
|
||||
MOZ_ASSERT(!mActiveRequests.Contains(aRequestId));
|
||||
nsRefPtr<cache::Manager> ref = mManager;
|
||||
if (!ref) {
|
||||
MOZ_ASSERT(mActiveRequests.IsEmpty());
|
||||
nsresult rv = cache::Manager::GetOrCreate(mManagerId, getter_AddRefs(ref));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
mManager = ref;
|
||||
}
|
||||
mActiveRequests.AppendElement(aRequestId);
|
||||
ref.forget(aManagerOut);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorageParent::ReleaseManager(RequestId aRequestId)
|
||||
{
|
||||
// Note that if the child process dies we also clean up the mManager in
|
||||
// ActorDestroy(). There is no race with this method, however, because
|
||||
// ActorDestroy removes this object from the Manager's listener list.
|
||||
// Therefore ReleaseManager() should never be called after ActorDestroy()
|
||||
// runs.
|
||||
MOZ_ASSERT(mManager);
|
||||
MOZ_ASSERT(!mActiveRequests.IsEmpty());
|
||||
|
||||
MOZ_ALWAYS_TRUE(mActiveRequests.RemoveElement(aRequestId));
|
||||
|
||||
if (mActiveRequests.IsEmpty()) {
|
||||
mManager->RemoveListener(this);
|
||||
mManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
||||
Vendored
+15
-63
@@ -7,24 +7,18 @@
|
||||
#ifndef mozilla_dom_cache_CacheStorageParent_h
|
||||
#define mozilla_dom_cache_CacheStorageParent_h
|
||||
|
||||
#include "mozilla/dom/cache/CacheInitData.h"
|
||||
#include "mozilla/dom/cache/PCacheStorageParent.h"
|
||||
#include "mozilla/dom/cache/Manager.h"
|
||||
#include "mozilla/dom/cache/PrincipalVerifier.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
|
||||
template <class T> class nsRefPtr;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CacheStreamControlParent;
|
||||
class ManagerId;
|
||||
|
||||
class CacheStorageParent final : public PCacheStorageParent
|
||||
, public PrincipalVerifier::Listener
|
||||
, public Manager::Listener
|
||||
{
|
||||
public:
|
||||
CacheStorageParent(PBackgroundParent* aManagingActor, Namespace aNamespace,
|
||||
@@ -33,72 +27,30 @@ public:
|
||||
|
||||
private:
|
||||
// PCacheStorageParent methods
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
virtual bool RecvTeardown() override;
|
||||
virtual bool RecvMatch(const RequestId& aRequestId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams) override;
|
||||
virtual bool RecvHas(const RequestId& aRequestId,
|
||||
const nsString& aKey) override;
|
||||
virtual bool RecvOpen(const RequestId& aRequestId,
|
||||
const nsString& aKey) override;
|
||||
virtual bool RecvDelete(const RequestId& aRequestId,
|
||||
const nsString& aKey) override;
|
||||
virtual bool RecvKeys(const RequestId& aRequestId) override;
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual PCacheOpParent*
|
||||
AllocPCacheOpParent(const CacheOpArgs& aOpArgs) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCacheOpParent(PCacheOpParent* aActor) override;
|
||||
|
||||
virtual bool
|
||||
RecvPCacheOpConstructor(PCacheOpParent* actor,
|
||||
const CacheOpArgs& aOpArgs) override;
|
||||
|
||||
virtual bool
|
||||
RecvTeardown() override;
|
||||
|
||||
// PrincipalVerifier::Listener methods
|
||||
virtual void OnPrincipalVerified(nsresult aRv,
|
||||
ManagerId* aManagerId) override;
|
||||
|
||||
// Manager::Listener methods
|
||||
virtual void OnStorageMatch(RequestId aRequestId, nsresult aRv,
|
||||
const SavedResponse* aResponse,
|
||||
StreamList* aStreamList) override;
|
||||
virtual void OnStorageHas(RequestId aRequestId, nsresult aRv,
|
||||
bool aCacheFound) override;
|
||||
virtual void OnStorageOpen(RequestId aRequestId, nsresult aRv,
|
||||
CacheId aCacheId) override;
|
||||
virtual void OnStorageDelete(RequestId aRequestId, nsresult aRv,
|
||||
bool aCacheDeleted) override;
|
||||
virtual void OnStorageKeys(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<nsString>& aKeys) override;
|
||||
|
||||
CacheStreamControlParent*
|
||||
SerializeReadStream(CacheStreamControlParent *aStreamControl, const nsID& aId,
|
||||
StreamList* aStreamList,
|
||||
PCacheReadStream* aReadStreamOut);
|
||||
|
||||
void RetryPendingRequests();
|
||||
|
||||
nsresult RequestManager(RequestId aRequestId, cache::Manager** aManagerOut);
|
||||
void ReleaseManager(RequestId aRequestId);
|
||||
|
||||
const Namespace mNamespace;
|
||||
nsRefPtr<PrincipalVerifier> mVerifier;
|
||||
nsresult mVerifiedStatus;
|
||||
nsRefPtr<ManagerId> mManagerId;
|
||||
nsRefPtr<cache::Manager> mManager;
|
||||
|
||||
enum Op
|
||||
{
|
||||
OP_MATCH,
|
||||
OP_HAS,
|
||||
OP_OPEN,
|
||||
OP_DELETE,
|
||||
OP_KEYS
|
||||
};
|
||||
|
||||
struct Entry
|
||||
{
|
||||
Op mOp;
|
||||
RequestId mRequestId;
|
||||
nsString mKey;
|
||||
PCacheRequest mRequest;
|
||||
PCacheQueryParams mParams;
|
||||
};
|
||||
|
||||
nsTArray<Entry> mPendingRequests;
|
||||
nsTArray<RequestId> mActiveRequests;
|
||||
};
|
||||
|
||||
} // namesapce cache
|
||||
|
||||
+29
-4
@@ -9,7 +9,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
@@ -41,6 +41,7 @@ DeallocPCacheStreamControlChild(PCacheStreamControlChild* aActor)
|
||||
|
||||
CacheStreamControlChild::CacheStreamControlChild()
|
||||
: mDestroyStarted(false)
|
||||
, mDestroyDelayed(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(cache::CacheStreamControlChild);
|
||||
}
|
||||
@@ -63,13 +64,28 @@ CacheStreamControlChild::StartDestroy()
|
||||
}
|
||||
mDestroyStarted = true;
|
||||
|
||||
// If any of the streams have started to be read, then wait for them to close
|
||||
// naturally.
|
||||
if (HasEverBeenRead()) {
|
||||
// Note that we are delaying so that we can re-check for active streams
|
||||
// in NoteClosedAfterForget().
|
||||
mDestroyDelayed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, if the streams have not been touched then just pre-emptively
|
||||
// close them now. This handles the case where someone retrieves a Response
|
||||
// from the Cache, but never accesses the body. We should not keep the
|
||||
// Worker alive until that Response is GC'd just because of its ignored
|
||||
// body stream.
|
||||
|
||||
// Begin shutting down all streams. This is the same as if the parent had
|
||||
// asked us to shutdown. So simulate the CloseAll IPC message.
|
||||
RecvCloseAll();
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::SerializeControl(PCacheReadStream* aReadStreamOut)
|
||||
CacheStreamControlChild::SerializeControl(CacheReadStream* aReadStreamOut)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
aReadStreamOut->controlParent() = nullptr;
|
||||
@@ -77,7 +93,7 @@ CacheStreamControlChild::SerializeControl(PCacheReadStream* aReadStreamOut)
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
CacheStreamControlChild::SerializeFds(CacheReadStream* aReadStreamOut,
|
||||
const nsTArray<FileDescriptor>& aFds)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
@@ -97,7 +113,7 @@ CacheStreamControlChild::SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlChild::DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
CacheStreamControlChild::DeserializeFds(const CacheReadStream& aReadStream,
|
||||
nsTArray<FileDescriptor>& aFdsOut)
|
||||
{
|
||||
if (aReadStream.fds().type() !=
|
||||
@@ -120,6 +136,15 @@ CacheStreamControlChild::NoteClosedAfterForget(const nsID& aId)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
|
||||
unused << SendNoteClosed(aId);
|
||||
|
||||
// A stream has closed. If we delayed StartDestry() due to this stream
|
||||
// being read, then we should check to see if any of the remaining streams
|
||||
// are active. If none of our other streams have been read, then we can
|
||||
// proceed with the shutdown now.
|
||||
if (mDestroyDelayed && !HasEverBeenRead()) {
|
||||
mDestroyDelayed = false;
|
||||
RecvCloseAll();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
Vendored
+4
-3
@@ -31,14 +31,14 @@ public:
|
||||
|
||||
// StreamControl methods
|
||||
virtual void
|
||||
SerializeControl(PCacheReadStream* aReadStreamOut) override;
|
||||
SerializeControl(CacheReadStream* aReadStreamOut) override;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
SerializeFds(CacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) override;
|
||||
|
||||
virtual void
|
||||
DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
DeserializeFds(const CacheReadStream& aReadStream,
|
||||
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) override;
|
||||
|
||||
private:
|
||||
@@ -56,6 +56,7 @@ private:
|
||||
virtual bool RecvCloseAll() override;
|
||||
|
||||
bool mDestroyStarted;
|
||||
bool mDestroyDelayed;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
+4
-4
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/StreamList.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
@@ -45,7 +45,7 @@ CacheStreamControlParent::~CacheStreamControlParent()
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::SerializeControl(PCacheReadStream* aReadStreamOut)
|
||||
CacheStreamControlParent::SerializeControl(CacheReadStream* aReadStreamOut)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
aReadStreamOut->controlChild() = nullptr;
|
||||
@@ -53,7 +53,7 @@ CacheStreamControlParent::SerializeControl(PCacheReadStream* aReadStreamOut)
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
CacheStreamControlParent::SerializeFds(CacheReadStream* aReadStreamOut,
|
||||
const nsTArray<FileDescriptor>& aFds)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
|
||||
@@ -73,7 +73,7 @@ CacheStreamControlParent::SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
}
|
||||
|
||||
void
|
||||
CacheStreamControlParent::DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
CacheStreamControlParent::DeserializeFds(const CacheReadStream& aReadStream,
|
||||
nsTArray<FileDescriptor>& aFdsOut)
|
||||
{
|
||||
if (aReadStream.fds().type() !=
|
||||
|
||||
Vendored
+3
-3
@@ -32,14 +32,14 @@ public:
|
||||
|
||||
// StreamControl methods
|
||||
virtual void
|
||||
SerializeControl(PCacheReadStream* aReadStreamOut) override;
|
||||
SerializeControl(CacheReadStream* aReadStreamOut) override;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
SerializeFds(CacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) override;
|
||||
|
||||
virtual void
|
||||
DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
DeserializeFds(const CacheReadStream& aReadStream,
|
||||
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) override;
|
||||
|
||||
private:
|
||||
|
||||
Vendored
+245
@@ -0,0 +1,245 @@
|
||||
/* 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 protocol PCache;
|
||||
include protocol PCachePushStream;
|
||||
include protocol PCacheStreamControl;
|
||||
include InputStreamParams;
|
||||
|
||||
using HeadersGuardEnum from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestCredentials from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestMode from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestCache from "mozilla/dom/cache/IPCUtils.h";
|
||||
using RequestContext from "mozilla/dom/cache/IPCUtils.h";
|
||||
using ResponseType from "mozilla/dom/cache/IPCUtils.h";
|
||||
using mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
using struct nsID from "nsID.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
struct CacheQueryParams
|
||||
{
|
||||
bool ignoreSearch;
|
||||
bool ignoreMethod;
|
||||
bool ignoreVary;
|
||||
bool prefixMatch;
|
||||
bool cacheNameSet;
|
||||
nsString cacheName;
|
||||
};
|
||||
|
||||
struct CacheReadStream
|
||||
{
|
||||
nsID id;
|
||||
OptionalInputStreamParams params;
|
||||
OptionalFileDescriptorSet fds;
|
||||
nullable PCacheStreamControl control;
|
||||
nullable PCachePushStream pushStream;
|
||||
};
|
||||
|
||||
union CacheReadStreamOrVoid
|
||||
{
|
||||
void_t;
|
||||
CacheReadStream;
|
||||
};
|
||||
|
||||
struct HeadersEntry
|
||||
{
|
||||
nsCString name;
|
||||
nsCString value;
|
||||
};
|
||||
|
||||
struct CacheRequest
|
||||
{
|
||||
nsCString method;
|
||||
nsString url;
|
||||
nsString urlWithoutQuery;
|
||||
HeadersEntry[] headers;
|
||||
HeadersGuardEnum headersGuard;
|
||||
nsString referrer;
|
||||
RequestMode mode;
|
||||
RequestCredentials credentials;
|
||||
CacheReadStreamOrVoid body;
|
||||
uint32_t contentPolicyType;
|
||||
RequestContext context;
|
||||
RequestCache requestCache;
|
||||
};
|
||||
|
||||
union CacheRequestOrVoid
|
||||
{
|
||||
void_t;
|
||||
CacheRequest;
|
||||
};
|
||||
|
||||
struct CacheResponse
|
||||
{
|
||||
ResponseType type;
|
||||
nsString url;
|
||||
uint32_t status;
|
||||
nsCString statusText;
|
||||
HeadersEntry[] headers;
|
||||
HeadersGuardEnum headersGuard;
|
||||
CacheReadStreamOrVoid body;
|
||||
nsCString securityInfo;
|
||||
};
|
||||
|
||||
union CacheResponseOrVoid
|
||||
{
|
||||
void_t;
|
||||
CacheResponse;
|
||||
};
|
||||
|
||||
struct CacheRequestResponse
|
||||
{
|
||||
CacheRequest request;
|
||||
CacheResponse response;
|
||||
};
|
||||
|
||||
struct CacheMatchArgs
|
||||
{
|
||||
CacheRequest request;
|
||||
CacheQueryParams params;
|
||||
};
|
||||
|
||||
struct CacheMatchAllArgs
|
||||
{
|
||||
CacheRequestOrVoid requestOrVoid;
|
||||
CacheQueryParams params;
|
||||
};
|
||||
|
||||
struct CacheAddAllArgs
|
||||
{
|
||||
CacheRequest[] requestList;
|
||||
};
|
||||
|
||||
struct CachePutAllArgs
|
||||
{
|
||||
CacheRequestResponse[] requestResponseList;
|
||||
};
|
||||
|
||||
struct CacheDeleteArgs
|
||||
{
|
||||
CacheRequest request;
|
||||
CacheQueryParams params;
|
||||
};
|
||||
|
||||
struct CacheKeysArgs
|
||||
{
|
||||
CacheRequestOrVoid requestOrVoid;
|
||||
CacheQueryParams params;
|
||||
};
|
||||
|
||||
struct StorageMatchArgs
|
||||
{
|
||||
CacheRequest request;
|
||||
CacheQueryParams params;
|
||||
};
|
||||
|
||||
struct StorageHasArgs
|
||||
{
|
||||
nsString key;
|
||||
};
|
||||
|
||||
struct StorageOpenArgs
|
||||
{
|
||||
nsString key;
|
||||
};
|
||||
|
||||
struct StorageDeleteArgs
|
||||
{
|
||||
nsString key;
|
||||
};
|
||||
|
||||
struct StorageKeysArgs
|
||||
{
|
||||
};
|
||||
|
||||
union CacheOpArgs
|
||||
{
|
||||
CacheMatchArgs;
|
||||
CacheMatchAllArgs;
|
||||
CacheAddAllArgs;
|
||||
CachePutAllArgs;
|
||||
CacheDeleteArgs;
|
||||
CacheKeysArgs;
|
||||
StorageMatchArgs;
|
||||
StorageHasArgs;
|
||||
StorageOpenArgs;
|
||||
StorageDeleteArgs;
|
||||
StorageKeysArgs;
|
||||
};
|
||||
|
||||
struct CacheMatchResult
|
||||
{
|
||||
CacheResponseOrVoid responseOrVoid;
|
||||
};
|
||||
|
||||
struct CacheMatchAllResult
|
||||
{
|
||||
CacheResponse[] responseList;
|
||||
};
|
||||
|
||||
struct CacheAddAllResult
|
||||
{
|
||||
};
|
||||
|
||||
struct CachePutAllResult
|
||||
{
|
||||
};
|
||||
|
||||
struct CacheDeleteResult
|
||||
{
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct CacheKeysResult
|
||||
{
|
||||
CacheRequest[] requestList;
|
||||
};
|
||||
|
||||
struct StorageMatchResult
|
||||
{
|
||||
CacheResponseOrVoid responseOrVoid;
|
||||
};
|
||||
|
||||
struct StorageHasResult
|
||||
{
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct StorageOpenResult
|
||||
{
|
||||
nullable PCache actor;
|
||||
};
|
||||
|
||||
struct StorageDeleteResult
|
||||
{
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct StorageKeysResult
|
||||
{
|
||||
nsString[] keyList;
|
||||
};
|
||||
|
||||
union CacheOpResult
|
||||
{
|
||||
void_t;
|
||||
CacheMatchResult;
|
||||
CacheMatchAllResult;
|
||||
CacheAddAllResult;
|
||||
CachePutAllResult;
|
||||
CacheDeleteResult;
|
||||
CacheKeysResult;
|
||||
StorageMatchResult;
|
||||
StorageHasResult;
|
||||
StorageOpenResult;
|
||||
StorageDeleteResult;
|
||||
StorageKeysResult;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Vendored
+9
-1
@@ -732,6 +732,7 @@ Context::Dispatch(nsIEventTarget* aTarget, Action* aAction)
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(aAction);
|
||||
|
||||
MOZ_ASSERT(mState != STATE_CONTEXT_CANCELED);
|
||||
if (mState == STATE_CONTEXT_CANCELED) {
|
||||
return;
|
||||
} else if (mState == STATE_CONTEXT_INIT) {
|
||||
@@ -766,11 +767,18 @@ Context::CancelAll()
|
||||
AllowToClose();
|
||||
}
|
||||
|
||||
bool
|
||||
Context::IsCanceled() const
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Context);
|
||||
return mState == STATE_CONTEXT_CANCELED;
|
||||
}
|
||||
|
||||
void
|
||||
Context::Invalidate()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Context);
|
||||
mManager->Invalidate();
|
||||
mManager->NoteClosing();
|
||||
CancelAll();
|
||||
}
|
||||
|
||||
|
||||
Vendored
+3
@@ -126,6 +126,9 @@ public:
|
||||
// Only callable from the thread that created the Context.
|
||||
void CancelAll();
|
||||
|
||||
// True if CancelAll() has been called.
|
||||
bool IsCanceled() const;
|
||||
|
||||
// Like CancelAll(), but also marks the Manager as "invalid".
|
||||
void Invalidate();
|
||||
|
||||
|
||||
Vendored
+4
-3
@@ -14,6 +14,7 @@
|
||||
#include "nsIFile.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "DBSchema.h"
|
||||
#include "FileUtils.h"
|
||||
|
||||
@@ -146,7 +147,7 @@ DBAction::OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
|
||||
int32_t schemaVersion = 0;
|
||||
rv = conn->GetSchemaVersion(&schemaVersion);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
if (schemaVersion > 0 && schemaVersion < DBSchema::kMaxWipeSchemaVersion) {
|
||||
if (schemaVersion > 0 && schemaVersion < db::kMaxWipeSchemaVersion) {
|
||||
conn = nullptr;
|
||||
rv = WipeDatabase(dbFile, aDBDir);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
@@ -154,7 +155,7 @@ DBAction::OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
|
||||
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
|
||||
}
|
||||
|
||||
rv = DBSchema::InitializeConnection(conn);
|
||||
rv = db::InitializeConnection(conn);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
conn.forget(aConnOut);
|
||||
@@ -169,7 +170,7 @@ DBAction::WipeDatabase(nsIFile* aDBFile, nsIFile* aDBDir)
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
// Delete the morgue as well.
|
||||
rv = FileUtils::BodyDeleteDir(aDBDir);
|
||||
rv = BodyDeleteDir(aDBDir);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
return rv;
|
||||
|
||||
Vendored
-1
@@ -8,7 +8,6 @@
|
||||
#define mozilla_dom_cache_DBAction_h
|
||||
|
||||
#include "mozilla/dom/cache/Action.h"
|
||||
#include "mozilla/dom/cache/CacheInitData.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
|
||||
Vendored
+143
-117
@@ -8,8 +8,10 @@
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "mozIStorageConnection.h"
|
||||
#include "mozIStorageStatement.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@@ -19,16 +21,21 @@
|
||||
#include "mozilla/dom/HeadersBinding.h"
|
||||
#include "mozilla/dom/RequestBinding.h"
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
#include "Types.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
namespace db {
|
||||
|
||||
const int32_t DBSchema::kMaxWipeSchemaVersion = 6;
|
||||
const int32_t DBSchema::kLatestSchemaVersion = 6;
|
||||
const int32_t DBSchema::kMaxEntriesPerStatement = 255;
|
||||
const int32_t kMaxWipeSchemaVersion = 6;
|
||||
|
||||
namespace {
|
||||
|
||||
const int32_t kLatestSchemaVersion = 6;
|
||||
const int32_t kMaxEntriesPerStatement = 255;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// If any of the static_asserts below fail, it means that you have changed
|
||||
// the corresponding WebIDL enum in a way that may be incompatible with the
|
||||
@@ -140,11 +147,48 @@ static_assert(nsIContentPolicy::TYPE_INVALID == 0 &&
|
||||
nsIContentPolicy::TYPE_IMAGESET == 21,
|
||||
"nsContentPolicytType values are as expected");
|
||||
|
||||
using mozilla::void_t;
|
||||
namespace {
|
||||
|
||||
typedef int32_t EntryId;
|
||||
|
||||
static nsresult QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<EntryId>& aEntryIdListOut);
|
||||
static nsresult QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<EntryId>& aEntryIdListOut,
|
||||
uint32_t aMaxResults = UINT32_MAX);
|
||||
static nsresult MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
const CacheRequest& aRequest,
|
||||
EntryId entryId, bool* aSuccessOut);
|
||||
static nsresult DeleteEntries(mozIStorageConnection* aConn,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut,
|
||||
uint32_t aPos=0, int32_t aLen=-1);
|
||||
static nsresult InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const CacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId);
|
||||
static nsresult ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedResponse* aSavedResponseOut);
|
||||
static nsresult ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedRequest* aSavedRequestOut);
|
||||
|
||||
static void AppendListParamsToQuery(nsACString& aQuery,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen);
|
||||
static nsresult BindListParamsToQuery(mozIStorageStatement* aState,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen);
|
||||
static nsresult BindId(mozIStorageStatement* aState, uint32_t aPos,
|
||||
const nsID* aId);
|
||||
static nsresult ExtractId(mozIStorageStatement* aState, uint32_t aPos,
|
||||
nsID* aIdOut);
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CreateSchema(mozIStorageConnection* aConn)
|
||||
CreateSchema(mozIStorageConnection* aConn)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -284,9 +328,8 @@ DBSchema::CreateSchema(mozIStorageConnection* aConn)
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::InitializeConnection(mozIStorageConnection* aConn)
|
||||
InitializeConnection(mozIStorageConnection* aConn)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -315,9 +358,8 @@ DBSchema::InitializeConnection(mozIStorageConnection* aConn)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CreateCache(mozIStorageConnection* aConn, CacheId* aCacheIdOut)
|
||||
CreateCacheId(mozIStorageConnection* aConn, CacheId* aCacheIdOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -345,10 +387,9 @@ DBSchema::CreateCache(mozIStorageConnection* aConn, CacheId* aCacheIdOut)
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::DeleteCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut)
|
||||
DeleteCacheId(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -379,10 +420,9 @@ DBSchema::DeleteCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::IsCacheOrphaned(mozIStorageConnection* aConn,
|
||||
CacheId aCacheId, bool* aOrphanedOut)
|
||||
IsCacheOrphaned(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
bool* aOrphanedOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -414,13 +454,12 @@ DBSchema::IsCacheOrphaned(mozIStorageConnection* aConn,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut)
|
||||
CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -446,19 +485,18 @@ DBSchema::CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequestOrVoid& aRequestOrVoid,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<SavedResponse>& aSavedResponsesOut)
|
||||
CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequestOrVoid& aRequestOrVoid,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<SavedResponse>& aSavedResponsesOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
nsresult rv;
|
||||
|
||||
nsAutoTArray<EntryId, 256> matches;
|
||||
if (aRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t) {
|
||||
if (aRequestOrVoid.type() == CacheRequestOrVoid::Tvoid_t) {
|
||||
rv = QueryAll(aConn, aCacheId, matches);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
} else {
|
||||
@@ -478,19 +516,18 @@ DBSchema::CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const PCacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut)
|
||||
CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const CacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
|
||||
PCacheQueryParams params(false, false, false, false, false,
|
||||
CacheQueryParams params(false, false, false, false, false,
|
||||
NS_LITERAL_STRING(""));
|
||||
nsAutoTArray<EntryId, 256> matches;
|
||||
nsresult rv = QueryCache(aConn, aCacheId, aRequest, params, matches);
|
||||
@@ -506,12 +543,11 @@ DBSchema::CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut, bool* aSuccessOut)
|
||||
CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut, bool* aSuccessOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -535,19 +571,18 @@ DBSchema::CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequestOrVoid& aRequestOrVoid,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<SavedRequest>& aSavedRequestsOut)
|
||||
CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequestOrVoid& aRequestOrVoid,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<SavedRequest>& aSavedRequestsOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
nsresult rv;
|
||||
|
||||
nsAutoTArray<EntryId, 256> matches;
|
||||
if (aRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t) {
|
||||
if (aRequestOrVoid.type() == CacheRequestOrVoid::Tvoid_t) {
|
||||
rv = QueryAll(aConn, aCacheId, matches);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
} else {
|
||||
@@ -567,14 +602,13 @@ DBSchema::CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::StorageMatch(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut)
|
||||
StorageMatch(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -639,11 +673,10 @@ DBSchema::StorageMatch(mozIStorageConnection* aConn,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey, bool* aFoundCacheOut,
|
||||
CacheId* aCacheIdOut)
|
||||
StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey, bool* aFoundCacheOut,
|
||||
CacheId* aCacheIdOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -679,10 +712,9 @@ DBSchema::StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey, CacheId aCacheId)
|
||||
StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey, CacheId aCacheId)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -708,10 +740,9 @@ DBSchema::StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey)
|
||||
StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -734,10 +765,9 @@ DBSchema::StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
nsTArray<nsString>& aKeysOut)
|
||||
StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
nsTArray<nsString>& aKeysOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -762,10 +792,11 @@ DBSchema::StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
DBSchema::QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<EntryId>& aEntryIdListOut)
|
||||
QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<EntryId>& aEntryIdListOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -790,13 +821,12 @@ DBSchema::QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<EntryId>& aEntryIdListOut,
|
||||
uint32_t aMaxResults)
|
||||
QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<EntryId>& aEntryIdListOut,
|
||||
uint32_t aMaxResults)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -882,11 +912,10 @@ DBSchema::QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
const PCacheRequest& aRequest,
|
||||
EntryId entryId, bool* aSuccessOut)
|
||||
MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
const CacheRequest& aRequest,
|
||||
EntryId entryId, bool* aSuccessOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -927,7 +956,8 @@ DBSchema::MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
rv = state->BindInt32Parameter(0, entryId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
nsRefPtr<InternalHeaders> cachedHeaders = new InternalHeaders(HeadersGuardEnum::None);
|
||||
nsRefPtr<InternalHeaders> cachedHeaders =
|
||||
new InternalHeaders(HeadersGuardEnum::None);
|
||||
|
||||
while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
|
||||
nsAutoCString name;
|
||||
@@ -944,7 +974,8 @@ DBSchema::MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
nsRefPtr<InternalHeaders> queryHeaders = new InternalHeaders(aRequest.headers());
|
||||
nsRefPtr<InternalHeaders> queryHeaders =
|
||||
TypeUtils::ToInternalHeaders(aRequest.headers());
|
||||
|
||||
// Assume the vary headers match until we find a conflict
|
||||
bool varyHeadersMatch = true;
|
||||
@@ -993,12 +1024,11 @@ DBSchema::MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::DeleteEntries(mozIStorageConnection* aConn,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut,
|
||||
uint32_t aPos, int32_t aLen)
|
||||
DeleteEntries(mozIStorageConnection* aConn,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut,
|
||||
uint32_t aPos, int32_t aLen)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -1082,13 +1112,12 @@ DBSchema::DeleteEntries(mozIStorageConnection* aConn,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const PCacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId)
|
||||
InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const CacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -1209,7 +1238,7 @@ DBSchema::InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
), getter_AddRefs(state));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
const nsTArray<PHeadersEntry>& requestHeaders = aRequest.headers();
|
||||
const nsTArray<HeadersEntry>& requestHeaders = aRequest.headers();
|
||||
for (uint32_t i = 0; i < requestHeaders.Length(); ++i) {
|
||||
rv = state->BindUTF8StringParameter(0, requestHeaders[i].name());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
@@ -1233,7 +1262,7 @@ DBSchema::InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
), getter_AddRefs(state));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
const nsTArray<PHeadersEntry>& responseHeaders = aResponse.headers();
|
||||
const nsTArray<HeadersEntry>& responseHeaders = aResponse.headers();
|
||||
for (uint32_t i = 0; i < responseHeaders.Length(); ++i) {
|
||||
rv = state->BindUTF8StringParameter(0, responseHeaders[i].name());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
@@ -1251,10 +1280,9 @@ DBSchema::InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedResponse* aSavedResponseOut)
|
||||
ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedResponse* aSavedResponseOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -1334,7 +1362,7 @@ DBSchema::ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
|
||||
PHeadersEntry header;
|
||||
HeadersEntry header;
|
||||
|
||||
rv = state->GetUTF8String(0, header.name());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
@@ -1348,10 +1376,9 @@ DBSchema::ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedRequest* aSavedRequestOut)
|
||||
ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedRequest* aSavedRequestOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aConn);
|
||||
@@ -1453,7 +1480,7 @@ DBSchema::ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
|
||||
PHeadersEntry header;
|
||||
HeadersEntry header;
|
||||
|
||||
rv = state->GetUTF8String(0, header.name());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
@@ -1467,11 +1494,10 @@ DBSchema::ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
DBSchema::AppendListParamsToQuery(nsACString& aQuery,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen)
|
||||
AppendListParamsToQuery(nsACString& aQuery,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT((aPos + aLen) <= aEntryIdList.Length());
|
||||
@@ -1484,11 +1510,10 @@ DBSchema::AppendListParamsToQuery(nsACString& aQuery,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::BindListParamsToQuery(mozIStorageStatement* aState,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen)
|
||||
BindListParamsToQuery(mozIStorageStatement* aState,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT((aPos + aLen) <= aEntryIdList.Length());
|
||||
@@ -1499,9 +1524,8 @@ DBSchema::BindListParamsToQuery(mozIStorageStatement* aState,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::BindId(mozIStorageStatement* aState, uint32_t aPos, const nsID* aId)
|
||||
BindId(mozIStorageStatement* aState, uint32_t aPos, const nsID* aId)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aState);
|
||||
@@ -1521,9 +1545,8 @@ DBSchema::BindId(mozIStorageStatement* aState, uint32_t aPos, const nsID* aId)
|
||||
return rv;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
DBSchema::ExtractId(mozIStorageStatement* aState, uint32_t aPos, nsID* aIdOut)
|
||||
ExtractId(mozIStorageStatement* aState, uint32_t aPos, nsID* aIdOut)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aState);
|
||||
@@ -1539,6 +1562,9 @@ DBSchema::ExtractId(mozIStorageStatement* aState, uint32_t aPos, nsID* aIdOut)
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // anonymouns namespace
|
||||
|
||||
} // namespace db
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+74
-103
@@ -14,129 +14,100 @@
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
|
||||
class mozIStorageConnection;
|
||||
class mozIStorageStatement;
|
||||
struct nsID;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class PCacheQueryParams;
|
||||
class PCacheRequest;
|
||||
class PCacheRequestOrVoid;
|
||||
class PCacheResponse;
|
||||
class CacheQueryParams;
|
||||
class CacheRequest;
|
||||
class CacheRequestOrVoid;
|
||||
class CacheResponse;
|
||||
struct SavedRequest;
|
||||
struct SavedResponse;
|
||||
|
||||
// TODO: remove static class and use functions in cache namespace (bug 1110485)
|
||||
class DBSchema final
|
||||
{
|
||||
public:
|
||||
static nsresult CreateSchema(mozIStorageConnection* aConn);
|
||||
static nsresult InitializeConnection(mozIStorageConnection* aConn);
|
||||
namespace db {
|
||||
|
||||
static nsresult CreateCache(mozIStorageConnection* aConn,
|
||||
CacheId* aCacheIdOut);
|
||||
// TODO: improve naming (confusing with CacheDelete) (bug 1110485)
|
||||
static nsresult DeleteCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut);
|
||||
nsresult
|
||||
CreateSchema(mozIStorageConnection* aConn);
|
||||
|
||||
// TODO: Consider removing unused IsCacheOrphaned after writing cleanup code. (bug 1110446)
|
||||
static nsresult IsCacheOrphaned(mozIStorageConnection* aConn,
|
||||
CacheId aCacheId, bool* aOrphanedOut);
|
||||
nsresult
|
||||
InitializeConnection(mozIStorageConnection* aConn);
|
||||
|
||||
static nsresult CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut);
|
||||
static nsresult CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequestOrVoid& aRequestOrVoid,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<SavedResponse>& aSavedResponsesOut);
|
||||
static nsresult CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const PCacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut);
|
||||
static nsresult CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut,
|
||||
bool* aSuccessOut);
|
||||
static nsresult CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequestOrVoid& aRequestOrVoid,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<SavedRequest>& aSavedRequestsOut);
|
||||
nsresult
|
||||
CreateCacheId(mozIStorageConnection* aConn, CacheId* aCacheIdOut);
|
||||
|
||||
static nsresult StorageMatch(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut);
|
||||
static nsresult StorageGetCacheId(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace, const nsAString& aKey,
|
||||
bool* aFoundCacheOut, CacheId* aCacheIdOut);
|
||||
static nsresult StoragePutCache(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace, const nsAString& aKey,
|
||||
CacheId aCacheId);
|
||||
static nsresult StorageForgetCache(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace,
|
||||
const nsAString& aKey);
|
||||
static nsresult StorageGetKeys(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace,
|
||||
nsTArray<nsString>& aKeysOut);
|
||||
nsresult
|
||||
DeleteCacheId(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut);
|
||||
|
||||
// We will wipe out databases with a schema versions less than this.
|
||||
static const int32_t kMaxWipeSchemaVersion;
|
||||
// TODO: Consider removing unused IsCacheOrphaned after writing cleanup code. (bug 1110446)
|
||||
nsresult
|
||||
IsCacheOrphaned(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
bool* aOrphanedOut);
|
||||
|
||||
private:
|
||||
typedef int32_t EntryId;
|
||||
nsresult
|
||||
CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest, const CacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut, SavedResponse* aSavedResponseOut);
|
||||
|
||||
static nsresult QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
nsTArray<EntryId>& aEntryIdListOut);
|
||||
static nsresult QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams,
|
||||
nsTArray<EntryId>& aEntryIdListOut,
|
||||
uint32_t aMaxResults = UINT32_MAX);
|
||||
static nsresult MatchByVaryHeader(mozIStorageConnection* aConn,
|
||||
const PCacheRequest& aRequest,
|
||||
EntryId entryId, bool* aSuccessOut);
|
||||
static nsresult DeleteEntries(mozIStorageConnection* aConn,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut,
|
||||
uint32_t aPos=0, int32_t aLen=-1);
|
||||
static nsresult InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const PCacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId);
|
||||
static nsresult ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedResponse* aSavedResponseOut);
|
||||
static nsresult ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||
SavedRequest* aSavedRequestOut);
|
||||
nsresult
|
||||
CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequestOrVoid& aRequestOrVoid,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<SavedResponse>& aSavedResponsesOut);
|
||||
|
||||
static void AppendListParamsToQuery(nsACString& aQuery,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen);
|
||||
static nsresult BindListParamsToQuery(mozIStorageStatement* aState,
|
||||
const nsTArray<EntryId>& aEntryIdList,
|
||||
uint32_t aPos, int32_t aLen);
|
||||
static nsresult BindId(mozIStorageStatement* aState, uint32_t aPos,
|
||||
const nsID* aId);
|
||||
static nsresult ExtractId(mozIStorageStatement* aState, uint32_t aPos,
|
||||
nsID* aIdOut);
|
||||
nsresult
|
||||
CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const nsID* aRequestBodyId,
|
||||
const CacheResponse& aResponse,
|
||||
const nsID* aResponseBodyId,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut);
|
||||
|
||||
DBSchema() = delete;
|
||||
~DBSchema() = delete;
|
||||
nsresult
|
||||
CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<nsID>& aDeletedBodyIdListOut,
|
||||
bool* aSuccessOut);
|
||||
|
||||
static const int32_t kLatestSchemaVersion;
|
||||
static const int32_t kMaxEntriesPerStatement;
|
||||
};
|
||||
nsresult
|
||||
CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
|
||||
const CacheRequestOrVoid& aRequestOrVoid,
|
||||
const CacheQueryParams& aParams,
|
||||
nsTArray<SavedRequest>& aSavedRequestsOut);
|
||||
|
||||
nsresult
|
||||
StorageMatch(mozIStorageConnection* aConn,
|
||||
Namespace aNamespace,
|
||||
const CacheRequest& aRequest,
|
||||
const CacheQueryParams& aParams,
|
||||
bool* aFoundResponseOut,
|
||||
SavedResponse* aSavedResponseOut);
|
||||
|
||||
nsresult
|
||||
StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey, bool* aFoundCacheOut,
|
||||
CacheId* aCacheIdOut);
|
||||
|
||||
nsresult
|
||||
StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey, CacheId aCacheId);
|
||||
|
||||
nsresult
|
||||
StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
const nsAString& aKey);
|
||||
|
||||
nsresult
|
||||
StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
|
||||
nsTArray<nsString>& aKeysOut);
|
||||
|
||||
// We will wipe out databases with a schema versions less than this.
|
||||
extern const int32_t kMaxWipeSchemaVersion;
|
||||
|
||||
} // namespace db
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+35
-35
@@ -16,7 +16,6 @@
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozilla/dom/cache/ManagerId.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@@ -98,9 +97,8 @@ private:
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FetchPut::Create(Listener* aListener, Manager* aManager,
|
||||
RequestId aRequestId, CacheId aCacheId,
|
||||
const nsTArray<PCacheRequest>& aRequests,
|
||||
FetchPut::Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
||||
const nsTArray<CacheRequest>& aRequests,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
|
||||
FetchPut** aFetchPutOut)
|
||||
{
|
||||
@@ -115,7 +113,7 @@ FetchPut::Create(Listener* aListener, Manager* aManager,
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aRequestId, aCacheId,
|
||||
nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aCacheId,
|
||||
aRequests, aRequestStreams);
|
||||
|
||||
nsresult rv = ref->DispatchToMainThread();
|
||||
@@ -133,13 +131,11 @@ FetchPut::ClearListener()
|
||||
mListener = nullptr;
|
||||
}
|
||||
|
||||
FetchPut::FetchPut(Listener* aListener, Manager* aManager,
|
||||
RequestId aRequestId, CacheId aCacheId,
|
||||
const nsTArray<PCacheRequest>& aRequests,
|
||||
FetchPut::FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
||||
const nsTArray<CacheRequest>& aRequests,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams)
|
||||
: mListener(aListener)
|
||||
, mManager(aManager)
|
||||
, mRequestId(aRequestId)
|
||||
, mCacheId(aCacheId)
|
||||
, mInitiatingThread(NS_GetCurrentThread())
|
||||
, mStateList(aRequests.Length())
|
||||
@@ -151,7 +147,7 @@ FetchPut::FetchPut(Listener* aListener, Manager* aManager,
|
||||
|
||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
||||
State* s = mStateList.AppendElement();
|
||||
s->mPCacheRequest = aRequests[i];
|
||||
s->mCacheRequest = aRequests[i];
|
||||
s->mRequestStream = aRequestStreams[i];
|
||||
}
|
||||
|
||||
@@ -211,14 +207,14 @@ FetchPut::DoFetchOnMainThread()
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MaybeSetError(rv);
|
||||
MaybeSetError(ErrorResult(rv));
|
||||
MaybeCompleteOnMainThread();
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mStateList.Length(); ++i) {
|
||||
nsRefPtr<InternalRequest> internalRequest =
|
||||
ToInternalRequest(mStateList[i].mPCacheRequest);
|
||||
ToInternalRequest(mStateList[i].mCacheRequest);
|
||||
|
||||
// If there is a stream we must clone it so that its still available
|
||||
// to store in the cache later;
|
||||
@@ -240,7 +236,7 @@ FetchPut::DoFetchOnMainThread()
|
||||
mStateList[i].mFetchObserver = new FetchObserver(this);
|
||||
rv = fetchDriver->Fetch(mStateList[i].mFetchObserver);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MaybeSetError(rv);
|
||||
MaybeSetError(ErrorResult(rv));
|
||||
mStateList[i].mFetchObserver = nullptr;
|
||||
mPendingCount -= 1;
|
||||
continue;
|
||||
@@ -258,16 +254,16 @@ FetchPut::FetchComplete(FetchObserver* aObserver,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (aInternalResponse->IsError() && !mResult.Failed()) {
|
||||
MaybeSetError(NS_ERROR_FAILURE);
|
||||
MaybeSetError(ErrorResult(NS_ERROR_FAILURE));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mStateList.Length(); ++i) {
|
||||
if (mStateList[i].mFetchObserver == aObserver) {
|
||||
ErrorResult rv;
|
||||
ToPCacheResponseWithoutBody(mStateList[i].mPCacheResponse,
|
||||
ToCacheResponseWithoutBody(mStateList[i].mCacheResponse,
|
||||
*aInternalResponse, rv);
|
||||
if (rv.Failed()) {
|
||||
mResult = Move(rv);
|
||||
MaybeSetError(Move(rv));
|
||||
} else {
|
||||
aInternalResponse->GetBody(getter_AddRefs(mStateList[i].mResponseStream));
|
||||
}
|
||||
@@ -316,27 +312,27 @@ FetchPut::DoPutOnWorkerThread()
|
||||
for (uint32_t i = 0; i < mStateList.Length(); ++i) {
|
||||
// The spec requires us to catch if content tries to insert a set of
|
||||
// requests that would overwrite each other.
|
||||
if (MatchInPutList(mStateList[i].mPCacheRequest, putList)) {
|
||||
MaybeSetError(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
if (MatchInPutList(mStateList[i].mCacheRequest, putList)) {
|
||||
MaybeSetError(ErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
|
||||
MaybeNotifyListener();
|
||||
return;
|
||||
}
|
||||
|
||||
CacheRequestResponse* entry = putList.AppendElement();
|
||||
entry->request() = mStateList[i].mPCacheRequest;
|
||||
entry->response() = mStateList[i].mPCacheResponse;
|
||||
entry->request() = mStateList[i].mCacheRequest;
|
||||
entry->response() = mStateList[i].mCacheResponse;
|
||||
requestStreamList.AppendElement(mStateList[i].mRequestStream.forget());
|
||||
responseStreamList.AppendElement(mStateList[i].mResponseStream.forget());
|
||||
}
|
||||
mStateList.Clear();
|
||||
|
||||
mManager->CachePutAll(this, mRequestId, mCacheId, putList, requestStreamList,
|
||||
responseStreamList);
|
||||
mManager->ExecutePutAll(this, mCacheId, putList, requestStreamList,
|
||||
responseStreamList);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
FetchPut::MatchInPutList(const PCacheRequest& aRequest,
|
||||
FetchPut::MatchInPutList(const CacheRequest& aRequest,
|
||||
const nsTArray<CacheRequestResponse>& aPutList)
|
||||
{
|
||||
// This method implements the SW spec QueryCache algorithm against an
|
||||
@@ -351,11 +347,11 @@ FetchPut::MatchInPutList(const PCacheRequest& aRequest,
|
||||
}
|
||||
|
||||
nsRefPtr<InternalHeaders> requestHeaders =
|
||||
new InternalHeaders(aRequest.headers());
|
||||
ToInternalHeaders(aRequest.headers());
|
||||
|
||||
for (uint32_t i = 0; i < aPutList.Length(); ++i) {
|
||||
const PCacheRequest& cachedRequest = aPutList[i].request();
|
||||
const PCacheResponse& cachedResponse = aPutList[i].response();
|
||||
const CacheRequest& cachedRequest = aPutList[i].request();
|
||||
const CacheResponse& cachedResponse = aPutList[i].response();
|
||||
|
||||
// If the URLs don't match, then just skip to the next entry.
|
||||
if (aRequest.url() != cachedRequest.url()) {
|
||||
@@ -363,10 +359,10 @@ FetchPut::MatchInPutList(const PCacheRequest& aRequest,
|
||||
}
|
||||
|
||||
nsRefPtr<InternalHeaders> cachedRequestHeaders =
|
||||
new InternalHeaders(cachedRequest.headers());
|
||||
ToInternalHeaders(cachedRequest.headers());
|
||||
|
||||
nsRefPtr<InternalHeaders> cachedResponseHeaders =
|
||||
new InternalHeaders(cachedResponse.headers());
|
||||
ToInternalHeaders(cachedResponse.headers());
|
||||
|
||||
nsAutoTArray<nsCString, 16> varyHeaders;
|
||||
ErrorResult rv;
|
||||
@@ -426,20 +422,25 @@ FetchPut::MatchInPutList(const PCacheRequest& aRequest,
|
||||
}
|
||||
|
||||
void
|
||||
FetchPut::OnCachePutAll(RequestId aRequestId, nsresult aRv)
|
||||
FetchPut::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
CacheId aOpenedCacheId,
|
||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList)
|
||||
{
|
||||
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
|
||||
MaybeSetError(aRv);
|
||||
MOZ_ASSERT(aResult.type() == CacheOpResult::TCachePutAllResult);
|
||||
MaybeSetError(Move(aRv));
|
||||
MaybeNotifyListener();
|
||||
}
|
||||
|
||||
void
|
||||
FetchPut::MaybeSetError(nsresult aRv)
|
||||
FetchPut::MaybeSetError(ErrorResult&& aRv)
|
||||
{
|
||||
if (mResult.Failed() || NS_SUCCEEDED(aRv)) {
|
||||
if (mResult.Failed() || !aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
mResult.Throw(aRv);
|
||||
mResult = Move(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -453,8 +454,7 @@ FetchPut::MaybeNotifyListener()
|
||||
// object is removed from CacheParent::mFetchPutList, so make sure that
|
||||
// doesn't happen until this method returns.
|
||||
nsRefPtr<FetchPut> kungFuDeathGrip(this);
|
||||
mListener->OnFetchPut(this, mRequestId, mResult);
|
||||
mResult.ClearMessage(); // This may contain a TypeError.
|
||||
mListener->OnFetchPut(this, Move(mResult));
|
||||
}
|
||||
|
||||
nsIGlobalObject*
|
||||
|
||||
Vendored
+17
-14
@@ -11,7 +11,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/cache/Manager.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
@@ -40,13 +40,12 @@ public:
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId, const ErrorResult& aRv) = 0;
|
||||
OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) = 0;
|
||||
};
|
||||
|
||||
static nsresult
|
||||
Create(Listener* aListener, Manager* aManager,
|
||||
RequestId aRequestId, CacheId aCacheId,
|
||||
const nsTArray<PCacheRequest>& aRequests,
|
||||
Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
||||
const nsTArray<CacheRequest>& aRequests,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
|
||||
FetchPut** aFetchPutOut);
|
||||
|
||||
@@ -58,19 +57,18 @@ private:
|
||||
friend class FetchObserver;
|
||||
struct State
|
||||
{
|
||||
PCacheRequest mPCacheRequest;
|
||||
CacheRequest mCacheRequest;
|
||||
nsCOMPtr<nsIInputStream> mRequestStream;
|
||||
nsRefPtr<FetchObserver> mFetchObserver;
|
||||
PCacheResponse mPCacheResponse;
|
||||
CacheResponse mCacheResponse;
|
||||
nsCOMPtr<nsIInputStream> mResponseStream;
|
||||
|
||||
nsRefPtr<Request> mRequest;
|
||||
nsRefPtr<Response> mResponse;
|
||||
};
|
||||
|
||||
FetchPut(Listener* aListener, Manager* aManager,
|
||||
RequestId aRequestId, CacheId aCacheId,
|
||||
const nsTArray<PCacheRequest>& aRequests,
|
||||
FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
||||
const nsTArray<CacheRequest>& aRequests,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams);
|
||||
~FetchPut();
|
||||
|
||||
@@ -83,11 +81,17 @@ private:
|
||||
void MaybeCompleteOnMainThread();
|
||||
|
||||
void DoPutOnWorkerThread();
|
||||
static bool MatchInPutList(const PCacheRequest& aRequest,
|
||||
static bool MatchInPutList(const CacheRequest& aRequest,
|
||||
const nsTArray<CacheRequestResponse>& aPutList);
|
||||
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) override;
|
||||
|
||||
void MaybeSetError(nsresult aRv);
|
||||
virtual void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
CacheId aOpenedCacheId,
|
||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList) override;
|
||||
|
||||
void MaybeSetError(ErrorResult&& aRv);
|
||||
void MaybeNotifyListener();
|
||||
|
||||
// TypeUtils methods
|
||||
@@ -101,7 +105,6 @@ private:
|
||||
|
||||
Listener* mListener;
|
||||
nsRefPtr<Manager> mManager;
|
||||
const RequestId mRequestId;
|
||||
const CacheId mCacheId;
|
||||
nsCOMPtr<nsIThread> mInitiatingThread;
|
||||
nsTArray<State> mStateList;
|
||||
|
||||
Vendored
+33
-18
@@ -23,11 +23,24 @@ namespace cache {
|
||||
using mozilla::dom::quota::FileInputStream;
|
||||
using mozilla::dom::quota::FileOutputStream;
|
||||
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
|
||||
using mozilla::unused;
|
||||
|
||||
namespace {
|
||||
|
||||
enum BodyFileType
|
||||
{
|
||||
BODY_FILE_FINAL,
|
||||
BODY_FILE_TMP
|
||||
};
|
||||
|
||||
nsresult
|
||||
BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
|
||||
nsIFile** aBodyFileOut);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyCreateDir(nsIFile* aBaseDir)
|
||||
BodyCreateDir(nsIFile* aBaseDir)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
|
||||
@@ -49,7 +62,7 @@ FileUtils::BodyCreateDir(nsIFile* aBaseDir)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyDeleteDir(nsIFile* aBaseDir)
|
||||
BodyDeleteDir(nsIFile* aBaseDir)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
|
||||
@@ -72,8 +85,7 @@ FileUtils::BodyDeleteDir(nsIFile* aBaseDir)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,
|
||||
nsIFile** aCacheDirOut)
|
||||
BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId, nsIFile** aCacheDirOut)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
MOZ_ASSERT(aCacheDirOut);
|
||||
@@ -107,11 +119,11 @@ FileUtils::BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyStartWriteStream(const QuotaInfo& aQuotaInfo,
|
||||
nsIFile* aBaseDir, nsIInputStream* aSource,
|
||||
void* aClosure,
|
||||
nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
|
||||
nsISupports** aCopyContextOut)
|
||||
BodyStartWriteStream(const QuotaInfo& aQuotaInfo,
|
||||
nsIFile* aBaseDir, nsIInputStream* aSource,
|
||||
void* aClosure,
|
||||
nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
|
||||
nsISupports** aCopyContextOut)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
MOZ_ASSERT(aSource);
|
||||
@@ -168,7 +180,7 @@ FileUtils::BodyStartWriteStream(const QuotaInfo& aQuotaInfo,
|
||||
|
||||
// static
|
||||
void
|
||||
FileUtils::BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext)
|
||||
BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
MOZ_ASSERT(aCopyContext);
|
||||
@@ -182,7 +194,7 @@ FileUtils::BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId)
|
||||
BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
|
||||
@@ -206,8 +218,8 @@ FileUtils::BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
|
||||
const nsID& aId, nsIInputStream** aStreamOut)
|
||||
BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
|
||||
nsIInputStream** aStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
MOZ_ASSERT(aStreamOut);
|
||||
@@ -234,7 +246,7 @@ FileUtils::BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
|
||||
|
||||
// static
|
||||
nsresult
|
||||
FileUtils::BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList)
|
||||
BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
@@ -273,10 +285,11 @@ FileUtils::BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
FileUtils::BodyIdToFile(nsIFile* aBaseDir, const nsID& aId,
|
||||
BodyFileType aType, nsIFile** aBodyFileOut)
|
||||
BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
|
||||
nsIFile** aBodyFileOut)
|
||||
{
|
||||
MOZ_ASSERT(aBaseDir);
|
||||
MOZ_ASSERT(aBodyFileOut);
|
||||
@@ -304,6 +317,8 @@ FileUtils::BodyIdToFile(nsIFile* aBaseDir, const nsID& aId,
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+23
-38
@@ -19,51 +19,36 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
// TODO: remove static class and use functions in cache namespace (bug 1110485)
|
||||
class FileUtils final
|
||||
{
|
||||
public:
|
||||
enum BodyFileType
|
||||
{
|
||||
BODY_FILE_FINAL,
|
||||
BODY_FILE_TMP
|
||||
};
|
||||
nsresult
|
||||
BodyCreateDir(nsIFile* aBaseDir);
|
||||
|
||||
static nsresult BodyCreateDir(nsIFile* aBaseDir);
|
||||
// Note that this function can only be used during the initialization of the
|
||||
// database. We're unlikely to be able to delete the DB successfully past
|
||||
// that point due to the file being in use.
|
||||
static nsresult BodyDeleteDir(nsIFile* aBaseDir);
|
||||
static nsresult BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,
|
||||
nsIFile** aCacheDirOut);
|
||||
// Note that this function can only be used during the initialization of the
|
||||
// database. We're unlikely to be able to delete the DB successfully past
|
||||
// that point due to the file being in use.
|
||||
nsresult
|
||||
BodyDeleteDir(nsIFile* aBaseDir);
|
||||
|
||||
static nsresult
|
||||
BodyStartWriteStream(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
|
||||
nsIInputStream* aSource, void* aClosure,
|
||||
nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
|
||||
nsISupports** aCopyContextOut);
|
||||
nsresult
|
||||
BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId, nsIFile** aCacheDirOut);
|
||||
|
||||
static void
|
||||
BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext);
|
||||
nsresult
|
||||
BodyStartWriteStream(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
|
||||
nsIInputStream* aSource, void* aClosure,
|
||||
nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
|
||||
nsISupports** aCopyContextOut);
|
||||
|
||||
static nsresult
|
||||
BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId);
|
||||
void
|
||||
BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext);
|
||||
|
||||
static nsresult
|
||||
BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
|
||||
nsIInputStream** aStreamOut);
|
||||
nsresult
|
||||
BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId);
|
||||
|
||||
static nsresult
|
||||
BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList);
|
||||
nsresult
|
||||
BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
|
||||
nsIInputStream** aStreamOut);
|
||||
|
||||
private:
|
||||
static nsresult
|
||||
BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
|
||||
nsIFile** aBodyFileOut);
|
||||
|
||||
FileUtils() = delete;
|
||||
~FileUtils() = delete;
|
||||
};
|
||||
nsresult
|
||||
BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList);
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
|
||||
Vendored
+37
@@ -8,10 +8,47 @@
|
||||
#define mozilla_dom_cache_IPCUtils_h
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
// Fix X11 header brain damage that conflicts with HeadersGuardEnum::None
|
||||
#undef None
|
||||
|
||||
#include "mozilla/dom/HeadersBinding.h"
|
||||
#include "mozilla/dom/RequestBinding.h"
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
|
||||
namespace IPC {
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::HeadersGuardEnum> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::HeadersGuardEnum,
|
||||
mozilla::dom::HeadersGuardEnum::None,
|
||||
mozilla::dom::HeadersGuardEnum::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestMode> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestMode,
|
||||
mozilla::dom::RequestMode::Same_origin,
|
||||
mozilla::dom::RequestMode::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestCredentials> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestCredentials,
|
||||
mozilla::dom::RequestCredentials::Omit,
|
||||
mozilla::dom::RequestCredentials::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestCache> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestCache,
|
||||
mozilla::dom::RequestCache::Default,
|
||||
mozilla::dom::RequestCache::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestContext> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestContext,
|
||||
mozilla::dom::RequestContext::Audio,
|
||||
mozilla::dom::RequestContext::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::ResponseType> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::ResponseType,
|
||||
mozilla::dom::ResponseType::Basic,
|
||||
mozilla::dom::ResponseType::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::cache::Namespace> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::cache::Namespace,
|
||||
mozilla::dom::cache::DEFAULT_NAMESPACE,
|
||||
|
||||
Vendored
+327
-348
File diff suppressed because it is too large
Load Diff
Vendored
+62
-73
@@ -7,11 +7,10 @@
|
||||
#ifndef mozilla_dom_cache_Manager_h
|
||||
#define mozilla_dom_cache_Manager_h
|
||||
|
||||
#include "mozilla/dom/cache/CacheInitData.h"
|
||||
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@@ -22,12 +21,11 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CacheOpArgs;
|
||||
class CacheOpResult;
|
||||
class CacheRequestResponse;
|
||||
class Context;
|
||||
class ManagerId;
|
||||
class PCacheQueryParams;
|
||||
class PCacheRequest;
|
||||
class PCacheRequestOrVoid;
|
||||
struct SavedRequest;
|
||||
struct SavedResponse;
|
||||
class StreamList;
|
||||
@@ -41,23 +39,25 @@ class StreamList;
|
||||
// Cache API. This uniqueness is defined by the ManagerId equality operator.
|
||||
// The uniqueness is enforced by the Manager GetOrCreate() factory method.
|
||||
//
|
||||
// The Manager object can out live the IPC actors in the case where the child
|
||||
// process is killed; e.g a child process OOM. The Manager object can
|
||||
// The Manager object can potentially use non-trivial resources. Long lived
|
||||
// DOM objects and their actors should not maintain a reference to the Manager
|
||||
// while idle. Transient DOM objects that may keep a reference for their
|
||||
// lifetimes.
|
||||
// The life cycle of Manager objects is somewhat complex. While code may
|
||||
// hold a strong reference to the Manager, it will invalidate itself once it
|
||||
// believes it has become completely idle. This is currently determined when
|
||||
// all of the following conditions occur:
|
||||
//
|
||||
// For example, once a CacheStorage DOM object is access it will live until its
|
||||
// global is released. Therefore, CacheStorage should release its Manager
|
||||
// reference after operations complete and it becomes idle. Cache objects,
|
||||
// however, can be GC'd once content are done using them and can therefore keep
|
||||
// their Manager reference alive. Its expected that more operations are
|
||||
// performed on a Cache object, so keeping the Manager reference will help
|
||||
// minimize overhead for each reference.
|
||||
// 1) There are no more Manager::Listener objects registered with the Manager
|
||||
// by performing a Cache or Storage operation.
|
||||
// 2) There are no more CacheId references noted via Manager::AddRefCacheId().
|
||||
// 3) There are no more BodyId references noted via Manager::AddRefBodyId().
|
||||
//
|
||||
// In order to keep your Manager alive you should perform an operation to set
|
||||
// a Listener, call AddRefCacheId(), or call AddRefBodyId().
|
||||
//
|
||||
// Even once a Manager becomes invalid, however, it may still continue to
|
||||
// exist. This is allowed so that any in-progress Actions can gracefully
|
||||
// complete.
|
||||
//
|
||||
// As an invariant, all Manager objects must cease all IO before shutdown. This
|
||||
// is enforced by the ShutdownObserver. If content still holds references to
|
||||
// is enforced by the Manager::Factory. If content still holds references to
|
||||
// Cache DOM objects during shutdown, then all operations will begin rejecting.
|
||||
class Manager final
|
||||
{
|
||||
@@ -84,30 +84,36 @@ public:
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual void OnCacheMatch(RequestId aRequestId, nsresult aRv,
|
||||
const SavedResponse* aResponse,
|
||||
StreamList* aStreamList) { }
|
||||
virtual void OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<SavedResponse>& aSavedResponses,
|
||||
StreamList* aStreamList) { }
|
||||
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) { }
|
||||
virtual void OnCacheDelete(RequestId aRequestId, nsresult aRv,
|
||||
bool aSuccess) { }
|
||||
virtual void OnCacheKeys(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<SavedRequest>& aSavedRequests,
|
||||
StreamList* aStreamList) { }
|
||||
// convenience routines
|
||||
void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult);
|
||||
|
||||
virtual void OnStorageMatch(RequestId aRequestId, nsresult aRv,
|
||||
const SavedResponse* aResponse,
|
||||
StreamList* aStreamList) { }
|
||||
virtual void OnStorageHas(RequestId aRequestId, nsresult aRv,
|
||||
bool aCacheFound) { }
|
||||
virtual void OnStorageOpen(RequestId aRequestId, nsresult aRv,
|
||||
CacheId aCacheId) { }
|
||||
virtual void OnStorageDelete(RequestId aRequestId, nsresult aRv,
|
||||
bool aCacheDeleted) { }
|
||||
virtual void OnStorageKeys(RequestId aRequestId, nsresult aRv,
|
||||
const nsTArray<nsString>& aKeys) { }
|
||||
void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
CacheId aOpenedCacheId);
|
||||
|
||||
void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
const SavedResponse& aSavedResponse,
|
||||
StreamList* aStreamList);
|
||||
|
||||
void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
||||
StreamList* aStreamList);
|
||||
|
||||
void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList);
|
||||
|
||||
// interface to be implemented
|
||||
virtual void
|
||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
CacheId aOpenedCacheId,
|
||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList) { }
|
||||
|
||||
protected:
|
||||
~Listener() { }
|
||||
@@ -127,8 +133,8 @@ public:
|
||||
|
||||
// Marks the Manager "invalid". Once the Context completes no new operations
|
||||
// will be permitted with this Manager. New actors will get a new Manager.
|
||||
void Invalidate();
|
||||
bool IsValid() const;
|
||||
void NoteClosing();
|
||||
bool IsClosing() const;
|
||||
|
||||
// If an actor represents a long term reference to a cache or body stream,
|
||||
// then they must call AddRefCacheId() or AddRefBodyId(). This will
|
||||
@@ -148,35 +154,15 @@ public:
|
||||
void AddStreamList(StreamList* aStreamList);
|
||||
void RemoveStreamList(StreamList* aStreamList);
|
||||
|
||||
// TODO: consider moving CacheId up in the argument lists below (bug 1110485)
|
||||
void CacheMatch(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
|
||||
const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams);
|
||||
void CacheMatchAll(Listener* aListener, RequestId aRequestId,
|
||||
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
|
||||
const PCacheQueryParams& aParams);
|
||||
void CachePutAll(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
|
||||
const nsTArray<CacheRequestResponse>& aPutList,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
|
||||
void CacheDelete(Listener* aListener, RequestId aRequestId,
|
||||
CacheId aCacheId, const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams);
|
||||
void CacheKeys(Listener* aListener, RequestId aRequestId,
|
||||
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
|
||||
const PCacheQueryParams& aParams);
|
||||
void ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
|
||||
const CacheOpArgs& aOpArgs);
|
||||
void ExecutePutAll(Listener* aListener, CacheId aCacheId,
|
||||
const nsTArray<CacheRequestResponse>& aPutList,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
|
||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
|
||||
|
||||
void StorageMatch(Listener* aListener, RequestId aRequestId,
|
||||
Namespace aNamespace, const PCacheRequest& aRequest,
|
||||
const PCacheQueryParams& aParams);
|
||||
void StorageHas(Listener* aListener, RequestId aRequestId,
|
||||
Namespace aNamespace, const nsAString& aKey);
|
||||
void StorageOpen(Listener* aListener, RequestId aRequestId,
|
||||
Namespace aNamespace, const nsAString& aKey);
|
||||
void StorageDelete(Listener* aListener, RequestId aRequestId,
|
||||
Namespace aNamespace, const nsAString& aKey);
|
||||
void StorageKeys(Listener* aListener, RequestId aRequestId,
|
||||
Namespace aNamespace);
|
||||
void ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
|
||||
const CacheOpArgs& aOpArgs);
|
||||
|
||||
private:
|
||||
class Factory;
|
||||
@@ -199,6 +185,7 @@ private:
|
||||
|
||||
Manager(ManagerId* aManagerId, nsIThread* aIOThread);
|
||||
~Manager();
|
||||
void Init();
|
||||
void Shutdown();
|
||||
already_AddRefed<Context> CurrentContext();
|
||||
|
||||
@@ -209,6 +196,8 @@ private:
|
||||
bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId);
|
||||
void NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList);
|
||||
|
||||
void MaybeAllowContextToClose();
|
||||
|
||||
nsRefPtr<ManagerId> mManagerId;
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
|
||||
@@ -260,7 +249,7 @@ private:
|
||||
nsTArray<StreamList*> mStreamLists;
|
||||
|
||||
bool mShuttingDown;
|
||||
bool mValid;
|
||||
bool mClosing;
|
||||
|
||||
struct CacheIdRefCounter
|
||||
{
|
||||
|
||||
Vendored
+6
-21
@@ -3,16 +3,13 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PBlob; // FIXME: bug 792908
|
||||
include protocol PCacheOp;
|
||||
include protocol PCachePushStream;
|
||||
include PCacheTypes;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
|
||||
include protocol PBlob; // FIXME: bug 792908
|
||||
include protocol PCacheStreamControl;
|
||||
|
||||
using mozilla::dom::cache::RequestId from "mozilla/dom/cache/Types.h";
|
||||
using mozilla::ErrorResult from "ipc/ErrorIPCUtils.h";
|
||||
include "mozilla/dom/cache/IPCUtils.h";
|
||||
include CacheTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -21,27 +18,15 @@ namespace cache {
|
||||
protocol PCache
|
||||
{
|
||||
manager PBackground;
|
||||
manages PCacheOp;
|
||||
manages PCachePushStream;
|
||||
|
||||
parent:
|
||||
PCacheOp(CacheOpArgs aOpArgs);
|
||||
PCachePushStream();
|
||||
Teardown();
|
||||
Match(RequestId requestId, PCacheRequest request, PCacheQueryParams params);
|
||||
MatchAll(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params);
|
||||
AddAll(RequestId requestId, PCacheRequest[] requests);
|
||||
Put(RequestId requestId, CacheRequestResponse aPut);
|
||||
Delete(RequestId requestId, PCacheRequest request, PCacheQueryParams params);
|
||||
Keys(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params);
|
||||
|
||||
child:
|
||||
MatchResponse(RequestId requestId, nsresult aRv, PCacheResponseOrVoid aResponse);
|
||||
MatchAllResponse(RequestId requestId, nsresult aRv, PCacheResponse[] responses);
|
||||
AddAllResponse(RequestId requestId, ErrorResult aRv);
|
||||
PutResponse(RequestId requestId, nsresult aRv);
|
||||
DeleteResponse(RequestId requestId, nsresult aRv, bool success);
|
||||
KeysResponse(RequestId requestId, nsresult aRv, PCacheRequest[] requests);
|
||||
|
||||
both:
|
||||
__delete__();
|
||||
};
|
||||
|
||||
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
/* 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 protocol PCache;
|
||||
include protocol PCachePushStream;
|
||||
include protocol PCacheStorage;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
|
||||
include CacheTypes;
|
||||
|
||||
using mozilla::ErrorResult from "ipc/ErrorIPCUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
protocol PCacheOp
|
||||
{
|
||||
manager PCache or PCacheStorage;
|
||||
|
||||
child:
|
||||
__delete__(ErrorResult aRv, CacheOpResult aResult);
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Vendored
+6
-17
@@ -3,14 +3,13 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PBlob; // FIXME: bug 792908
|
||||
include protocol PCache;
|
||||
include PCacheTypes;
|
||||
include protocol PCacheOp;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
|
||||
include protocol PBlob; // FIXME: bug 792908
|
||||
include protocol PCacheStreamControl;
|
||||
|
||||
using mozilla::dom::cache::RequestId from "mozilla/dom/cache/IPCUtils.h";
|
||||
include CacheTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -19,23 +18,13 @@ namespace cache {
|
||||
protocol PCacheStorage
|
||||
{
|
||||
manager PBackground;
|
||||
manages PCacheOp;
|
||||
|
||||
parent:
|
||||
PCacheOp(CacheOpArgs aOpArgs);
|
||||
Teardown();
|
||||
Match(RequestId aRequestId, PCacheRequest aRequest,
|
||||
PCacheQueryParams aParams);
|
||||
Has(RequestId aRequestId, nsString aKey);
|
||||
Open(RequestId aRequestId, nsString aKey);
|
||||
Delete(RequestId aRequestId, nsString aKey);
|
||||
Keys(RequestId aRequestId);
|
||||
|
||||
child:
|
||||
MatchResponse(RequestId aRequestId, nsresult aRv,
|
||||
PCacheResponseOrVoid aResponseOrVoid);
|
||||
HasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
|
||||
OpenResponse(RequestId aRequestId, nsresult aRv, nullable PCache aActor);
|
||||
DeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
|
||||
KeysResponse(RequestId aRequestId, nsresult aRv, nsString[] aKeys);
|
||||
__delete__();
|
||||
};
|
||||
|
||||
|
||||
Vendored
-96
@@ -1,96 +0,0 @@
|
||||
/* 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 protocol PCachePushStream;
|
||||
include protocol PCacheStreamControl;
|
||||
include PHeaders;
|
||||
include InputStreamParams;
|
||||
|
||||
using HeadersGuardEnum from "mozilla/dom/FetchIPCUtils.h";
|
||||
using RequestCredentials from "mozilla/dom/FetchIPCUtils.h";
|
||||
using RequestMode from "mozilla/dom/FetchIPCUtils.h";
|
||||
using RequestCache from "mozilla/dom/FetchIPCUtils.h";
|
||||
using RequestContext from "mozilla/dom/FetchIPCUtils.h";
|
||||
using mozilla::dom::ResponseType from "mozilla/dom/FetchIPCUtils.h";
|
||||
using mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
using struct nsID from "nsID.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
struct PCacheQueryParams
|
||||
{
|
||||
bool ignoreSearch;
|
||||
bool ignoreMethod;
|
||||
bool ignoreVary;
|
||||
bool prefixMatch;
|
||||
bool cacheNameSet;
|
||||
nsString cacheName;
|
||||
};
|
||||
|
||||
struct PCacheReadStream
|
||||
{
|
||||
nsID id;
|
||||
OptionalInputStreamParams params;
|
||||
OptionalFileDescriptorSet fds;
|
||||
nullable PCacheStreamControl control;
|
||||
nullable PCachePushStream pushStream;
|
||||
};
|
||||
|
||||
union PCacheReadStreamOrVoid
|
||||
{
|
||||
void_t;
|
||||
PCacheReadStream;
|
||||
};
|
||||
|
||||
struct PCacheRequest
|
||||
{
|
||||
nsCString method;
|
||||
nsString url;
|
||||
nsString urlWithoutQuery;
|
||||
PHeadersEntry[] headers;
|
||||
HeadersGuardEnum headersGuard;
|
||||
nsString referrer;
|
||||
RequestMode mode;
|
||||
RequestCredentials credentials;
|
||||
PCacheReadStreamOrVoid body;
|
||||
uint32_t contentPolicyType;
|
||||
RequestContext context;
|
||||
RequestCache requestCache;
|
||||
};
|
||||
|
||||
union PCacheRequestOrVoid
|
||||
{
|
||||
void_t;
|
||||
PCacheRequest;
|
||||
};
|
||||
|
||||
struct PCacheResponse
|
||||
{
|
||||
ResponseType type;
|
||||
nsString url;
|
||||
uint32_t status;
|
||||
nsCString statusText;
|
||||
PHeadersEntry[] headers;
|
||||
HeadersGuardEnum headersGuard;
|
||||
PCacheReadStreamOrVoid body;
|
||||
nsCString securityInfo;
|
||||
};
|
||||
|
||||
union PCacheResponseOrVoid
|
||||
{
|
||||
void_t;
|
||||
PCacheResponse;
|
||||
};
|
||||
|
||||
struct CacheRequestResponse
|
||||
{
|
||||
PCacheRequest request;
|
||||
PCacheResponse response;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Vendored
+22
-16
@@ -46,25 +46,35 @@ PrincipalVerifier::CreateAndDispatch(Listener* aListener,
|
||||
}
|
||||
|
||||
void
|
||||
PrincipalVerifier::ClearListener()
|
||||
PrincipalVerifier::AddListener(Listener* aListener)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mListener);
|
||||
mListener = nullptr;
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ASSERT(!mListenerList.Contains(aListener));
|
||||
mListenerList.AppendElement(aListener);
|
||||
}
|
||||
|
||||
void
|
||||
PrincipalVerifier::RemoveListener(Listener* aListener)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ALWAYS_TRUE(mListenerList.RemoveElement(aListener));
|
||||
}
|
||||
|
||||
PrincipalVerifier::PrincipalVerifier(Listener* aListener,
|
||||
PBackgroundParent* aActor,
|
||||
const PrincipalInfo& aPrincipalInfo)
|
||||
: mListener(aListener)
|
||||
, mActor(BackgroundParent::GetContentParent(aActor))
|
||||
: mActor(BackgroundParent::GetContentParent(aActor))
|
||||
, mPrincipalInfo(aPrincipalInfo)
|
||||
, mInitiatingThread(NS_GetCurrentThread())
|
||||
, mResult(NS_OK)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mListener);
|
||||
MOZ_ASSERT(mInitiatingThread);
|
||||
MOZ_ASSERT(aListener);
|
||||
|
||||
mListenerList.AppendElement(aListener);
|
||||
}
|
||||
|
||||
PrincipalVerifier::~PrincipalVerifier()
|
||||
@@ -73,7 +83,7 @@ PrincipalVerifier::~PrincipalVerifier()
|
||||
// threads, its a race to see which thread de-refs us last. Therefore
|
||||
// we cannot guarantee which thread we destruct on.
|
||||
|
||||
MOZ_ASSERT(!mListener);
|
||||
MOZ_ASSERT(mListenerList.IsEmpty());
|
||||
|
||||
// We should always be able to explicitly release the actor on the main
|
||||
// thread.
|
||||
@@ -172,17 +182,13 @@ void
|
||||
PrincipalVerifier::CompleteOnInitiatingThread()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// This can happen if the listener is destroyed before we finish. For
|
||||
// example, if the child process OOMs and the actor is destroyed.
|
||||
if (!mListener) {
|
||||
return;
|
||||
ListenerList::ForwardIterator iter(mListenerList);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnPrincipalVerified(mResult, mManagerId);
|
||||
}
|
||||
|
||||
mListener->OnPrincipalVerified(mResult, mManagerId);
|
||||
|
||||
// The listener must clear their reference in OnPrincipalVerified()
|
||||
MOZ_ASSERT(!mListener);
|
||||
// The listener must clear its reference in OnPrincipalVerified()
|
||||
MOZ_ASSERT(mListenerList.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Vendored
+9
-5
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTObserverArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -26,7 +27,7 @@ class PrincipalVerifier final : public nsRunnable
|
||||
public:
|
||||
// An interface to be implemented by code wishing to use the
|
||||
// PrincipalVerifier. Note, the Listener implementation is responsible
|
||||
// for calling ClearListener() on the PrincipalVerifier to clear the
|
||||
// for calling RemoveListener() on the PrincipalVerifier to clear the
|
||||
// weak reference.
|
||||
class Listener
|
||||
{
|
||||
@@ -38,9 +39,11 @@ public:
|
||||
CreateAndDispatch(Listener* aListener, mozilla::ipc::PBackgroundParent* aActor,
|
||||
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
|
||||
// The Listener must call ClearListener() when OnPrincipalVerified() is
|
||||
void AddListener(Listener* aListener);
|
||||
|
||||
// The Listener must call RemoveListener() when OnPrincipalVerified() is
|
||||
// called or when the Listener is destroyed.
|
||||
void ClearListener();
|
||||
void RemoveListener(Listener* aListener);
|
||||
|
||||
private:
|
||||
PrincipalVerifier(Listener* aListener, mozilla::ipc::PBackgroundParent* aActor,
|
||||
@@ -52,8 +55,9 @@ private:
|
||||
|
||||
void DispatchToInitiatingThread(nsresult aRv);
|
||||
|
||||
// Weak reference cleared by ClearListener()
|
||||
Listener* mListener;
|
||||
// Weak reference cleared by RemoveListener()
|
||||
typedef nsTObserverArray<Listener*> ListenerList;
|
||||
ListenerList mListenerList;
|
||||
|
||||
// set in originating thread at construction, but must be accessed and
|
||||
// released on main thread
|
||||
|
||||
Vendored
+37
-12
@@ -9,7 +9,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlChild.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/SnappyUncompressInputStream.h"
|
||||
@@ -34,10 +34,10 @@ public:
|
||||
nsIInputStream* aStream);
|
||||
|
||||
void
|
||||
Serialize(PCacheReadStreamOrVoid* aReadStreamOut);
|
||||
Serialize(CacheReadStreamOrVoid* aReadStreamOut);
|
||||
|
||||
void
|
||||
Serialize(PCacheReadStream* aReadStreamOut);
|
||||
Serialize(CacheReadStream* aReadStreamOut);
|
||||
|
||||
// ReadStream::Controllable methods
|
||||
virtual void
|
||||
@@ -49,6 +49,9 @@ public:
|
||||
virtual bool
|
||||
MatchId(const nsID& aId) const override;
|
||||
|
||||
virtual bool
|
||||
HasEverBeenRead() const override;
|
||||
|
||||
// Simulate nsIInputStream methods, but we don't actually inherit from it
|
||||
NS_METHOD
|
||||
Close();
|
||||
@@ -102,6 +105,7 @@ private:
|
||||
NumStates
|
||||
};
|
||||
Atomic<State> mState;
|
||||
Atomic<bool> mHasEverBeenRead;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(cache::ReadStream::Inner)
|
||||
};
|
||||
@@ -192,17 +196,17 @@ ReadStream::Inner::Inner(StreamControl* aControl, const nsID& aId,
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::Serialize(PCacheReadStreamOrVoid* aReadStreamOut)
|
||||
ReadStream::Inner::Serialize(CacheReadStreamOrVoid* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
PCacheReadStream stream;
|
||||
CacheReadStream stream;
|
||||
Serialize(&stream);
|
||||
*aReadStreamOut = stream;
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Inner::Serialize(PCacheReadStream* aReadStreamOut)
|
||||
ReadStream::Inner::Serialize(CacheReadStream* aReadStreamOut)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
MOZ_ASSERT(aReadStreamOut);
|
||||
@@ -248,6 +252,13 @@ ReadStream::Inner::MatchId(const nsID& aId) const
|
||||
return mId.Equals(aId);
|
||||
}
|
||||
|
||||
bool
|
||||
ReadStream::Inner::HasEverBeenRead() const
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
|
||||
return mHasEverBeenRead;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReadStream::Inner::Close()
|
||||
{
|
||||
@@ -283,6 +294,8 @@ ReadStream::Inner::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
|
||||
Close();
|
||||
}
|
||||
|
||||
mHasEverBeenRead = true;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -293,6 +306,10 @@ ReadStream::Inner::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
// stream ops can happen on any thread
|
||||
MOZ_ASSERT(aNumReadOut);
|
||||
|
||||
if (aCount) {
|
||||
mHasEverBeenRead = true;
|
||||
}
|
||||
|
||||
nsresult rv = mSnappyStream->ReadSegments(aWriter, aClosure, aCount,
|
||||
aNumReadOut);
|
||||
|
||||
@@ -301,6 +318,14 @@ ReadStream::Inner::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
Close();
|
||||
}
|
||||
|
||||
// Verify bytes were actually read before marking as being ever read. For
|
||||
// example, code can test if the stream supports ReadSegments() by calling
|
||||
// this method with a dummy callback which doesn't read anything. We don't
|
||||
// want to trigger on that.
|
||||
if (*aNumReadOut) {
|
||||
mHasEverBeenRead = true;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -390,18 +415,18 @@ NS_IMPL_ISUPPORTS(cache::ReadStream, nsIInputStream, ReadStream);
|
||||
|
||||
// static
|
||||
already_AddRefed<ReadStream>
|
||||
ReadStream::Create(const PCacheReadStreamOrVoid& aReadStreamOrVoid)
|
||||
ReadStream::Create(const CacheReadStreamOrVoid& aReadStreamOrVoid)
|
||||
{
|
||||
if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Create(aReadStreamOrVoid.get_PCacheReadStream());
|
||||
return Create(aReadStreamOrVoid.get_CacheReadStream());
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ReadStream>
|
||||
ReadStream::Create(const PCacheReadStream& aReadStream)
|
||||
ReadStream::Create(const CacheReadStream& aReadStream)
|
||||
{
|
||||
// The parameter may or may not be for a Cache created stream. The way we
|
||||
// tell is by looking at the stream control actor. If the actor exists,
|
||||
@@ -456,13 +481,13 @@ ReadStream::Create(PCacheStreamControlParent* aControl, const nsID& aId,
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Serialize(PCacheReadStreamOrVoid* aReadStreamOut)
|
||||
ReadStream::Serialize(CacheReadStreamOrVoid* aReadStreamOut)
|
||||
{
|
||||
mInner->Serialize(aReadStreamOut);
|
||||
}
|
||||
|
||||
void
|
||||
ReadStream::Serialize(PCacheReadStream* aReadStreamOut)
|
||||
ReadStream::Serialize(CacheReadStream* aReadStreamOut)
|
||||
{
|
||||
mInner->Serialize(aReadStreamOut);
|
||||
}
|
||||
|
||||
Vendored
+9
-6
@@ -21,8 +21,8 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class PCacheReadStream;
|
||||
class PCacheReadStreamOrVoid;
|
||||
class CacheReadStream;
|
||||
class CacheReadStreamOrVoid;
|
||||
class PCacheStreamControlParent;
|
||||
|
||||
// IID for the dom::cache::ReadStream interface
|
||||
@@ -63,6 +63,9 @@ public:
|
||||
virtual bool
|
||||
MatchId(const nsID& aId) const = 0;
|
||||
|
||||
virtual bool
|
||||
HasEverBeenRead() const = 0;
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType)
|
||||
AddRef(void) = 0;
|
||||
|
||||
@@ -71,17 +74,17 @@ public:
|
||||
};
|
||||
|
||||
static already_AddRefed<ReadStream>
|
||||
Create(const PCacheReadStreamOrVoid& aReadStreamOrVoid);
|
||||
Create(const CacheReadStreamOrVoid& aReadStreamOrVoid);
|
||||
|
||||
static already_AddRefed<ReadStream>
|
||||
Create(const PCacheReadStream& aReadStream);
|
||||
Create(const CacheReadStream& aReadStream);
|
||||
|
||||
static already_AddRefed<ReadStream>
|
||||
Create(PCacheStreamControlParent* aControl, const nsID& aId,
|
||||
nsIInputStream* aStream);
|
||||
|
||||
void Serialize(PCacheReadStreamOrVoid* aReadStreamOut);
|
||||
void Serialize(PCacheReadStream* aReadStreamOut);
|
||||
void Serialize(CacheReadStreamOrVoid* aReadStreamOut);
|
||||
void Serialize(CacheReadStream* aReadStreamOut);
|
||||
|
||||
private:
|
||||
class Inner;
|
||||
|
||||
Vendored
+3
-3
@@ -10,7 +10,7 @@
|
||||
// NOTE: This cannot be rolled into Types.h because the IPC dependency.
|
||||
// breaks webidl unified builds.
|
||||
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsID.h"
|
||||
@@ -23,7 +23,7 @@ namespace cache {
|
||||
struct SavedRequest
|
||||
{
|
||||
SavedRequest() : mHasBodyId(false) { mValue.body() = void_t(); }
|
||||
PCacheRequest mValue;
|
||||
CacheRequest mValue;
|
||||
bool mHasBodyId;
|
||||
nsID mBodyId;
|
||||
CacheId mCacheId;
|
||||
@@ -32,7 +32,7 @@ struct SavedRequest
|
||||
struct SavedResponse
|
||||
{
|
||||
SavedResponse() : mHasBodyId(false) { mValue.body() = void_t(); }
|
||||
PCacheResponse mValue;
|
||||
CacheResponse mValue;
|
||||
bool mHasBodyId;
|
||||
nsID mBodyId;
|
||||
CacheId mCacheId;
|
||||
|
||||
Vendored
+12
@@ -84,6 +84,18 @@ StreamControl::CloseAllReadStreamsWithoutReporting()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
StreamControl::HasEverBeenRead() const
|
||||
{
|
||||
ReadStreamList::ForwardIterator iter(mReadStreamList);
|
||||
while (iter.HasMore()) {
|
||||
if (iter.GetNext()->HasEverBeenRead()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
Vendored
+7
-4
@@ -20,7 +20,7 @@ namespace ipc {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class PCacheReadStream;
|
||||
class CacheReadStream;
|
||||
|
||||
// Abstract class to help implement the stream control Child and Parent actors.
|
||||
// This provides an interface to partly help with serialization of IPC types,
|
||||
@@ -30,14 +30,14 @@ class StreamControl
|
||||
public:
|
||||
// abstract interface that must be implemented by child class
|
||||
virtual void
|
||||
SerializeControl(PCacheReadStream* aReadStreamOut) = 0;
|
||||
SerializeControl(CacheReadStream* aReadStreamOut) = 0;
|
||||
|
||||
virtual void
|
||||
SerializeFds(PCacheReadStream* aReadStreamOut,
|
||||
SerializeFds(CacheReadStream* aReadStreamOut,
|
||||
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) = 0;
|
||||
|
||||
virtual void
|
||||
DeserializeFds(const PCacheReadStream& aReadStream,
|
||||
DeserializeFds(const CacheReadStream& aReadStream,
|
||||
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) = 0;
|
||||
|
||||
// inherited implementation of the ReadStream::Controllable list
|
||||
@@ -68,6 +68,9 @@ protected:
|
||||
void
|
||||
CloseAllReadStreamsWithoutReporting();
|
||||
|
||||
bool
|
||||
HasEverBeenRead() const;
|
||||
|
||||
// protected parts of the abstract interface
|
||||
virtual void
|
||||
NoteClosedAfterForget(const nsID& aId) = 0;
|
||||
|
||||
Vendored
-151
@@ -1,151 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/cache/StreamUtils.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlChild.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
namespace {
|
||||
|
||||
using mozilla::unused;
|
||||
using mozilla::void_t;
|
||||
using mozilla::dom::cache::CacheStreamControlChild;
|
||||
using mozilla::dom::cache::Feature;
|
||||
using mozilla::dom::cache::PCacheReadStream;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::FileDescriptorSetChild;
|
||||
using mozilla::ipc::OptionalFileDescriptorSet;
|
||||
|
||||
void
|
||||
StartDestroyStreamChild(const PCacheReadStream& aReadStream)
|
||||
{
|
||||
CacheStreamControlChild* cacheControl =
|
||||
static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
|
||||
if (cacheControl) {
|
||||
cacheControl->StartDestroy();
|
||||
}
|
||||
|
||||
if (aReadStream.fds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
|
||||
FileDescriptorSetChild* fdSetActor =
|
||||
static_cast<FileDescriptorSetChild*>(aReadStream.fds().get_PFileDescriptorSetChild());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const PCacheReadStream& aReadStream, Feature* aFeature)
|
||||
{
|
||||
CacheStreamControlChild* cacheControl =
|
||||
static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
|
||||
if (cacheControl) {
|
||||
cacheControl->SetFeature(aFeature);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
StartDestroyStreamChild(const PCacheResponseOrVoid& aResponseOrVoid)
|
||||
{
|
||||
if (aResponseOrVoid.type() == PCacheResponseOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
StartDestroyStreamChild(aResponseOrVoid.get_PCacheResponse());
|
||||
}
|
||||
|
||||
void
|
||||
StartDestroyStreamChild(const PCacheResponse& aResponse)
|
||||
{
|
||||
if (aResponse.body().type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
StartDestroyStreamChild(aResponse.body().get_PCacheReadStream());
|
||||
}
|
||||
|
||||
void
|
||||
StartDestroyStreamChild(const nsTArray<PCacheResponse>& aResponses)
|
||||
{
|
||||
for (uint32_t i = 0; i < aResponses.Length(); ++i) {
|
||||
StartDestroyStreamChild(aResponses[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StartDestroyStreamChild(const nsTArray<PCacheRequest>& aRequests)
|
||||
{
|
||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
||||
if (aRequests[i].body().type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
continue;
|
||||
}
|
||||
StartDestroyStreamChild(aRequests[i].body().get_PCacheReadStream());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const PCacheResponseOrVoid& aResponseOrVoid,
|
||||
Feature* aFeature)
|
||||
{
|
||||
if (aResponseOrVoid.type() == PCacheResponseOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddFeatureToStreamChild(aResponseOrVoid.get_PCacheResponse(), aFeature);
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const PCacheResponse& aResponse,
|
||||
Feature* aFeature)
|
||||
{
|
||||
if (aResponse.body().type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddFeatureToStreamChild(aResponse.body().get_PCacheReadStream(), aFeature);
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const nsTArray<PCacheResponse>& aResponses,
|
||||
Feature* aFeature)
|
||||
{
|
||||
for (uint32_t i = 0; i < aResponses.Length(); ++i) {
|
||||
AddFeatureToStreamChild(aResponses[i], aFeature);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AddFeatureToStreamChild(const nsTArray<PCacheRequest>& aRequests,
|
||||
Feature* aFeature)
|
||||
{
|
||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
||||
if (aRequests[i].body().type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
continue;
|
||||
}
|
||||
AddFeatureToStreamChild(aRequests[i].body().get_PCacheReadStream(),
|
||||
aFeature);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Vendored
-39
@@ -1,39 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_cache_StreamUtils_h
|
||||
#define mozilla_dom_cache_StreamUtils_h
|
||||
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class Feature;
|
||||
class PCacheRequest;
|
||||
class PCacheResponse;
|
||||
class PCacheResponseOrVoid;
|
||||
|
||||
void StartDestroyStreamChild(const PCacheResponseOrVoid& aResponseOrVoid);
|
||||
void StartDestroyStreamChild(const PCacheResponse& aResponse);
|
||||
void StartDestroyStreamChild(const nsTArray<PCacheResponse>& aResponses);
|
||||
void StartDestroyStreamChild(const nsTArray<PCacheRequest>& aRequests);
|
||||
|
||||
void AddFeatureToStreamChild(const PCacheResponseOrVoid& aResponseOrVoid,
|
||||
Feature* aFeature);
|
||||
void AddFeatureToStreamChild(const PCacheResponse& aResponse,
|
||||
Feature* aFeature);
|
||||
void AddFeatureToStreamChild(const nsTArray<PCacheResponse>& aResponses,
|
||||
Feature* aFeature);
|
||||
void AddFeatureToStreamChild(const nsTArray<PCacheRequest>& aRequests,
|
||||
Feature* aFeature);
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_cache_StreamUtils_h
|
||||
Vendored
+56
-23
@@ -12,7 +12,7 @@
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
@@ -34,7 +34,9 @@ namespace {
|
||||
using mozilla::ErrorResult;
|
||||
using mozilla::unused;
|
||||
using mozilla::void_t;
|
||||
using mozilla::dom::cache::PCacheReadStream;
|
||||
using mozilla::dom::InternalHeaders;
|
||||
using mozilla::dom::cache::CacheReadStream;
|
||||
using mozilla::dom::cache::HeadersEntry;
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::PBackgroundChild;
|
||||
@@ -130,7 +132,7 @@ HasVaryStar(mozilla::dom::InternalHeaders* aHeaders)
|
||||
}
|
||||
|
||||
void
|
||||
SerializeNormalStream(nsIInputStream* aStream, PCacheReadStream& aReadStreamOut)
|
||||
SerializeNormalStream(nsIInputStream* aStream, CacheReadStream& aReadStreamOut)
|
||||
{
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
SerializeInputStream(aStream, aReadStreamOut.params(), fds);
|
||||
@@ -154,6 +156,20 @@ SerializeNormalStream(nsIInputStream* aStream, PCacheReadStream& aReadStreamOut)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
|
||||
{
|
||||
MOZ_ASSERT(aHeaders);
|
||||
|
||||
nsAutoTArray<InternalHeaders::Entry, 16> entryList;
|
||||
aHeaders->GetEntries(entryList);
|
||||
|
||||
for (uint32_t i = 0; i < entryList.Length(); ++i) {
|
||||
InternalHeaders::Entry& entry = entryList[i];
|
||||
aOut.AppendElement(HeadersEntry(entry.mName, entry.mValue));
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
@@ -206,10 +222,10 @@ TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
||||
}
|
||||
|
||||
void
|
||||
TypeUtils::ToPCacheRequest(PCacheRequest& aOut, InternalRequest* aIn,
|
||||
BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||
TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aIn);
|
||||
|
||||
@@ -245,7 +261,7 @@ TypeUtils::ToPCacheRequest(PCacheRequest& aOut, InternalRequest* aIn,
|
||||
|
||||
nsRefPtr<InternalHeaders> headers = aIn->Headers();
|
||||
MOZ_ASSERT(headers);
|
||||
headers->GetPHeaders(aOut.headers());
|
||||
ToHeadersEntryList(aOut.headers(), headers);
|
||||
aOut.headersGuard() = headers->Guard();
|
||||
aOut.mode() = aIn->Mode();
|
||||
aOut.credentials() = aIn->GetCredentialsMode();
|
||||
@@ -269,8 +285,8 @@ TypeUtils::ToPCacheRequest(PCacheRequest& aOut, InternalRequest* aIn,
|
||||
}
|
||||
|
||||
void
|
||||
TypeUtils::ToPCacheResponseWithoutBody(PCacheResponse& aOut,
|
||||
InternalResponse& aIn, ErrorResult& aRv)
|
||||
TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
|
||||
InternalResponse& aIn, ErrorResult& aRv)
|
||||
{
|
||||
aOut.type() = aIn.Type();
|
||||
|
||||
@@ -295,13 +311,13 @@ TypeUtils::ToPCacheResponseWithoutBody(PCacheResponse& aOut,
|
||||
aRv.ThrowTypeError(MSG_RESPONSE_HAS_VARY_STAR);
|
||||
return;
|
||||
}
|
||||
headers->GetPHeaders(aOut.headers());
|
||||
ToHeadersEntryList(aOut.headers(), headers);
|
||||
aOut.headersGuard() = headers->Guard();
|
||||
aOut.securityInfo() = aIn.GetSecurityInfo();
|
||||
}
|
||||
|
||||
void
|
||||
TypeUtils::ToPCacheResponse(PCacheResponse& aOut, Response& aIn, ErrorResult& aRv)
|
||||
TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn, ErrorResult& aRv)
|
||||
{
|
||||
if (aIn.BodyUsed()) {
|
||||
aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
|
||||
@@ -309,7 +325,7 @@ TypeUtils::ToPCacheResponse(PCacheResponse& aOut, Response& aIn, ErrorResult& aR
|
||||
}
|
||||
|
||||
nsRefPtr<InternalResponse> ir = aIn.GetInternalResponse();
|
||||
ToPCacheResponseWithoutBody(aOut, *ir, aRv);
|
||||
ToCacheResponseWithoutBody(aOut, *ir, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@@ -328,8 +344,8 @@ TypeUtils::ToPCacheResponse(PCacheResponse& aOut, Response& aIn, ErrorResult& aR
|
||||
|
||||
// static
|
||||
void
|
||||
TypeUtils::ToPCacheQueryParams(PCacheQueryParams& aOut,
|
||||
const CacheQueryOptions& aIn)
|
||||
TypeUtils::ToCacheQueryParams(CacheQueryParams& aOut,
|
||||
const CacheQueryOptions& aIn)
|
||||
{
|
||||
aOut.ignoreSearch() = aIn.mIgnoreSearch;
|
||||
aOut.ignoreMethod() = aIn.mIgnoreMethod;
|
||||
@@ -344,7 +360,7 @@ TypeUtils::ToPCacheQueryParams(PCacheQueryParams& aOut,
|
||||
}
|
||||
|
||||
already_AddRefed<Response>
|
||||
TypeUtils::ToResponse(const PCacheResponse& aIn)
|
||||
TypeUtils::ToResponse(const CacheResponse& aIn)
|
||||
{
|
||||
if (aIn.type() == ResponseType::Error) {
|
||||
nsRefPtr<InternalResponse> error = InternalResponse::NetworkError();
|
||||
@@ -357,7 +373,7 @@ TypeUtils::ToResponse(const PCacheResponse& aIn)
|
||||
ir->SetUrl(NS_ConvertUTF16toUTF8(aIn.url()));
|
||||
|
||||
nsRefPtr<InternalHeaders> internalHeaders =
|
||||
new InternalHeaders(aIn.headers(), aIn.headersGuard());
|
||||
ToInternalHeaders(aIn.headers(), aIn.headersGuard());
|
||||
ErrorResult result;
|
||||
ir->Headers()->SetGuard(aIn.headersGuard(), result);
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
@@ -392,7 +408,7 @@ TypeUtils::ToResponse(const PCacheResponse& aIn)
|
||||
}
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
TypeUtils::ToInternalRequest(const PCacheRequest& aIn)
|
||||
TypeUtils::ToInternalRequest(const CacheRequest& aIn)
|
||||
{
|
||||
nsRefPtr<InternalRequest> internalRequest = new InternalRequest();
|
||||
|
||||
@@ -409,7 +425,7 @@ TypeUtils::ToInternalRequest(const PCacheRequest& aIn)
|
||||
internalRequest->SetCacheMode(aIn.requestCache());
|
||||
|
||||
nsRefPtr<InternalHeaders> internalHeaders =
|
||||
new InternalHeaders(aIn.headers(), aIn.headersGuard());
|
||||
ToInternalHeaders(aIn.headers(), aIn.headersGuard());
|
||||
ErrorResult result;
|
||||
internalRequest->Headers()->SetGuard(aIn.headersGuard(), result);
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
@@ -424,13 +440,30 @@ TypeUtils::ToInternalRequest(const PCacheRequest& aIn)
|
||||
}
|
||||
|
||||
already_AddRefed<Request>
|
||||
TypeUtils::ToRequest(const PCacheRequest& aIn)
|
||||
TypeUtils::ToRequest(const CacheRequest& aIn)
|
||||
{
|
||||
nsRefPtr<InternalRequest> internalRequest = ToInternalRequest(aIn);
|
||||
nsRefPtr<Request> request = new Request(GetGlobalObject(), internalRequest);
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<InternalHeaders>
|
||||
TypeUtils::ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
||||
HeadersGuardEnum aGuard)
|
||||
{
|
||||
nsTArray<InternalHeaders::Entry> entryList(aHeadersEntryList.Length());
|
||||
|
||||
for (uint32_t i = 0; i < aHeadersEntryList.Length(); ++i) {
|
||||
const HeadersEntry& headersEntry = aHeadersEntryList[i];
|
||||
entryList.AppendElement(InternalHeaders::Entry(headersEntry.name(),
|
||||
headersEntry.value()));
|
||||
}
|
||||
|
||||
nsRefPtr<InternalHeaders> ref = new InternalHeaders(Move(entryList), aGuard);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
ErrorResult& aRv)
|
||||
@@ -478,7 +511,7 @@ TypeUtils::ToInternalRequest(const nsAString& aIn, ErrorResult& aRv)
|
||||
|
||||
void
|
||||
TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
|
||||
PCacheReadStreamOrVoid* aStreamOut,
|
||||
CacheReadStreamOrVoid* aStreamOut,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
*aStreamOut = void_t();
|
||||
@@ -493,7 +526,7 @@ TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
|
||||
return;
|
||||
}
|
||||
|
||||
PCacheReadStream readStream;
|
||||
CacheReadStream readStream;
|
||||
readStream.controlChild() = nullptr;
|
||||
readStream.controlParent() = nullptr;
|
||||
readStream.pushStreamChild() = nullptr;
|
||||
@@ -517,7 +550,7 @@ TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
|
||||
|
||||
void
|
||||
TypeUtils::SerializePushStream(nsIInputStream* aStream,
|
||||
PCacheReadStream& aReadStreamOut,
|
||||
CacheReadStream& aReadStreamOut,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
||||
|
||||
Vendored
+24
-17
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "nsError.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
@@ -29,11 +30,12 @@ class Response;
|
||||
namespace cache {
|
||||
|
||||
class CachePushStreamChild;
|
||||
class PCacheQueryParams;
|
||||
class PCacheReadStream;
|
||||
class PCacheReadStreamOrVoid;
|
||||
class PCacheRequest;
|
||||
class PCacheResponse;
|
||||
class CacheQueryParams;
|
||||
class CacheReadStream;
|
||||
class CacheReadStreamOrVoid;
|
||||
class CacheRequest;
|
||||
class CacheResponse;
|
||||
class HeadersEntry;
|
||||
|
||||
class TypeUtils
|
||||
{
|
||||
@@ -77,28 +79,33 @@ public:
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToPCacheRequest(PCacheRequest& aOut, InternalRequest* aIn,
|
||||
BodyAction aBodyAction, ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
BodyAction aBodyAction, ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToPCacheResponseWithoutBody(PCacheResponse& aOut, InternalResponse& aIn,
|
||||
ErrorResult& aRv);
|
||||
ToCacheResponseWithoutBody(CacheResponse& aOut, InternalResponse& aIn,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToPCacheResponse(PCacheResponse& aOut, Response& aIn, ErrorResult& aRv);
|
||||
ToCacheResponse(CacheResponse& aOut, Response& aIn, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToPCacheQueryParams(PCacheQueryParams& aOut, const CacheQueryOptions& aIn);
|
||||
ToCacheQueryParams(CacheQueryParams& aOut, const CacheQueryOptions& aIn);
|
||||
|
||||
already_AddRefed<Response>
|
||||
ToResponse(const PCacheResponse& aIn);
|
||||
ToResponse(const CacheResponse& aIn);
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
ToInternalRequest(const PCacheRequest& aIn);
|
||||
ToInternalRequest(const CacheRequest& aIn);
|
||||
|
||||
already_AddRefed<Request>
|
||||
ToRequest(const PCacheRequest& aIn);
|
||||
ToRequest(const CacheRequest& aIn);
|
||||
|
||||
// static methods
|
||||
static already_AddRefed<InternalHeaders>
|
||||
ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
||||
HeadersGuardEnum aGuard = HeadersGuardEnum::None);
|
||||
|
||||
private:
|
||||
void
|
||||
@@ -109,11 +116,11 @@ private:
|
||||
ToInternalRequest(const nsAString& aIn, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SerializeCacheStream(nsIInputStream* aStream, PCacheReadStreamOrVoid* aStreamOut,
|
||||
SerializeCacheStream(nsIInputStream* aStream, CacheReadStreamOrVoid* aStreamOut,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SerializePushStream(nsIInputStream* aStream, PCacheReadStream& aReadStreamOut,
|
||||
SerializePushStream(nsIInputStream* aStream, CacheReadStream& aReadStreamOut,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
|
||||
Vendored
+1
-3
@@ -22,9 +22,7 @@ enum Namespace
|
||||
CHROME_ONLY_NAMESPACE,
|
||||
NUMBER_OF_NAMESPACES
|
||||
};
|
||||
|
||||
typedef uintptr_t RequestId;
|
||||
static const RequestId INVALID_REQUEST_ID = 0;
|
||||
static const Namespace INVALID_NAMESPACE = NUMBER_OF_NAMESPACES;
|
||||
|
||||
typedef int64_t CacheId;
|
||||
static const CacheId INVALID_CACHE_ID = -1;
|
||||
|
||||
Vendored
+6
-4
@@ -11,6 +11,8 @@ EXPORTS.mozilla.dom.cache += [
|
||||
'AutoUtils.h',
|
||||
'Cache.h',
|
||||
'CacheChild.h',
|
||||
'CacheOpChild.h',
|
||||
'CacheOpParent.h',
|
||||
'CacheParent.h',
|
||||
'CachePushStreamChild.h',
|
||||
'CachePushStreamParent.h',
|
||||
@@ -35,7 +37,6 @@ EXPORTS.mozilla.dom.cache += [
|
||||
'SavedTypes.h',
|
||||
'StreamControl.h',
|
||||
'StreamList.h',
|
||||
'StreamUtils.h',
|
||||
'Types.h',
|
||||
'TypeUtils.h',
|
||||
]
|
||||
@@ -46,6 +47,8 @@ UNIFIED_SOURCES += [
|
||||
'AutoUtils.cpp',
|
||||
'Cache.cpp',
|
||||
'CacheChild.cpp',
|
||||
'CacheOpChild.cpp',
|
||||
'CacheOpParent.cpp',
|
||||
'CacheParent.cpp',
|
||||
'CachePushStreamChild.cpp',
|
||||
'CachePushStreamParent.cpp',
|
||||
@@ -68,17 +71,16 @@ UNIFIED_SOURCES += [
|
||||
'ReadStream.cpp',
|
||||
'StreamControl.cpp',
|
||||
'StreamList.cpp',
|
||||
'StreamUtils.cpp',
|
||||
'TypeUtils.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'CacheInitData.ipdlh',
|
||||
'CacheTypes.ipdlh',
|
||||
'PCache.ipdl',
|
||||
'PCacheOp.ipdl',
|
||||
'PCachePushStream.ipdl',
|
||||
'PCacheStorage.ipdl',
|
||||
'PCacheStreamControl.ipdl',
|
||||
'PCacheTypes.ipdlh',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FetchIPCUtils_h
|
||||
#define mozilla_dom_FetchIPCUtils_h
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
// Fix X11 header brain damage that conflicts with HeadersGuardEnum::None
|
||||
#undef None
|
||||
|
||||
#include "mozilla/dom/HeadersBinding.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
|
||||
namespace IPC {
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::HeadersGuardEnum> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::HeadersGuardEnum,
|
||||
mozilla::dom::HeadersGuardEnum::None,
|
||||
mozilla::dom::HeadersGuardEnum::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestMode> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestMode,
|
||||
mozilla::dom::RequestMode::Same_origin,
|
||||
mozilla::dom::RequestMode::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestCredentials> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestCredentials,
|
||||
mozilla::dom::RequestCredentials::Omit,
|
||||
mozilla::dom::RequestCredentials::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestCache> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestCache,
|
||||
mozilla::dom::RequestCache::Default,
|
||||
mozilla::dom::RequestCache::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::RequestContext> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::RequestContext,
|
||||
mozilla::dom::RequestContext::Audio,
|
||||
mozilla::dom::RequestContext::EndGuard_> {};
|
||||
template<>
|
||||
struct ParamTraits<mozilla::dom::ResponseType> :
|
||||
public ContiguousEnumSerializer<mozilla::dom::ResponseType,
|
||||
mozilla::dom::ResponseType::Basic,
|
||||
mozilla::dom::ResponseType::EndGuard_> {};
|
||||
}
|
||||
|
||||
#endif // mozilla_dom_FetchIPCUtils_h
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/PHeaders.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsContentUtils.h"
|
||||
@@ -17,21 +16,11 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
InternalHeaders::InternalHeaders(const nsTArray<PHeadersEntry>& aHeaders,
|
||||
InternalHeaders::InternalHeaders(const nsTArray<Entry>&& aHeaders,
|
||||
HeadersGuardEnum aGuard)
|
||||
: mGuard(aGuard)
|
||||
, mList(aHeaders)
|
||||
{
|
||||
for (uint32_t i = 0; i < aHeaders.Length(); ++i) {
|
||||
mList.AppendElement(Entry(aHeaders[i].name(), aHeaders[i].value()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InternalHeaders::GetPHeaders(nsTArray<PHeadersEntry>& aPHeadersOut) const
|
||||
{
|
||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||
aPHeadersOut.AppendElement(PHeadersEntry(mList[i].mName, mList[i].mValue));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace dom {
|
||||
|
||||
template<typename T> class MozMap;
|
||||
class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
|
||||
class PHeadersEntry;
|
||||
|
||||
class InternalHeaders final
|
||||
{
|
||||
@@ -62,7 +61,7 @@ public:
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
}
|
||||
|
||||
explicit InternalHeaders(const nsTArray<PHeadersEntry>& aHeaders,
|
||||
explicit InternalHeaders(const nsTArray<Entry>&& aHeaders,
|
||||
HeadersGuardEnum aGuard = HeadersGuardEnum::None);
|
||||
|
||||
void Append(const nsACString& aName, const nsACString& aValue,
|
||||
@@ -91,9 +90,6 @@ public:
|
||||
static already_AddRefed<InternalHeaders>
|
||||
CORSHeaders(InternalHeaders* aHeaders);
|
||||
|
||||
void
|
||||
GetPHeaders(nsTArray<PHeadersEntry>& aPHeadersOut) const;
|
||||
|
||||
void
|
||||
GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const;
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct PHeadersEntry
|
||||
{
|
||||
nsCString name;
|
||||
nsCString value;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -7,7 +7,6 @@
|
||||
EXPORTS.mozilla.dom += [
|
||||
'Fetch.h',
|
||||
'FetchDriver.h',
|
||||
'FetchIPCUtils.h',
|
||||
'Headers.h',
|
||||
'InternalHeaders.h',
|
||||
'InternalRequest.h',
|
||||
@@ -27,12 +26,6 @@ UNIFIED_SOURCES += [
|
||||
'Response.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'PHeaders.ipdlh',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../workers',
|
||||
# For nsDataHandler.h
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
|
||||
// As required
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto);
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// setter and getter
|
||||
void Register(RTCIdentityProvider& aIdp);
|
||||
|
||||
@@ -60,12 +60,13 @@ nsPluginPlayPreviewInfo::GetWhitelist(nsACString& aWhitelist)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
/* static */ nsresult
|
||||
nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
|
||||
const nsACString& aObjectURI,
|
||||
const nsACString& aWhitelist,
|
||||
bool *_retval)
|
||||
{
|
||||
if (mWhitelist.Length() == 0) {
|
||||
if (aWhitelist.Length() == 0) {
|
||||
// Considering empty whitelist as '*' entry.
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
@@ -76,8 +77,8 @@ nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
|
||||
// where page_url and object_url pattern matches for aPageURI
|
||||
// and aObjectURI, and performs matching as the same time.
|
||||
nsACString::const_iterator start, end;
|
||||
mWhitelist.BeginReading(start);
|
||||
mWhitelist.EndReading(end);
|
||||
aWhitelist.BeginReading(start);
|
||||
aWhitelist.EndReading(end);
|
||||
|
||||
nsAutoCString pageURI(aPageURI);
|
||||
nsAutoCString objectURI(aObjectURI);
|
||||
@@ -143,3 +144,11 @@ nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
|
||||
const nsACString& aObjectURI,
|
||||
bool *_retval)
|
||||
{
|
||||
return CheckWhitelist(aPageURI, aObjectURI, mWhitelist, _retval);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,18 @@ public:
|
||||
const char* aWhitelist);
|
||||
explicit nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource);
|
||||
|
||||
/** This function checks aPageURI and aObjectURI against the whitelist
|
||||
* specified in aWhitelist. This is public static function because this
|
||||
* whitelist checking code needs to be accessed without any instances of
|
||||
* nsIPluginPlayPreviewInfo. In particular, the Shumway whitelist is
|
||||
* obtained directly from prefs and compared using this code for telemetry
|
||||
* purposes.
|
||||
*/
|
||||
static nsresult CheckWhitelist(const nsACString& aPageURI,
|
||||
const nsACString& aObjectURI,
|
||||
const nsACString& aWhitelist,
|
||||
bool *_retval);
|
||||
|
||||
nsCString mMimeType;
|
||||
bool mIgnoreCTP;
|
||||
nsCString mRedirectURL;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include <stdint.h> // for intptr_t
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "PluginInstanceParent.h"
|
||||
#include "BrowserStreamParent.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsFocusManager.h"
|
||||
@@ -54,6 +56,10 @@ extern const wchar_t* kFlashFullscreenClass;
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif // defined(XP_MACOSX)
|
||||
|
||||
// This is the pref used to determine whether to use Shumway on a Flash object
|
||||
// (when Shumway is enabled).
|
||||
static const char kShumwayWhitelistPref[] = "shumway.swf.whitelist";
|
||||
|
||||
using namespace mozilla::plugins;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gl;
|
||||
@@ -104,6 +110,7 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
||||
, mUseSurrogate(true)
|
||||
, mNPP(npp)
|
||||
, mNPNIface(npniface)
|
||||
, mIsWhitelistedForShumway(false)
|
||||
, mWindowType(NPWindowTypeWindow)
|
||||
, mDrawingModel(kDefaultDrawingModel)
|
||||
#if defined(OS_WIN)
|
||||
@@ -143,9 +150,38 @@ PluginInstanceParent::~PluginInstanceParent()
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::Init()
|
||||
PluginInstanceParent::InitMetadata(const nsACString& aMimeType,
|
||||
const nsACString& aSrcAttribute)
|
||||
{
|
||||
return true;
|
||||
if (aSrcAttribute.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// Ensure that the src attribute is absolute
|
||||
nsRefPtr<nsPluginInstanceOwner> owner = GetOwner();
|
||||
if (!owner) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIURI> baseUri(owner->GetBaseURI());
|
||||
nsresult rv = NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
// Check the whitelist
|
||||
nsAutoCString baseUrlSpec;
|
||||
rv = baseUri->GetSpec(baseUrlSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
auto whitelist = Preferences::GetCString(kShumwayWhitelistPref);
|
||||
// Empty whitelist is interpreted by CheckWhitelist as "allow everything,"
|
||||
// which is not valid for our use case and should be treated as a failure.
|
||||
if (whitelist.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
rv = nsPluginPlayPreviewInfo::CheckWhitelist(baseUrlSpec, mSrcAttribute,
|
||||
whitelist,
|
||||
&mIsWhitelistedForShumway);
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -68,7 +68,8 @@ public:
|
||||
|
||||
virtual ~PluginInstanceParent();
|
||||
|
||||
bool Init();
|
||||
bool InitMetadata(const nsACString& aMimeType,
|
||||
const nsACString& aSrcAttribute);
|
||||
NPError Destroy();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
@@ -271,6 +272,24 @@ public:
|
||||
return mUseSurrogate;
|
||||
}
|
||||
|
||||
void
|
||||
GetSrcAttribute(nsACString& aOutput) const
|
||||
{
|
||||
aOutput = mSrcAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function tells us whether this plugin instance would have been
|
||||
* whitelisted for Shumway if Shumway had been enabled. This is being used
|
||||
* for the purpose of gathering telemetry on Flash hangs that could
|
||||
* potentially be avoided by using Shumway instead.
|
||||
*/
|
||||
bool
|
||||
IsWhitelistedForShumway() const
|
||||
{
|
||||
return mIsWhitelistedForShumway;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
AnswerPluginFocusChange(const bool& gotFocus) override;
|
||||
|
||||
@@ -323,6 +342,8 @@ private:
|
||||
bool mUseSurrogate;
|
||||
NPP mNPP;
|
||||
const NPNetscapeFuncs* mNPNIface;
|
||||
nsCString mSrcAttribute;
|
||||
bool mIsWhitelistedForShumway;
|
||||
NPWindowType mWindowType;
|
||||
int16_t mDrawingModel;
|
||||
nsAutoPtr<mozilla::layers::CompositionNotifySink> mNotifySink;
|
||||
|
||||
@@ -33,8 +33,10 @@
|
||||
#include "prsystem.h"
|
||||
#include "GoannaProfiler.h"
|
||||
#include "nsPluginTags.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/plugins/PluginSurfaceParent.h"
|
||||
#include "mozilla/widget/AudioSession.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "PluginHangUIParent.h"
|
||||
@@ -502,6 +504,7 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome)
|
||||
, mNPPIface(nullptr)
|
||||
, mPlugin(nullptr)
|
||||
, mTaskFactory(this)
|
||||
, mIsFlashPlugin(false)
|
||||
, mIsStartingAsync(false)
|
||||
, mNPInitialized(false)
|
||||
, mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
|
||||
@@ -543,17 +546,21 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32
|
||||
, mPluginId(aPluginId)
|
||||
, mChromeTaskFactory(this)
|
||||
, mHangAnnotationFlags(0)
|
||||
, mHangAnnotatorMutex("PluginModuleChromeParent::mHangAnnotatorMutex")
|
||||
#ifdef XP_WIN
|
||||
, mPluginCpuUsageOnHang()
|
||||
, mHangUIParent(nullptr)
|
||||
, mHangUIEnabled(true)
|
||||
, mIsTimerReset(true)
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
, mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
|
||||
, mCrashReporter(nullptr)
|
||||
#endif
|
||||
#endif
|
||||
, mInitOnAsyncConnect(false)
|
||||
, mAsyncInitRv(NS_ERROR_NOT_INITIALIZED)
|
||||
, mAsyncInitError(NPERR_NO_ERROR)
|
||||
, mContentParent(nullptr)
|
||||
, mIsFlashPlugin(false)
|
||||
{
|
||||
NS_ASSERTION(mSubprocess, "Out of memory!");
|
||||
sInstantiated = true;
|
||||
@@ -736,6 +743,119 @@ GetProcessCpuUsage(const InfallibleTArray<base::ProcessHandle>& processHandles,
|
||||
|
||||
#endif // #ifdef XP_WIN
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::OnEnteredCall()
|
||||
{
|
||||
mozilla::ipc::IProtocol* protocol = GetInvokingProtocol();
|
||||
MOZ_ASSERT(protocol);
|
||||
mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
|
||||
mProtocolCallStack.AppendElement(protocol);
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::OnExitedCall()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
|
||||
MOZ_ASSERT(!mProtocolCallStack.IsEmpty());
|
||||
mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1);
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::OnEnteredSyncSend()
|
||||
{
|
||||
mozilla::ipc::IProtocol* protocol = GetInvokingProtocol();
|
||||
MOZ_ASSERT(protocol);
|
||||
mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
|
||||
mProtocolCallStack.AppendElement(protocol);
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::OnExitedSyncSend()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
|
||||
MOZ_ASSERT(!mProtocolCallStack.IsEmpty());
|
||||
mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function converts the topmost routing id on the call stack (as recorded
|
||||
* by the MessageChannel) into a pointer to a IProtocol object.
|
||||
*/
|
||||
mozilla::ipc::IProtocol*
|
||||
PluginModuleChromeParent::GetInvokingProtocol()
|
||||
{
|
||||
int32_t routingId = GetIPCChannel()->GetTopmostMessageRoutingId();
|
||||
// Nothing being routed. No protocol. Just return nullptr.
|
||||
if (routingId == MSG_ROUTING_NONE) {
|
||||
return nullptr;
|
||||
}
|
||||
// If routingId is MSG_ROUTING_CONTROL then we're dealing with control
|
||||
// messages that were initiated by the topmost managing protocol, ie. this.
|
||||
if (routingId == MSG_ROUTING_CONTROL) {
|
||||
return this;
|
||||
}
|
||||
// Otherwise we can look up the protocol object by the routing id.
|
||||
mozilla::ipc::IProtocol* protocol = Lookup(routingId);
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function examines the IProtocol object parameter and converts it into
|
||||
* the PluginInstanceParent object that is associated with that protocol, if
|
||||
* any. Since PluginInstanceParent manages subprotocols, this function needs
|
||||
* to determine whether |aProtocol| is a subprotocol, and if so it needs to
|
||||
* obtain the protocol's manager.
|
||||
*
|
||||
* This function needs to be updated if the subprotocols are modified in
|
||||
* PPluginInstance.ipdl.
|
||||
*/
|
||||
PluginInstanceParent*
|
||||
PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol)
|
||||
{
|
||||
MOZ_ASSERT(aProtocol);
|
||||
mozilla::ipc::MessageListener* listener =
|
||||
static_cast<mozilla::ipc::MessageListener*>(aProtocol);
|
||||
switch (listener->GetProtocolTypeId()) {
|
||||
case PPluginInstanceMsgStart:
|
||||
// In this case, aProtocol is the instance itself. Just cast it.
|
||||
return static_cast<PluginInstanceParent*>(aProtocol);
|
||||
case PPluginBackgroundDestroyerMsgStart: {
|
||||
PPluginBackgroundDestroyerParent* actor =
|
||||
static_cast<PPluginBackgroundDestroyerParent*>(aProtocol);
|
||||
return static_cast<PluginInstanceParent*>(actor->Manager());
|
||||
}
|
||||
case PPluginScriptableObjectMsgStart: {
|
||||
PPluginScriptableObjectParent* actor =
|
||||
static_cast<PPluginScriptableObjectParent*>(aProtocol);
|
||||
return static_cast<PluginInstanceParent*>(actor->Manager());
|
||||
}
|
||||
case PBrowserStreamMsgStart: {
|
||||
PBrowserStreamParent* actor =
|
||||
static_cast<PBrowserStreamParent*>(aProtocol);
|
||||
return static_cast<PluginInstanceParent*>(actor->Manager());
|
||||
}
|
||||
case PPluginStreamMsgStart: {
|
||||
PPluginStreamParent* actor =
|
||||
static_cast<PPluginStreamParent*>(aProtocol);
|
||||
return static_cast<PluginInstanceParent*>(actor->Manager());
|
||||
}
|
||||
case PStreamNotifyMsgStart: {
|
||||
PStreamNotifyParent* actor =
|
||||
static_cast<PStreamNotifyParent*>(aProtocol);
|
||||
return static_cast<PluginInstanceParent*>(actor->Manager());
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
case PPluginSurfaceMsgStart: {
|
||||
PPluginSurfaceParent* actor =
|
||||
static_cast<PPluginSurfaceParent*>(aProtocol);
|
||||
return static_cast<PluginInstanceParent*>(actor->Manager());
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChromeParent::EnteredCxxStack()
|
||||
{
|
||||
@@ -778,6 +898,24 @@ PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aA
|
||||
aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName);
|
||||
aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"),
|
||||
mPluginVersion);
|
||||
if (mIsFlashPlugin) {
|
||||
bool isWhitelistedForShumway = false;
|
||||
{ // Scope for lock
|
||||
mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
|
||||
if (!mProtocolCallStack.IsEmpty()) {
|
||||
mozilla::ipc::IProtocol* topProtocol =
|
||||
mProtocolCallStack.LastElement();
|
||||
PluginInstanceParent* instance =
|
||||
GetManagingInstance(topProtocol);
|
||||
if (instance) {
|
||||
isWhitelistedForShumway =
|
||||
instance->IsWhitelistedForShumway();
|
||||
}
|
||||
}
|
||||
}
|
||||
aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginIsWhitelistedForShumway"),
|
||||
isWhitelistedForShumway);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,8 +987,7 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop)
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::GetPluginDetails(nsACString& aPluginName,
|
||||
nsACString& aPluginVersion)
|
||||
PluginModuleParent::GetPluginDetails()
|
||||
{
|
||||
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
|
||||
if (!host) {
|
||||
@@ -860,8 +997,9 @@ PluginModuleParent::GetPluginDetails(nsACString& aPluginName,
|
||||
if (!pluginTag) {
|
||||
return false;
|
||||
}
|
||||
aPluginName = pluginTag->mName;
|
||||
aPluginVersion = pluginTag->mVersion;
|
||||
mPluginName = pluginTag->mName;
|
||||
mPluginVersion = pluginTag->mVersion;
|
||||
mIsFlashPlugin = pluginTag->mIsFlashPlugin;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1892,7 +2030,7 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
|
||||
}
|
||||
|
||||
if (mPluginName.IsEmpty()) {
|
||||
GetPluginDetails(mPluginName, mPluginVersion);
|
||||
GetPluginDetails();
|
||||
/** mTimeBlocked measures the time that the main thread has been blocked
|
||||
* on plugin module initialization. As implemented, this is the sum of
|
||||
* plugin-container launch + toolhelp32 snapshot + NP_Initialize.
|
||||
@@ -1922,6 +2060,15 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
|
||||
return NS_PLUGIN_INIT_PENDING;
|
||||
}
|
||||
|
||||
class nsCaseInsensitiveUTF8StringArrayComparator
|
||||
{
|
||||
public:
|
||||
template<class A, class B>
|
||||
bool Equals(const A& a, const B& b) const {
|
||||
return a.Equals(b.get(), nsCaseInsensitiveUTF8StringComparator());
|
||||
}
|
||||
};
|
||||
|
||||
nsresult
|
||||
PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
|
||||
uint16_t mode,
|
||||
@@ -1929,13 +2076,20 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
|
||||
InfallibleTArray<nsCString>& values,
|
||||
NPSavedData* saved, NPError* error)
|
||||
{
|
||||
PluginInstanceParent* parentInstance =
|
||||
new PluginInstanceParent(this, instance,
|
||||
nsDependentCString(pluginType), mNPNIface);
|
||||
nsCaseInsensitiveUTF8StringArrayComparator comparator;
|
||||
NS_NAMED_LITERAL_CSTRING(srcAttributeName, "src");
|
||||
auto srcAttributeIndex = names.IndexOf(srcAttributeName, 0, comparator);
|
||||
nsAutoCString srcAttribute;
|
||||
if (srcAttributeIndex != names.NoIndex) {
|
||||
srcAttribute = values[srcAttributeIndex];
|
||||
}
|
||||
|
||||
if (!parentInstance->Init()) {
|
||||
delete parentInstance;
|
||||
return NS_ERROR_FAILURE;
|
||||
nsDependentCString strPluginType(pluginType);
|
||||
PluginInstanceParent* parentInstance =
|
||||
new PluginInstanceParent(this, instance, strPluginType, mNPNIface);
|
||||
|
||||
if (mIsFlashPlugin) {
|
||||
parentInstance->InitMetadata(strPluginType, srcAttribute);
|
||||
}
|
||||
|
||||
// Release the surrogate reference that was in pdata
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "base/process.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/HangMonitor.h"
|
||||
#include "mozilla/HangAnnotations.h"
|
||||
#include "mozilla/PluginLibrary.h"
|
||||
#include "mozilla/plugins/ScopedMethodFactory.h"
|
||||
#include "mozilla/plugins/PluginProcessParent.h"
|
||||
@@ -261,6 +261,7 @@ protected:
|
||||
TimeDuration mTimeBlocked;
|
||||
nsCString mPluginName;
|
||||
nsCString mPluginVersion;
|
||||
bool mIsFlashPlugin;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
// Dup of plugin's X socket, used to scope its resources to this
|
||||
@@ -269,7 +270,7 @@ protected:
|
||||
#endif
|
||||
|
||||
bool
|
||||
GetPluginDetails(nsACString& aPluginName, nsACString& aPluginVersion);
|
||||
GetPluginDetails();
|
||||
|
||||
friend class mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
@@ -358,6 +359,11 @@ class PluginModuleChromeParent
|
||||
|
||||
void CachedSettingChanged();
|
||||
|
||||
void OnEnteredCall() override;
|
||||
void OnExitedCall() override;
|
||||
void OnEnteredSyncSend() override;
|
||||
void OnExitedSyncSend() override;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
EnteredCxxStack() override;
|
||||
@@ -365,6 +371,9 @@ private:
|
||||
void
|
||||
ExitedCxxStack() override;
|
||||
|
||||
mozilla::ipc::IProtocol* GetInvokingProtocol();
|
||||
PluginInstanceParent* GetManagingInstance(mozilla::ipc::IProtocol* aProtocol);
|
||||
|
||||
virtual void
|
||||
AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
|
||||
|
||||
@@ -417,6 +426,8 @@ private:
|
||||
kHangUIDontShow = (1u << 3)
|
||||
};
|
||||
Atomic<uint32_t> mHangAnnotationFlags;
|
||||
mozilla::Mutex mHangAnnotatorMutex;
|
||||
InfallibleTArray<mozilla::ipc::IProtocol*> mProtocolCallStack;
|
||||
#ifdef XP_WIN
|
||||
InfallibleTArray<float> mPluginCpuUsageOnHang;
|
||||
PluginHangUIParent *mHangUIParent;
|
||||
@@ -469,7 +480,6 @@ private:
|
||||
NPError mAsyncInitError;
|
||||
dom::ContentParent* mContentParent;
|
||||
nsCOMPtr<nsIObserver> mOfflineObserver;
|
||||
bool mIsFlashPlugin;
|
||||
bool mIsBlocklisted;
|
||||
static bool sInstantiated;
|
||||
};
|
||||
|
||||
@@ -193,6 +193,11 @@ public:
|
||||
*name = mMessageName;
|
||||
}
|
||||
|
||||
int32_t GetRoutingId() const
|
||||
{
|
||||
return mMessageRoutingId;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* mMessageName;
|
||||
int32_t mMessageRoutingId;
|
||||
@@ -1826,6 +1831,17 @@ MessageChannel::DumpInterruptStack(const char* const pfx) const
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
MessageChannel::GetTopmostMessageRoutingId() const
|
||||
{
|
||||
MOZ_ASSERT(MessageLoop::current() == mWorkerLoop);
|
||||
if (mCxxStackFrames.empty()) {
|
||||
return MSG_ROUTING_NONE;
|
||||
}
|
||||
const InterruptFrame& frame = mCxxStackFrames.back();
|
||||
return frame.GetRoutingId();
|
||||
}
|
||||
|
||||
bool
|
||||
ParentProcessIsBlocked()
|
||||
{
|
||||
|
||||
@@ -135,6 +135,14 @@ class MessageChannel : HasResultCodes
|
||||
return !mCxxStackFrames.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used by hang annotation code to determine which IPDL
|
||||
* actor is highest in the call stack at the time of the hang. It should
|
||||
* be called from the main thread when a sync or intr message is about to
|
||||
* be sent.
|
||||
*/
|
||||
int32_t GetTopmostMessageRoutingId() const;
|
||||
|
||||
void FlushPendingInterruptQueue();
|
||||
|
||||
// Unsound_IsClosed and Unsound_NumQueuedMessages are safe to call from any
|
||||
|
||||
@@ -5160,6 +5160,11 @@ static bool
|
||||
CheckInternalCall(FunctionCompiler& f, ParseNode* callNode, PropertyName* calleeName,
|
||||
RetType retType, MDefinition** def, Type* type)
|
||||
{
|
||||
if (!f.canCall()) {
|
||||
return f.fail(callNode, "call expressions may not be nested inside heap expressions "
|
||||
"when the module contains a change-heap function");
|
||||
}
|
||||
|
||||
FunctionCompiler::Call call(f, callNode, retType);
|
||||
|
||||
if (!CheckCallArgs(f, callNode, CheckIsVarType, &call))
|
||||
@@ -5205,6 +5210,11 @@ CheckFuncPtrTableAgainstExisting(ModuleCompiler& m, ParseNode* usepn,
|
||||
static bool
|
||||
CheckFuncPtrCall(FunctionCompiler& f, ParseNode* callNode, RetType retType, MDefinition** def, Type* type)
|
||||
{
|
||||
if (!f.canCall()) {
|
||||
return f.fail(callNode, "function-pointer call expressions may not be nested inside heap "
|
||||
"expressions when the module contains a change-heap function");
|
||||
}
|
||||
|
||||
ParseNode* callee = CallCallee(callNode);
|
||||
ParseNode* tableNode = ElemBase(callee);
|
||||
ParseNode* indexExpr = ElemIndex(callee);
|
||||
@@ -5264,6 +5274,11 @@ static bool
|
||||
CheckFFICall(FunctionCompiler& f, ParseNode* callNode, unsigned ffiIndex, RetType retType,
|
||||
MDefinition** def, Type* type)
|
||||
{
|
||||
if (!f.canCall()) {
|
||||
return f.fail(callNode, "FFI call expressions may not be nested inside heap "
|
||||
"expressions when the module contains a change-heap function");
|
||||
}
|
||||
|
||||
PropertyName* calleeName = CallCallee(callNode)->name();
|
||||
|
||||
if (retType == RetType::Float)
|
||||
@@ -6130,11 +6145,6 @@ CheckCoercedCall(FunctionCompiler& f, ParseNode* call, RetType retType, MDefinit
|
||||
{
|
||||
JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed());
|
||||
|
||||
if (!f.canCall()) {
|
||||
return f.fail(call, "call expressions may not be nested inside heap expressions when "
|
||||
"the module contains a change-heap function");
|
||||
}
|
||||
|
||||
if (IsNumericLiteral(f.m(), call)) {
|
||||
AsmJSNumLit literal = ExtractNumericLiteral(f.m(), call);
|
||||
MDefinition* result = f.constant(literal);
|
||||
|
||||
@@ -147,13 +147,18 @@ assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if
|
||||
|
||||
// Tests for no calls in heap index expressions
|
||||
|
||||
const SETUP = USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }';
|
||||
const CHANGE_FUN = 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }';
|
||||
const SETUP = USE_ASM + IMPORT2 + 'var imul=glob.Math.imul; var ffi=ffis.ffi;' + CHANGE_FUN;
|
||||
|
||||
asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] } return f');
|
||||
asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] = 0 } return f');
|
||||
asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] } return f');
|
||||
asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = 0 } return f');
|
||||
asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(imul(i,i)|0) >> 2] = 0 } return f');
|
||||
asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = (imul(i,i)|0) } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(ffi()|0) >> 2] } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(g()|0) >> 2] } function g() { return 0 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(TBL[i&0]()|0) >> 2] } function g() { return 0 } var TBL=[g]; return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(g()|0) >> 2] = 0 } function g() { return 0 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = g()|0 } function g() { return 0 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i32[(g()|0)>>2] >> 2] } function g() { return 0 } return f');
|
||||
@@ -162,6 +167,8 @@ assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[((i32[i>>2]|0) + (g()|0)) >> 2] } function g() { return 0 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[((i32[i>>2]|0) + (g()|0)) >> 2] = 0 } function g() { return 0 } return f');
|
||||
assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = (i32[i>>2]|0) + (g()|0) } function g() { return 0 } return f');
|
||||
if (isSimdAvailable() && typeof SIMD !== 'undefined')
|
||||
asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'var i4 = glob.SIMD.int32x4; var add = i4.add;' + CHANGE_FUN + 'function f(i) { i=i|0; i32[i4(i,1,2,i).x >> 2]; i32[add(i4(0,0,0,0),i4(1,1,1,1)).x >> 2]; } return f');
|
||||
|
||||
// Tests for constant heap accesses when change-heap is used
|
||||
|
||||
|
||||
@@ -83,6 +83,9 @@ CollectLaterSiblings(nsISupports* aElement,
|
||||
|
||||
struct RestyleEnumerateData : RestyleTracker::Hints {
|
||||
nsRefPtr<dom::Element> mElement;
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
UniquePtr<ProfilerBacktrace> mBacktrace;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RestyleCollector {
|
||||
@@ -140,7 +143,9 @@ CollectRestyles(nsISupports* aElement,
|
||||
currentRestyle->mElement = element;
|
||||
currentRestyle->mRestyleHint = aData->mRestyleHint;
|
||||
currentRestyle->mChangeHint = aData->mChangeHint;
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
currentRestyle->mBacktrace = Move(aData->mBacktrace);
|
||||
#endif
|
||||
#ifdef RESTYLE_LOGGING
|
||||
collector->count++;
|
||||
#endif
|
||||
@@ -305,6 +310,12 @@ RestyleTracker::DoProcessRestyles()
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
Maybe<GoannaProfilerTracingRAII> profilerRAII;
|
||||
if (profiler_feature_active("restyle")) {
|
||||
profilerRAII.emplace("Paint", "Styles", Move(data->mBacktrace));
|
||||
}
|
||||
#endif
|
||||
ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint);
|
||||
AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
|
||||
}
|
||||
@@ -340,6 +351,13 @@ RestyleTracker::DoProcessRestyles()
|
||||
FrameTagToString(currentRestyle->mElement).get(),
|
||||
index++, collector.count);
|
||||
LOG_RESTYLE_INDENT();
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
Maybe<GoannaProfilerTracingRAII> profilerRAII;
|
||||
if (profiler_feature_active("restyle")) {
|
||||
profilerRAII.emplace("Paint", "Styles", Move(currentRestyle->mBacktrace));
|
||||
}
|
||||
#endif
|
||||
ProcessOneRestyle(currentRestyle->mElement,
|
||||
currentRestyle->mRestyleHint,
|
||||
currentRestyle->mChangeHint);
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
#include "nsContainerFrame.h"
|
||||
#include "mozilla/SplayTree.h"
|
||||
#include "mozilla/RestyleLogging.h"
|
||||
#include "GoannaProfiler.h"
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
#include "ProfilerBacktrace.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -291,6 +296,9 @@ public:
|
||||
// that we called AddPendingRestyle for and found the element this is
|
||||
// the RestyleData for as its nearest restyle root.
|
||||
nsTArray<nsRefPtr<Element>> mDescendants;
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
UniquePtr<ProfilerBacktrace> mBacktrace;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -388,8 +396,13 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
||||
}
|
||||
|
||||
if (!existingData) {
|
||||
mPendingRestyles.Put(aElement,
|
||||
new RestyleData(aRestyleHint, aMinChangeHint));
|
||||
RestyleData* rd = new RestyleData(aRestyleHint, aMinChangeHint);
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
if (profiler_feature_active("restyle")) {
|
||||
rd->mBacktrace.reset(profiler_get_backtrace());
|
||||
}
|
||||
#endif
|
||||
mPendingRestyles.Put(aElement, rd);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -141,7 +141,7 @@ MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
|
||||
aStr, aFilename, aLine);
|
||||
#else
|
||||
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
|
||||
#ifdef MOZ_DUMP_ASSERTION_STACK
|
||||
#if defined (MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API)
|
||||
nsTraceRefcnt::WalkTheStack(stderr);
|
||||
#endif
|
||||
fflush(stderr);
|
||||
@@ -157,7 +157,7 @@ MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
|
||||
"Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
|
||||
#else
|
||||
fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
|
||||
#ifdef MOZ_DUMP_ASSERTION_STACK
|
||||
#if defined(MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API)
|
||||
nsTraceRefcnt::WalkTheStack(stderr);
|
||||
#endif
|
||||
fflush(stderr);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API) && \
|
||||
!defined(MOZILLA_XPCOMRT_API) && \
|
||||
(defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
|
||||
#define MOZ_REFCOUNTED_LEAK_CHECKING
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@
|
||||
* symbols. We add the weak attribute to the import version of the MFBT API
|
||||
* macros to exploit this.
|
||||
*/
|
||||
# if defined(MOZ_GLUE_IN_PROGRAM)
|
||||
# if defined(MOZ_GLUE_IN_PROGRAM) && !defined(MOZILLA_XPCOMRT_API)
|
||||
# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API
|
||||
# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA
|
||||
# else
|
||||
|
||||
@@ -108,10 +108,10 @@ function testHistogram(histogramId, expectedNonZeroRanges) {
|
||||
* the test data that will be used by the following tests.
|
||||
*/
|
||||
add_task(function test_initialize() {
|
||||
let oldCanRecord = Services.telemetry.canRecord;
|
||||
Services.telemetry.canRecord = true;
|
||||
let oldCanRecord = Services.telemetry.canRecordExtended;
|
||||
Services.telemetry.canRecordExtended = true;
|
||||
do_register_cleanup(function () {
|
||||
Services.telemetry.canRecord = oldCanRecord;
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
});
|
||||
|
||||
let uniqueNumber = 1;
|
||||
|
||||
@@ -4338,6 +4338,12 @@
|
||||
"extended_statistics_ok": true,
|
||||
"description": "Number of histograms with total count low errors"
|
||||
},
|
||||
"TELEMETRY_DISCARDED_CONTENT_PINGS_COUNT": {
|
||||
"alert_emails": ["perf-telemetry-alerts@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "count",
|
||||
"description": "Count of discarded content payloads."
|
||||
},
|
||||
"TELEMETRY_FILES_EVICTED": {
|
||||
"alert_emails": ["perf-telemetry-alerts@mozilla.com", "rvitillo@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsBaseHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@@ -53,6 +54,7 @@
|
||||
#include "nsReadableUtils.h"
|
||||
#include "plstr.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/ProcessedStack.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
@@ -78,6 +80,7 @@ using base::LinearHistogram;
|
||||
using base::StatisticsRecorder;
|
||||
|
||||
const char KEYED_HISTOGRAM_NAME_SEPARATOR[] = "#";
|
||||
const char SUBSESSION_HISTOGRAM_PREFIX[] = "sub#";
|
||||
|
||||
enum reflectStatus {
|
||||
REFLECT_OK,
|
||||
@@ -234,7 +237,7 @@ public:
|
||||
*/
|
||||
struct AnnotationInfo {
|
||||
AnnotationInfo(uint32_t aHangIndex,
|
||||
UniquePtr<HangAnnotations> aAnnotations)
|
||||
HangAnnotationsPtr aAnnotations)
|
||||
: mHangIndex(aHangIndex)
|
||||
, mAnnotations(Move(aAnnotations))
|
||||
{}
|
||||
@@ -250,7 +253,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
uint32_t mHangIndex;
|
||||
UniquePtr<HangAnnotations> mAnnotations;
|
||||
HangAnnotationsPtr mAnnotations;
|
||||
|
||||
private:
|
||||
// Force move constructor
|
||||
@@ -260,7 +263,7 @@ public:
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
void AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration,
|
||||
int32_t aSystemUptime, int32_t aFirefoxUptime,
|
||||
UniquePtr<HangAnnotations> aAnnotations);
|
||||
HangAnnotationsPtr aAnnotations);
|
||||
uint32_t GetDuration(unsigned aIndex) const;
|
||||
int32_t GetSystemUptime(unsigned aIndex) const;
|
||||
int32_t GetFirefoxUptime(unsigned aIndex) const;
|
||||
@@ -289,7 +292,7 @@ HangReports::AddHang(const Telemetry::ProcessedStack& aStack,
|
||||
uint32_t aDuration,
|
||||
int32_t aSystemUptime,
|
||||
int32_t aFirefoxUptime,
|
||||
UniquePtr<HangAnnotations> aAnnotations) {
|
||||
HangAnnotationsPtr aAnnotations) {
|
||||
HangInfo info = { aDuration, aSystemUptime, aFirefoxUptime };
|
||||
mHangInfo.push_back(info);
|
||||
if (aAnnotations) {
|
||||
@@ -639,7 +642,8 @@ class TelemetryImpl final
|
||||
public:
|
||||
void InitMemoryReporter();
|
||||
|
||||
static bool CanRecord();
|
||||
static bool CanRecordBase();
|
||||
static bool CanRecordExtended();
|
||||
static already_AddRefed<nsITelemetry> CreateTelemetryInstance();
|
||||
static void ShutdownTelemetry();
|
||||
static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName,
|
||||
@@ -685,6 +689,10 @@ private:
|
||||
nsresult GetHistogramByName(const nsACString &name, Histogram **ret);
|
||||
bool ShouldReflectHistogram(Histogram *h);
|
||||
void IdentifyCorruptHistograms(StatisticsRecorder::Histograms &hs);
|
||||
nsresult CreateHistogramSnapshots(JSContext *cx,
|
||||
JS::MutableHandle<JS::Value> ret,
|
||||
bool subsession,
|
||||
bool clearSubsession);
|
||||
typedef StatisticsRecorder::Histograms::iterator HistogramIterator;
|
||||
|
||||
struct AddonHistogramInfo {
|
||||
@@ -710,7 +718,8 @@ private:
|
||||
typedef nsBaseHashtableET<nsDepCharHashKey, Telemetry::ID> CharPtrEntryType;
|
||||
typedef AutoHashtable<CharPtrEntryType> HistogramMapType;
|
||||
HistogramMapType mHistogramMap;
|
||||
bool mCanRecord;
|
||||
bool mCanRecordBase;
|
||||
bool mCanRecordExtended;
|
||||
static TelemetryImpl *sTelemetry;
|
||||
AutoHashtable<SlowSQLEntryType> mPrivateSQL;
|
||||
AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
|
||||
@@ -757,18 +766,22 @@ public:
|
||||
KeyedHistogram(const nsACString &name, const nsACString &expiration,
|
||||
uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount);
|
||||
nsresult GetHistogram(const nsCString& name, Histogram** histogram);
|
||||
Histogram* GetHistogram(const nsCString& name);
|
||||
nsresult GetHistogram(const nsCString& name, Histogram** histogram, bool subsession);
|
||||
Histogram* GetHistogram(const nsCString& name, bool subsession);
|
||||
uint32_t GetHistogramType() const { return mHistogramType; }
|
||||
nsresult GetDataset(uint32_t* dataset) const;
|
||||
nsresult GetJSKeys(JSContext* cx, JS::CallArgs& args);
|
||||
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
void Clear();
|
||||
nsresult GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
bool subsession, bool clearSubsession);
|
||||
|
||||
nsresult Add(const nsCString& key, uint32_t aSample);
|
||||
void Clear(bool subsession);
|
||||
|
||||
private:
|
||||
typedef nsBaseHashtableET<nsCStringHashKey, Histogram*> KeyedHistogramEntry;
|
||||
typedef AutoHashtable<KeyedHistogramEntry> KeyedHistogramMapType;
|
||||
KeyedHistogramMapType mHistogramMap;
|
||||
KeyedHistogramMapType mSubsessionMap;
|
||||
|
||||
struct ReflectKeysArgs {
|
||||
JSContext* jsContext;
|
||||
@@ -971,6 +984,89 @@ GetHistogramByEnumId(Telemetry::ID id, Histogram **ret)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This clones a histogram |existing| with the id |existingId| to a
|
||||
* new histogram with the name |newName|.
|
||||
* For simplicity this is limited to registered histograms.
|
||||
*/
|
||||
Histogram*
|
||||
CloneHistogram(const nsACString& newName, Telemetry::ID existingId,
|
||||
Histogram& existing)
|
||||
{
|
||||
const TelemetryHistogram &info = gHistograms[existingId];
|
||||
Histogram *clone = nullptr;
|
||||
nsresult rv;
|
||||
|
||||
rv = HistogramGet(PromiseFlatCString(newName).get(), info.expiration(),
|
||||
info.histogramType, existing.declared_min(),
|
||||
existing.declared_max(), existing.bucket_count(),
|
||||
true, &clone);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Histogram::SampleSet ss;
|
||||
existing.SnapshotSample(&ss);
|
||||
clone->AddSampleSet(ss);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* This clones a histogram with the id |existingId| to a new histogram
|
||||
* with the name |newName|.
|
||||
* For simplicity this is limited to registered histograms.
|
||||
*/
|
||||
Histogram*
|
||||
CloneHistogram(const nsACString& newName, Telemetry::ID existingId)
|
||||
{
|
||||
Histogram *existing = nullptr;
|
||||
nsresult rv = GetHistogramByEnumId(existingId, &existing);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CloneHistogram(newName, existingId, *existing);
|
||||
}
|
||||
|
||||
Histogram*
|
||||
GetSubsessionHistogram(Histogram& existing)
|
||||
{
|
||||
Telemetry::ID id;
|
||||
nsresult rv = TelemetryImpl::GetHistogramEnumId(existing.histogram_name().c_str(), &id);
|
||||
if (NS_FAILED(rv) || gHistograms[id].keyed) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Histogram* subsession[Telemetry::HistogramCount] = {};
|
||||
if (subsession[id]) {
|
||||
return subsession[id];
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(prefix, SUBSESSION_HISTOGRAM_PREFIX);
|
||||
nsDependentCString existingName(gHistograms[id].id());
|
||||
if (StringBeginsWith(existingName, prefix)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCString subsessionName(prefix);
|
||||
subsessionName.Append(existingName);
|
||||
|
||||
subsession[id] = CloneHistogram(subsessionName, id, existing);
|
||||
return subsession[id];
|
||||
}
|
||||
|
||||
nsresult
|
||||
HistogramAdd(Histogram& histogram, int32_t value)
|
||||
{
|
||||
histogram.Add(value);
|
||||
if (Histogram* subsession = GetSubsessionHistogram(histogram)) {
|
||||
subsession->Add(value);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
FillRanges(JSContext *cx, JS::Handle<JSObject*> array, Histogram *h)
|
||||
{
|
||||
@@ -1069,6 +1165,7 @@ JSHistogram_Add(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
|
||||
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
|
||||
MOZ_ASSERT(h);
|
||||
Histogram::ClassType type = h->histogram_type();
|
||||
|
||||
int32_t value = 1;
|
||||
@@ -1089,8 +1186,8 @@ JSHistogram_Add(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
}
|
||||
|
||||
if (TelemetryImpl::CanRecord()) {
|
||||
h->Add(value);
|
||||
if (TelemetryImpl::CanRecordExtended()) {
|
||||
HistogramAdd(*h, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1132,8 +1229,28 @@ JSHistogram_Clear(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool onlySubsession = false;
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() >= 1) {
|
||||
if (!args[0].isBoolean()) {
|
||||
JS_ReportError(cx, "Not a boolean");
|
||||
return false;
|
||||
}
|
||||
|
||||
onlySubsession = JS::ToBoolean(args[0]);
|
||||
}
|
||||
|
||||
Histogram *h = static_cast<Histogram*>(JS_GetPrivate(obj));
|
||||
h->Clear();
|
||||
MOZ_ASSERT(h);
|
||||
if(!onlySubsession) {
|
||||
h->Clear();
|
||||
}
|
||||
|
||||
if (Histogram* subsession = GetSubsessionHistogram(*h)) {
|
||||
subsession->Clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1223,17 +1340,7 @@ JSKeyedHistogram_Add(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
}
|
||||
|
||||
Histogram* h = nullptr;
|
||||
nsresult rv = keyed->GetHistogram(NS_ConvertUTF16toUTF8(key), &h);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(cx, "Failed to get histogram");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TelemetryImpl::CanRecord()) {
|
||||
h->Add(value);
|
||||
}
|
||||
|
||||
keyed->Add(NS_ConvertUTF16toUTF8(key), value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1255,7 +1362,8 @@ JSKeyedHistogram_Keys(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
|
||||
bool
|
||||
JSKeyedHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
KeyedHistogram_SnapshotImpl(JSContext *cx, unsigned argc, JS::Value *vp,
|
||||
bool subsession, bool clearSubsession)
|
||||
{
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj) {
|
||||
@@ -1276,7 +1384,7 @@ JSKeyedHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NS_SUCCEEDED(keyed->GetJSSnapshot(cx, snapshot))) {
|
||||
if (!NS_SUCCEEDED(keyed->GetJSSnapshot(cx, snapshot, subsession, clearSubsession))) {
|
||||
JS_ReportError(cx, "Failed to reflect keyed histograms");
|
||||
return false;
|
||||
}
|
||||
@@ -1292,7 +1400,7 @@ JSKeyedHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
|
||||
Histogram* h = nullptr;
|
||||
nsresult rv = keyed->GetHistogram(NS_ConvertUTF16toUTF8(key), &h);
|
||||
nsresult rv = keyed->GetHistogram(NS_ConvertUTF16toUTF8(key), &h, subsession);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(cx, "Failed to get histogram");
|
||||
return false;
|
||||
@@ -1317,6 +1425,29 @@ JSKeyedHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JSKeyedHistogram_Snapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
return KeyedHistogram_SnapshotImpl(cx, argc, vp, false, false);
|
||||
}
|
||||
|
||||
bool
|
||||
JSKeyedHistogram_SubsessionSnapshot(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
return KeyedHistogram_SnapshotImpl(cx, argc, vp, true, false);
|
||||
}
|
||||
|
||||
bool
|
||||
JSKeyedHistogram_SnapshotSubsessionAndClear(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 0) {
|
||||
JS_ReportError(cx, "No key arguments supported for snapshotSubsessionAndClear");
|
||||
}
|
||||
|
||||
return KeyedHistogram_SnapshotImpl(cx, argc, vp, true, true);
|
||||
}
|
||||
|
||||
bool
|
||||
JSKeyedHistogram_Clear(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
@@ -1330,7 +1461,19 @@ JSKeyedHistogram_Clear(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
keyed->Clear();
|
||||
bool onlySubsession = false;
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() >= 1) {
|
||||
if (!(args[0].isNumber() || args[0].isBoolean())) {
|
||||
JS_ReportError(cx, "Not a boolean");
|
||||
return false;
|
||||
}
|
||||
|
||||
onlySubsession = JS::ToBoolean(args[0]);
|
||||
}
|
||||
|
||||
keyed->Clear(onlySubsession);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1371,6 +1514,8 @@ WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx, JS::MutableHandle<
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!(JS_DefineFunction(cx, obj, "add", JSKeyedHistogram_Add, 2, 0)
|
||||
&& JS_DefineFunction(cx, obj, "snapshot", JSKeyedHistogram_Snapshot, 1, 0)
|
||||
&& JS_DefineFunction(cx, obj, "subsessionSnapshot", JSKeyedHistogram_SubsessionSnapshot, 1, 0)
|
||||
&& JS_DefineFunction(cx, obj, "snapshotSubsessionAndClear", JSKeyedHistogram_SnapshotSubsessionAndClear, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "keys", JSKeyedHistogram_Keys, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "clear", JSKeyedHistogram_Clear, 0, 0)
|
||||
&& JS_DefineFunction(cx, obj, "dataset", JSKeyedHistogram_Dataset, 0, 0))) {
|
||||
@@ -1568,7 +1713,7 @@ TelemetryImpl::AsyncFetchTelemetryData(nsIFetchTelemetryDataCallback *aCallback)
|
||||
// We make this check so that GetShutdownTimeFileName() doesn't get
|
||||
// called; calling that function without telemetry enabled violates
|
||||
// assumptions that the write-the-shutdown-timestamp machinery makes.
|
||||
if (!Telemetry::CanRecord()) {
|
||||
if (!Telemetry::CanRecordExtended()) {
|
||||
mCachedTelemetryData = true;
|
||||
aCallback->Complete();
|
||||
return NS_OK;
|
||||
@@ -1622,7 +1767,10 @@ TelemetryImpl::AsyncFetchTelemetryData(nsIFetchTelemetryDataCallback *aCallback)
|
||||
|
||||
TelemetryImpl::TelemetryImpl():
|
||||
mHistogramMap(Telemetry::HistogramCount),
|
||||
mCanRecord(XRE_GetProcessType() == GoannaProcessType_Default),
|
||||
mCanRecordBase(XRE_GetProcessType() == GoannaProcessType_Default ||
|
||||
XRE_GetProcessType() == GoannaProcessType_Content),
|
||||
mCanRecordExtended(XRE_GetProcessType() == GoannaProcessType_Default ||
|
||||
XRE_GetProcessType() == GoannaProcessType_Content),
|
||||
mHashMutex("Telemetry::mHashMutex"),
|
||||
mHangReportsMutex("Telemetry::mHangReportsMutex"),
|
||||
mCachedTelemetryData(false),
|
||||
@@ -1658,6 +1806,7 @@ mFailedLockCount(0)
|
||||
mTrackedDBs.MarkImmutable();
|
||||
#endif
|
||||
|
||||
// Create registered keyed histograms
|
||||
for (size_t i = 0; i < ArrayLength(gHistograms); ++i) {
|
||||
const TelemetryHistogram& h = gHistograms[i];
|
||||
if (!h.keyed) {
|
||||
@@ -1834,25 +1983,12 @@ TelemetryImpl::HistogramFrom(const nsACString &name, const nsACString &existing_
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
const TelemetryHistogram &p = gHistograms[id];
|
||||
|
||||
Histogram *existing;
|
||||
rv = GetHistogramByEnumId(id, &existing);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
Histogram* clone = CloneHistogram(name, id);
|
||||
if (!clone) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Histogram *clone;
|
||||
rv = HistogramGet(PromiseFlatCString(name).get(), p.expiration(),
|
||||
p.histogramType, existing->declared_min(),
|
||||
existing->declared_max(), existing->bucket_count(),
|
||||
true, &clone);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
Histogram::SampleSet ss;
|
||||
existing->SnapshotSample(&ss);
|
||||
clone->AddSampleSet(ss);
|
||||
return WrapAndReturnHistogram(clone, cx, ret);
|
||||
}
|
||||
|
||||
@@ -2035,8 +2171,11 @@ TelemetryImpl::UnregisterAddonHistograms(const nsACString &id)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
||||
nsresult
|
||||
TelemetryImpl::CreateHistogramSnapshots(JSContext *cx,
|
||||
JS::MutableHandle<JS::Value> ret,
|
||||
bool subsession,
|
||||
bool clearSubsession)
|
||||
{
|
||||
JS::Rooted<JSObject*> root_obj(cx, JS_NewPlainObject(cx));
|
||||
if (!root_obj)
|
||||
@@ -2077,6 +2216,14 @@ TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value>
|
||||
continue;
|
||||
}
|
||||
|
||||
Histogram* original = h;
|
||||
if (subsession) {
|
||||
h = GetSubsessionHistogram(*h);
|
||||
if (!h) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
hobj = JS_NewPlainObject(cx);
|
||||
if (!hobj) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@@ -2090,15 +2237,33 @@ TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value>
|
||||
case REFLECT_FAILURE:
|
||||
return NS_ERROR_FAILURE;
|
||||
case REFLECT_OK:
|
||||
if (!JS_DefineProperty(cx, root_obj, h->histogram_name().c_str(), hobj,
|
||||
JSPROP_ENUMERATE)) {
|
||||
if (!JS_DefineProperty(cx, root_obj, original->histogram_name().c_str(),
|
||||
hobj, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (subsession && clearSubsession) {
|
||||
h->Clear();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
||||
{
|
||||
return CreateHistogramSnapshots(cx, ret, false, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::SnapshotSubsessionHistograms(bool clearSubsession,
|
||||
JSContext *cx,
|
||||
JS::MutableHandle<JS::Value> ret)
|
||||
{
|
||||
return CreateHistogramSnapshots(cx, ret, true, clearSubsession);
|
||||
}
|
||||
|
||||
bool
|
||||
TelemetryImpl::CreateHistogramForAddon(const nsACString &name,
|
||||
AddonHistogramInfo &info)
|
||||
@@ -2204,7 +2369,7 @@ TelemetryImpl::KeyedHistogramsReflector(const nsACString& key, nsAutoPtr<KeyedHi
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
if (!NS_SUCCEEDED(entry->GetJSSnapshot(cx, snapshot))) {
|
||||
if (!NS_SUCCEEDED(entry->GetJSSnapshot(cx, snapshot, false, false))) {
|
||||
return PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
@@ -2357,9 +2522,9 @@ TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle<JS::Value> ret)
|
||||
if (!jsAnnotation) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoPtr<HangAnnotations::Enumerator> annotationsEnum;
|
||||
if (!annotationInfo[iterIndex].mAnnotations->GetEnumerator(
|
||||
annotationsEnum.StartAssignment())) {
|
||||
UniquePtr<HangAnnotations::Enumerator> annotationsEnum =
|
||||
annotationInfo[iterIndex].mAnnotations->GetEnumerator();
|
||||
if (!annotationsEnum) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoString key;
|
||||
@@ -2722,24 +2887,56 @@ TelemetryImpl::GetKeyedHistogramById(const nsACString &name)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::GetCanRecord(bool *ret) {
|
||||
*ret = mCanRecord;
|
||||
TelemetryImpl::GetCanRecordBase(bool *ret) {
|
||||
*ret = mCanRecordBase;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::SetCanRecord(bool canRecord) {
|
||||
mCanRecord = !!canRecord;
|
||||
TelemetryImpl::SetCanRecordBase(bool canRecord) {
|
||||
mCanRecordBase = canRecord;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if Telemetry can record base data (FHR data). This is true if the
|
||||
* FHR data reporting service or self-support are enabled.
|
||||
*
|
||||
* In the unlikely event that adding a new base probe is needed, please check the data
|
||||
* collection wiki at https://wiki.mozilla.org/Firefox/Data_Collection and talk to the
|
||||
* Telemetry team.
|
||||
*/
|
||||
bool
|
||||
TelemetryImpl::CanRecord() {
|
||||
return !sTelemetry || sTelemetry->mCanRecord;
|
||||
TelemetryImpl::CanRecordBase() {
|
||||
return !sTelemetry || sTelemetry->mCanRecordBase;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::GetCanSend(bool *ret) {
|
||||
TelemetryImpl::GetCanRecordExtended(bool *ret) {
|
||||
*ret = mCanRecordExtended;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::SetCanRecordExtended(bool canRecord) {
|
||||
mCanRecordExtended = canRecord;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if Telemetry is allowed to record extended data. Returns false if the user
|
||||
* hasn't opted into "extended Telemetry" on the Release channel, when the user has
|
||||
* explicitly opted out of Telemetry on Nightly/Aurora/Beta or if manually set to false
|
||||
* during tests.
|
||||
* If the returned value is false, gathering of extended telemetry statistics is disabled.
|
||||
*/
|
||||
bool
|
||||
TelemetryImpl::CanRecordExtended() {
|
||||
return !sTelemetry || sTelemetry->mCanRecordExtended;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TelemetryImpl::GetIsOfficialTelemetry(bool *ret) {
|
||||
#if defined(MOZILLA_OFFICIAL) && defined(MOZ_TELEMETRY_REPORTING)
|
||||
*ret = true;
|
||||
#else
|
||||
@@ -2934,7 +3131,7 @@ TelemetryImpl::RecordSlowStatement(const nsACString &sql,
|
||||
const nsACString &dbName,
|
||||
uint32_t delay)
|
||||
{
|
||||
if (!sTelemetry || !sTelemetry->mCanRecord)
|
||||
if (!sTelemetry || !sTelemetry->mCanRecordExtended)
|
||||
return;
|
||||
|
||||
bool isFirefoxDB = sTelemetry->mTrackedDBs.Contains(dbName);
|
||||
@@ -3069,7 +3266,7 @@ RecordShutdownStartTimeStamp() {
|
||||
recorded = true;
|
||||
#endif
|
||||
|
||||
if (!Telemetry::CanRecord())
|
||||
if (!Telemetry::CanRecordExtended())
|
||||
return;
|
||||
|
||||
gRecordedShutdownStartTime = TimeStamp::Now();
|
||||
@@ -3120,13 +3317,13 @@ Accumulate(ID aHistogram, uint32_t aSample)
|
||||
{
|
||||
return;
|
||||
/*
|
||||
if (!TelemetryImpl::CanRecord()) {
|
||||
if (!TelemetryImpl::CanRecordExtended()) {
|
||||
return;
|
||||
}
|
||||
Histogram *h;
|
||||
nsresult rv = GetHistogramByEnumId(aHistogram, &h);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
h->Add(aSample);
|
||||
HistogramAdd(*h, aSample);
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -3135,7 +3332,7 @@ Accumulate(ID aID, const nsCString& aKey, uint32_t aSample)
|
||||
{
|
||||
return;
|
||||
/*
|
||||
if (!TelemetryImpl::CanRecord()) {
|
||||
if (!TelemetryImpl::CanRecordExtended()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3143,10 +3340,7 @@ return;
|
||||
KeyedHistogram* keyed = TelemetryImpl::GetKeyedHistogramById(nsDependentCString(th.id()));
|
||||
MOZ_ASSERT(keyed);
|
||||
|
||||
Histogram* histogram = keyed->GetHistogram(aKey);
|
||||
if (histogram) {
|
||||
histogram->Add(aSample);
|
||||
}
|
||||
keyed->Add(aKey, aSample);
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -3155,7 +3349,7 @@ Accumulate(const char* name, uint32_t sample)
|
||||
{
|
||||
return;
|
||||
/*
|
||||
if (!TelemetryImpl::CanRecord()) {
|
||||
if (!TelemetryImpl::CanRecordExtended()) {
|
||||
return;
|
||||
}
|
||||
ID id;
|
||||
@@ -3167,7 +3361,7 @@ return;
|
||||
Histogram *h;
|
||||
rv = GetHistogramByEnumId(id, &h);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
h->Add(sample);
|
||||
HistogramAdd(*h, sample);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -3183,9 +3377,15 @@ return;
|
||||
}
|
||||
|
||||
bool
|
||||
CanRecord()
|
||||
CanRecordBase()
|
||||
{
|
||||
return false; // TelemetryImpl::CanRecord();
|
||||
return false; // TelemetryImpl::CanRecordBase();
|
||||
}
|
||||
|
||||
bool
|
||||
CanRecordExtended()
|
||||
{
|
||||
return false; // TelemetryImpl::CanRecordExtended();
|
||||
}
|
||||
|
||||
base::Histogram*
|
||||
@@ -3388,6 +3588,7 @@ KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expirat
|
||||
uint32_t histogramType, uint32_t min, uint32_t max,
|
||||
uint32_t bucketCount)
|
||||
: mHistogramMap()
|
||||
, mSubsessionMap()
|
||||
, mName(name)
|
||||
, mExpiration(expiration)
|
||||
, mHistogramType(histogramType)
|
||||
@@ -3398,15 +3599,21 @@ KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expirat
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
|
||||
KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram,
|
||||
bool subsession)
|
||||
{
|
||||
KeyedHistogramEntry* entry = mHistogramMap.GetEntry(key);
|
||||
KeyedHistogramMapType& map = subsession ? mSubsessionMap : mHistogramMap;
|
||||
KeyedHistogramEntry* entry = map.GetEntry(key);
|
||||
if (entry) {
|
||||
*histogram = entry->mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString histogramName = mName;
|
||||
nsCString histogramName;
|
||||
if (subsession) {
|
||||
histogramName.Append(SUBSESSION_HISTOGRAM_PREFIX);
|
||||
}
|
||||
histogramName.Append(mName);
|
||||
histogramName.Append(KEYED_HISTOGRAM_NAME_SEPARATOR);
|
||||
histogramName.Append(key);
|
||||
|
||||
@@ -3422,7 +3629,7 @@ KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
|
||||
h->SetFlags(Histogram::kExtendedStatisticsFlag);
|
||||
*histogram = h;
|
||||
|
||||
entry = mHistogramMap.PutEntry(key);
|
||||
entry = map.PutEntry(key);
|
||||
if (MOZ_UNLIKELY(!entry)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -3432,10 +3639,10 @@ KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram)
|
||||
}
|
||||
|
||||
Histogram*
|
||||
KeyedHistogram::GetHistogram(const nsCString& key)
|
||||
KeyedHistogram::GetHistogram(const nsCString& key, bool subsession)
|
||||
{
|
||||
Histogram* h = nullptr;
|
||||
if (NS_FAILED(GetHistogram(key, &h))) {
|
||||
if (NS_FAILED(GetHistogram(key, &h, subsession))) {
|
||||
return nullptr;
|
||||
}
|
||||
return h;
|
||||
@@ -3464,9 +3671,34 @@ KeyedHistogram::ClearHistogramEnumerator(KeyedHistogramEntry* entry, void*)
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
KeyedHistogram::Clear()
|
||||
nsresult
|
||||
KeyedHistogram::Add(const nsCString& key, uint32_t sample)
|
||||
{
|
||||
if (!TelemetryImpl::CanRecordExtended()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Histogram* histogram = GetHistogram(key, false);
|
||||
Histogram* subsession = GetHistogram(key, true);
|
||||
MOZ_ASSERT(histogram && subsession);
|
||||
if (!histogram || !subsession) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
histogram->Add(sample);
|
||||
subsession->Add(sample);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
KeyedHistogram::Clear(bool onlySubsession)
|
||||
{
|
||||
mSubsessionMap.EnumerateEntries(&KeyedHistogram::ClearHistogramEnumerator, nullptr);
|
||||
mSubsessionMap.Clear();
|
||||
if (onlySubsession) {
|
||||
return;
|
||||
}
|
||||
|
||||
mHistogramMap.EnumerateEntries(&KeyedHistogram::ClearHistogramEnumerator, nullptr);
|
||||
mHistogramMap.Clear();
|
||||
}
|
||||
@@ -3532,11 +3764,17 @@ KeyedHistogram::ReflectKeyedHistogram(KeyedHistogramEntry* entry, JSContext* cx,
|
||||
}
|
||||
|
||||
nsresult
|
||||
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj)
|
||||
KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
bool subsession, bool clearSubsession)
|
||||
{
|
||||
if (!mHistogramMap.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
|
||||
KeyedHistogramMapType& map = subsession ? mSubsessionMap : mHistogramMap;
|
||||
if (!map.ReflectIntoJS(&KeyedHistogram::ReflectKeyedHistogram, cx, obj)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (subsession && clearSubsession) {
|
||||
Clear(true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -174,11 +174,15 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates whether Telemetry recording is turned on. This is intended
|
||||
* to guard calls to Accumulate when the statistic being recorded is
|
||||
* expensive to compute.
|
||||
* Indicates whether Telemetry base data recording is turned on. Added for future uses.
|
||||
*/
|
||||
bool CanRecord();
|
||||
bool CanRecordBase();
|
||||
|
||||
/**
|
||||
* Indicates whether Telemetry extended data recording is turned on. This is intended
|
||||
* to guard calls to Accumulate when the statistic being recorded is expensive to compute.
|
||||
*/
|
||||
bool CanRecordExtended();
|
||||
|
||||
/**
|
||||
* Records slow SQL statements for Telemetry reporting.
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"TelemetryEnvironment",
|
||||
];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
const LOGGER_NAME = "Toolkit.Telemetry";
|
||||
|
||||
this.TelemetryEnvironment = {
|
||||
_shutdown: true,
|
||||
|
||||
// A map of (sync) listeners that will be called on environment changes.
|
||||
_changeListeners: new Map(),
|
||||
// Async task for collecting the environment data.
|
||||
_collectTask: null,
|
||||
_doNotify: false,
|
||||
|
||||
/**
|
||||
* Initialize TelemetryEnvironment.
|
||||
*/
|
||||
init: function () {
|
||||
if (!this._shutdown) {
|
||||
this._log.error("init - Already initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
this._configureLog();
|
||||
this._log.trace("init");
|
||||
this._shutdown = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shutdown TelemetryEnvironment.
|
||||
* @return Promise<> that is resolved when shutdown is finished.
|
||||
*/
|
||||
shutdown: Task.async(function* () {
|
||||
if (this._shutdown) {
|
||||
if (this._log) {
|
||||
this._log.error("shutdown - Already shut down");
|
||||
} else {
|
||||
Cu.reportError("TelemetryEnvironment.shutdown - Already shut down");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._log.trace("shutdown");
|
||||
this._shutdown = true;
|
||||
this._changeListeners.clear();
|
||||
yield this._collectTask;
|
||||
}),
|
||||
|
||||
_configureLog: function () {
|
||||
if (this._log) {
|
||||
return;
|
||||
}
|
||||
this._log = Log.repository.getLoggerWithMessagePrefix(
|
||||
LOGGER_NAME, "TelemetryEnvironment::");
|
||||
},
|
||||
|
||||
/**
|
||||
* Register a listener for environment changes.
|
||||
* It's fine to call this on an unitialized TelemetryEnvironment.
|
||||
* @param name The name of the listener - good for debugging purposes.
|
||||
* @param listener A JS callback function.
|
||||
*/
|
||||
registerChangeListener: function (name, listener) {
|
||||
this._configureLog();
|
||||
this._log.trace("registerChangeListener for " + name);
|
||||
if (this._shutdown) {
|
||||
this._log.warn("registerChangeListener - already shutdown")
|
||||
return;
|
||||
}
|
||||
this._changeListeners.set(name, listener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister from listening to environment changes.
|
||||
* It's fine to call this on an unitialized TelemetryEnvironment.
|
||||
* @param name The name of the listener to remove.
|
||||
*/
|
||||
unregisterChangeListener: function (name) {
|
||||
this._configureLog();
|
||||
this._log.trace("unregisterChangeListener for " + name);
|
||||
if (this._shutdown) {
|
||||
this._log.warn("registerChangeListener - already shutdown")
|
||||
return;
|
||||
}
|
||||
this._changeListeners.delete(name);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the environment data in object form.
|
||||
* @return Promise<Object> Resolved with the data on success, otherwise rejected.
|
||||
*/
|
||||
getEnvironmentData: function() {
|
||||
if (this._shutdown) {
|
||||
this._log.error("getEnvironmentData - Already shut down");
|
||||
return Promise.reject("Already shutdown");
|
||||
}
|
||||
|
||||
this._log.trace("getEnvironmentData");
|
||||
if (this._collectTask) {
|
||||
return this._collectTask;
|
||||
}
|
||||
|
||||
this._collectTask = this._doGetEnvironmentData();
|
||||
let clear = () => this._collectTask = null;
|
||||
this._collectTask.then(clear, clear);
|
||||
return this._collectTask;
|
||||
},
|
||||
|
||||
_doGetEnvironmentData: Task.async(function* () {
|
||||
this._log.trace("getEnvironmentData");
|
||||
return {};
|
||||
}),
|
||||
|
||||
_onEnvironmentChange: function (what) {
|
||||
this._log.trace("_onEnvironmentChange for " + what);
|
||||
if (this._shutdown) {
|
||||
this._log.trace("_onEnvironmentChange - Already shut down.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (let [name, listener] of this._changeListeners) {
|
||||
try {
|
||||
this._log.debug("_onEnvironmentChange - calling " + name);
|
||||
listener();
|
||||
} catch (e) {
|
||||
this._log.warning("_onEnvironmentChange - listener " + name + " caught error", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -244,13 +244,9 @@ this.TelemetryFile = {
|
||||
*
|
||||
* @return {iterator}
|
||||
*/
|
||||
popPendingPings: function*(reason) {
|
||||
popPendingPings: function*() {
|
||||
while (pendingPings.length > 0) {
|
||||
let data = pendingPings.pop();
|
||||
// Send persisted pings to the test URL too.
|
||||
if (reason == "test-ping") {
|
||||
data.reason = reason;
|
||||
}
|
||||
yield data;
|
||||
}
|
||||
},
|
||||
@@ -263,7 +259,7 @@ this.TelemetryFile = {
|
||||
|
||||
///// Utility functions
|
||||
function pingFilePath(ping) {
|
||||
return OS.Path.join(TelemetryFile.pingDirectoryPath, ping.slug);
|
||||
return OS.Path.join(TelemetryFile.pingDirectoryPath, ping.id);
|
||||
}
|
||||
|
||||
function getPingDirectory() {
|
||||
|
||||
@@ -30,10 +30,14 @@ const PREF_LOG_DUMP = PREF_BRANCH_LOG + "dump";
|
||||
const PREF_CACHED_CLIENTID = PREF_BRANCH + "cachedClientID"
|
||||
const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
|
||||
|
||||
const PING_FORMAT_VERSION = 2;
|
||||
|
||||
// Delay before intializing telemetry (ms)
|
||||
const TELEMETRY_DELAY = 60000;
|
||||
// Delay before initializing telemetry if we're testing (ms)
|
||||
const TELEMETRY_TEST_DELAY = 100;
|
||||
// The number of days to keep pings serialised on the disk in case of failures.
|
||||
const DEFAULT_RETENTION_DAYS = 14;
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
|
||||
"@mozilla.org/base/telemetry;1",
|
||||
@@ -46,6 +50,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "TelemetryLog",
|
||||
"resource://gre/modules/TelemetryLog.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ThirdPartyCookieProbe",
|
||||
"resource://gre/modules/ThirdPartyCookieProbe.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
|
||||
"resource://gre/modules/TelemetryEnvironment.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
|
||||
"resource://gre/modules/UpdateChannel.jsm");
|
||||
|
||||
/**
|
||||
* Setup Telemetry logging. This function also gets called when loggin related
|
||||
@@ -108,6 +116,14 @@ this.TelemetryPing = Object.freeze({
|
||||
Impl._clientID = null;
|
||||
return this.setup();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Used only for testing purposes.
|
||||
*/
|
||||
shutdown: function() {
|
||||
return Impl.shutdown(true);
|
||||
},
|
||||
/**
|
||||
* Used only for testing purposes.
|
||||
*/
|
||||
@@ -131,9 +147,105 @@ this.TelemetryPing = Object.freeze({
|
||||
|
||||
/**
|
||||
* Send payloads to the server.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} [aOptions] Options object.
|
||||
* @param {Number} [aOptions.retentionDays=14] The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} [aOptions.addClientId=false] true if the ping should contain the client
|
||||
* id, false otherwise.
|
||||
* @param {Boolean} [aOptions.addEnvironment=false] true if the ping should contain the
|
||||
* environment data.
|
||||
* @returns {Promise} A promise that resolves when the ping is sent.
|
||||
*/
|
||||
send: function(aReason, aPingPayload) {
|
||||
return Impl.send(aReason, aPingPayload);
|
||||
send: function(aType, aPayload, aOptions = {}) {
|
||||
let options = aOptions;
|
||||
options.retentionDays = aOptions.retentionDays || DEFAULT_RETENTION_DAYS;
|
||||
options.addClientId = aOptions.addClientId || false;
|
||||
options.addEnvironment = aOptions.addEnvironment || false;
|
||||
|
||||
return Impl.send(aType, aPayload, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the ping to the pending ping list and save all pending pings.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} [aOptions] Options object.
|
||||
* @param {Number} [aOptions.retentionDays=14] The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} [aOptions.addClientId=false] true if the ping should contain the client
|
||||
* id, false otherwise.
|
||||
* @param {Boolean} [aOptions.addEnvironment=false] true if the ping should contain the
|
||||
* environment data.
|
||||
* @returns {Promise} A promise that resolves when the pings are saved.
|
||||
*/
|
||||
savePendingPings: function(aType, aPayload, aOptions = {}) {
|
||||
let options = aOptions;
|
||||
options.retentionDays = aOptions.retentionDays || DEFAULT_RETENTION_DAYS;
|
||||
options.addClientId = aOptions.addClientId || false;
|
||||
options.addEnvironment = aOptions.addEnvironment || false;
|
||||
|
||||
return Impl.savePendingPings(aType, aPayload, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Save a ping to disk.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} [aOptions] Options object.
|
||||
* @param {Number} [aOptions.retentionDays=14] The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} [aOptions.addClientId=false] true if the ping should contain the client
|
||||
* id, false otherwise.
|
||||
* @param {Boolean} [aOptions.addEnvironment=false] true if the ping should contain the
|
||||
* environment data.
|
||||
* @param {Boolean} [aOptions.overwrite=false] true overwrites a ping with the same name,
|
||||
* if found.
|
||||
*
|
||||
* @returns {Promise} A promise that resolves when the ping is saved to disk.
|
||||
*/
|
||||
savePing: function(aType, aPayload, aOptions = {}) {
|
||||
let options = aOptions;
|
||||
options.retentionDays = aOptions.retentionDays || DEFAULT_RETENTION_DAYS;
|
||||
options.addClientId = aOptions.addClientId || false;
|
||||
options.addEnvironment = aOptions.addEnvironment || false;
|
||||
options.overwrite = aOptions.overwrite || false;
|
||||
|
||||
return Impl.savePing(aType, aPayload, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Only used for testing. Saves a ping to disk and return the ping id once done.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} [aOptions] Options object.
|
||||
* @param {Number} [aOptions.retentionDays=14] The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} [aOptions.addClientId=false] true if the ping should contain the client
|
||||
* id, false otherwise.
|
||||
* @param {Boolean} [aOptions.addEnvironment=false] true if the ping should contain the
|
||||
* environment data.
|
||||
* @param {Boolean} [aOptions.overwrite=false] true overwrites a ping with the same name,
|
||||
* if found.
|
||||
* @param {String} [aOptions.filePath] The path to save the ping to. Will save to default
|
||||
* ping location if not provided.
|
||||
*
|
||||
* @returns {Promise<Integer>} A promise that resolves with the ping id when the ping is
|
||||
* saved to disk.
|
||||
*/
|
||||
testSavePingToFile: function(aType, aPayload, aOptions = {}) {
|
||||
let options = aOptions;
|
||||
options.retentionDays = aOptions.retentionDays || DEFAULT_RETENTION_DAYS;
|
||||
options.addClientId = aOptions.addClientId || false;
|
||||
options.addEnvironment = aOptions.addEnvironment || false;
|
||||
options.overwrite = aOptions.overwrite || false;
|
||||
|
||||
return Impl.testSavePingToFile(aType, aPayload, options);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -144,23 +256,109 @@ this.TelemetryPing = Object.freeze({
|
||||
get clientID() {
|
||||
return Impl.clientID;
|
||||
},
|
||||
|
||||
/**
|
||||
* The AsyncShutdown.Barrier to synchronize with TelemetryPing shutdown.
|
||||
*/
|
||||
get shutdown() {
|
||||
return Impl._shutdownBarrier.client;
|
||||
},
|
||||
});
|
||||
|
||||
let Impl = {
|
||||
_initialized: false,
|
||||
_initStarted: false, // Whether we started setting up TelemetryPing.
|
||||
_log: null,
|
||||
_prevValues: {},
|
||||
// The previous build ID, if this is the first run with a new build.
|
||||
// Undefined if this is not the first run, or the previous build ID is unknown.
|
||||
_previousBuildID: undefined,
|
||||
_clientID: null,
|
||||
// A task performing delayed initialization
|
||||
_delayedInitTask: null,
|
||||
|
||||
popPayloads: function popPayloads(reason, externalPayload) {
|
||||
_shutdownBarrier: new AsyncShutdown.Barrier("TelemetryPing: Waiting for clients."),
|
||||
|
||||
/**
|
||||
* Get the data for the "application" section of the ping.
|
||||
*/
|
||||
_getApplicationSection: function() {
|
||||
// Querying architecture and update channel can throw. Make sure to recover and null
|
||||
// those fields.
|
||||
let arch = null;
|
||||
try {
|
||||
arch = Services.sysinfo.get("arch");
|
||||
} catch (e) {
|
||||
this._log.trace("assemblePing - Unable to get system architecture.", e);
|
||||
}
|
||||
|
||||
let updateChannel = null;
|
||||
try {
|
||||
updateChannel = UpdateChannel.get();
|
||||
} catch (e) {
|
||||
this._log.trace("assemblePing - Unable to get update channel.", e);
|
||||
}
|
||||
|
||||
return {
|
||||
architecture: arch,
|
||||
buildId: Services.appinfo.appBuildID,
|
||||
name: Services.appinfo.name,
|
||||
version: Services.appinfo.version,
|
||||
vendor: Services.appinfo.vendor,
|
||||
platformVersion: Services.appinfo.platformVersion,
|
||||
xpcomAbi: Services.appinfo.XPCOMABI,
|
||||
channel: updateChannel,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Assemble a complete ping following the common ping format specification.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} aOptions Options object.
|
||||
* @param {Boolean} aOptions.addClientId true if the ping should contain the client
|
||||
* id, false otherwise.
|
||||
* @param {Boolean} aOptions.addEnvironment true if the ping should contain the
|
||||
* environment data.
|
||||
*
|
||||
* @returns Promise<Object> A promise that resolves when the ping is completely assembled.
|
||||
*/
|
||||
assemblePing: function assemblePing(aType, aPayload, aOptions = {}) {
|
||||
this._log.trace("assemblePing - Type " + aType + ", Server " + this._server +
|
||||
", aOptions " + JSON.stringify(aOptions));
|
||||
|
||||
// Fill the common ping fields.
|
||||
let pingData = {
|
||||
type: aType,
|
||||
id: generateUUID(),
|
||||
creationDate: (new Date()).toISOString(),
|
||||
version: PING_FORMAT_VERSION,
|
||||
application: this._getApplicationSection(),
|
||||
payload: aPayload,
|
||||
};
|
||||
|
||||
if (aOptions.addClientId) {
|
||||
pingData.clientId = this._clientID;
|
||||
}
|
||||
|
||||
if (aOptions.addEnvironment) {
|
||||
return TelemetryEnvironment.getEnvironmentData().then(environment => {
|
||||
pingData.environment = environment;
|
||||
return pingData;
|
||||
},
|
||||
error => {
|
||||
this._log.error("assemblePing - Rejection", error);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(pingData);
|
||||
},
|
||||
|
||||
popPayloads: function popPayloads() {
|
||||
this._log.trace("popPayloads");
|
||||
function payloadIter() {
|
||||
if (externalPayload && reason != "overdue-flush") {
|
||||
yield externalPayload;
|
||||
}
|
||||
let iterator = TelemetryFile.popPendingPings(reason);
|
||||
let iterator = TelemetryFile.popPendingPings();
|
||||
for (let data of iterator) {
|
||||
yield data;
|
||||
}
|
||||
@@ -178,29 +376,142 @@ let Impl = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Send data to the server. Record success/send-time in histograms
|
||||
* Build a complete ping and send data to the server. Record success/send-time in
|
||||
* histograms.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} aOptions Options object.
|
||||
* @param {Number} aOptions.retentionDays The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} aOptions.addClientId true if the ping should contain the client id,
|
||||
* false otherwise.
|
||||
* @param {Boolean} aOptions.addEnvironment true if the ping should contain the
|
||||
* environment data.
|
||||
*
|
||||
* @returns {Promise} A promise that resolves when the ping is sent.
|
||||
*/
|
||||
send: function send(reason, aPayload) {
|
||||
this._log.trace("send - Reason " + reason + ", Server " + this._server);
|
||||
return this.sendPingsFromIterator(this._server, reason,
|
||||
Iterator(this.popPayloads(reason, aPayload)));
|
||||
send: function send(aType, aPayload, aOptions) {
|
||||
this._log.trace("send - Type " + aType + ", Server " + this._server +
|
||||
", aOptions " + JSON.stringify(aOptions));
|
||||
|
||||
return this.assemblePing(aType, aPayload, aOptions)
|
||||
.then(pingData => {
|
||||
// Once ping is assembled, send it along with the persisted ping in the backlog.
|
||||
let p = [
|
||||
// Persist the ping if sending it fails.
|
||||
this.doPing(pingData, false)
|
||||
.catch(() => TelemetryFile.savePing(pingData, true)),
|
||||
this.sendPersistedPings(),
|
||||
];
|
||||
return Promise.all(p);
|
||||
},
|
||||
error => this._log.error("send - Rejection", error));
|
||||
},
|
||||
|
||||
sendPingsFromIterator: function sendPingsFromIterator(server, reason, i) {
|
||||
let p = [data for (data in i)].map((data) =>
|
||||
this.doPing(server, data).then(null, () => TelemetryFile.savePing(data, true)));
|
||||
|
||||
/**
|
||||
* Send the persisted pings to the server.
|
||||
*/
|
||||
sendPersistedPings: function sendPersistedPings() {
|
||||
this._log.trace("sendPersistedPings");
|
||||
let pingsIterator = Iterator(this.popPayloads());
|
||||
let p = [data for (data in pingsIterator)].map(data => this.doPing(data, true));
|
||||
return Promise.all(p);
|
||||
},
|
||||
|
||||
finishPingRequest: function finishPingRequest(success, startTime, ping) {
|
||||
/**
|
||||
* Saves all the pending pings, plus the passed one, to disk.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} aOptions Options object.
|
||||
* @param {Number} aOptions.retentionDays The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} aOptions.addClientId true if the ping should contain the client id,
|
||||
* false otherwise.
|
||||
* @param {Boolean} aOptions.addEnvironment true if the ping should contain the
|
||||
* environment data.
|
||||
*
|
||||
* @returns {Promise} A promise that resolves when all the pings are saved to disk.
|
||||
*/
|
||||
savePendingPings: function savePendingPings(aType, aPayload, aOptions) {
|
||||
this._log.trace("savePendingPings - Type " + aType + ", Server " + this._server +
|
||||
", aOptions " + JSON.stringify(aOptions));
|
||||
|
||||
return this.assemblePing(aType, aPayload, aOptions)
|
||||
.then(pingData => TelemetryFile.savePendingPings(pingData),
|
||||
error => this._log.error("savePendingPings - Rejection", error));
|
||||
},
|
||||
|
||||
/**
|
||||
* Save a ping to disk.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} aOptions Options object.
|
||||
* @param {Number} aOptions.retentionDays The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} aOptions.addClientId true if the ping should contain the client id,
|
||||
* false otherwise.
|
||||
* @param {Boolean} aOptions.addEnvironment true if the ping should contain the
|
||||
* environment data.
|
||||
* @param {Boolean} aOptions.overwrite true overwrites a ping with the same name, if found.
|
||||
*
|
||||
* @returns {Promise} A promise that resolves when the ping is saved to disk.
|
||||
*/
|
||||
savePing: function savePing(aType, aPayload, aOptions) {
|
||||
this._log.trace("savePing - Type " + aType + ", Server " + this._server +
|
||||
", aOptions " + JSON.stringify(aOptions));
|
||||
|
||||
return this.assemblePing(aType, aPayload, aOptions)
|
||||
.then(pingData => TelemetryFile.savePing(pingData, aOptions.overwrite),
|
||||
error => this._log.error("savePing - Rejection", error));
|
||||
},
|
||||
|
||||
/**
|
||||
* Save a ping to disk and return the ping id when done.
|
||||
*
|
||||
* @param {String} aType The type of the ping.
|
||||
* @param {Object} aPayload The actual data payload for the ping.
|
||||
* @param {Object} aOptions Options object.
|
||||
* @param {Number} aOptions.retentionDays The number of days to keep the ping on disk
|
||||
* if sending fails.
|
||||
* @param {Boolean} aOptions.addClientId true if the ping should contain the client id,
|
||||
* false otherwise.
|
||||
* @param {Boolean} aOptions.addEnvironment true if the ping should contain the
|
||||
* environment data.
|
||||
* @param {Boolean} aOptions.overwrite true overwrites a ping with the same name, if found.
|
||||
* @param {String} [aOptions.filePath] The path to save the ping to. Will save to default
|
||||
* ping location if not provided.
|
||||
*
|
||||
* @returns {Promise} A promise that resolves with the ping id when the ping is saved to
|
||||
* disk.
|
||||
*/
|
||||
testSavePingToFile: function testSavePingToFile(aType, aPayload, aOptions) {
|
||||
this._log.trace("testSavePingToFile - Type " + aType + ", Server " + this._server +
|
||||
", aOptions " + JSON.stringify(aOptions));
|
||||
return this.assemblePing(aType, aPayload, aOptions)
|
||||
.then(pingData => {
|
||||
if (aOptions.filePath) {
|
||||
return TelemetryFile.savePingToFile(pingData, aOptions.filePath, aOptions.overwrite)
|
||||
.then(() => { return pingData.id; });
|
||||
} else {
|
||||
return TelemetryFile.savePing(pingData, aOptions.overwrite)
|
||||
.then(() => { return pingData.id; });
|
||||
}
|
||||
}, error => this._log.error("testSavePing - Rejection", error));
|
||||
},
|
||||
|
||||
finishPingRequest: function finishPingRequest(success, startTime, ping, isPersisted) {
|
||||
this._log.trace("finishPingRequest - Success " + success + ", Persisted " + isPersisted);
|
||||
|
||||
let hping = Telemetry.getHistogramById("TELEMETRY_PING");
|
||||
let hsuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
|
||||
|
||||
hsuccess.add(success);
|
||||
hping.add(new Date() - startTime);
|
||||
|
||||
if (success) {
|
||||
if (success && isPersisted) {
|
||||
return TelemetryFile.cleanupPingFile(ping);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
@@ -208,23 +519,20 @@ let Impl = {
|
||||
},
|
||||
|
||||
submissionPath: function submissionPath(ping) {
|
||||
let slug;
|
||||
if (!ping) {
|
||||
slug = this._uuid;
|
||||
} else {
|
||||
let info = ping.payload.info;
|
||||
let pathComponents = [ping.slug, info.reason, info.appName,
|
||||
info.appVersion, info.appUpdateChannel,
|
||||
info.appBuildID];
|
||||
slug = pathComponents.join("/");
|
||||
}
|
||||
let app = ping.application;
|
||||
// We insert the Ping id in the URL to simplify server handling of duplicated
|
||||
// pings.
|
||||
let pathComponents = [ping.id, ping.type, app.name, app.version,
|
||||
app.channel, app.buildId];
|
||||
let slug = pathComponents.join("/");
|
||||
|
||||
return "/submit/telemetry/" + slug;
|
||||
},
|
||||
|
||||
doPing: function doPing(server, ping) {
|
||||
this._log.trace("doPing - Server " + server);
|
||||
doPing: function doPing(ping, isPersisted) {
|
||||
this._log.trace("doPing - Server " + this._server + ", Persisted " + isPersisted);
|
||||
let deferred = Promise.defer();
|
||||
let url = server + this.submissionPath(ping);
|
||||
let url = this._server + this.submissionPath(ping);
|
||||
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
request.mozBackgroundRequest = true;
|
||||
@@ -235,14 +543,22 @@ let Impl = {
|
||||
let startTime = new Date();
|
||||
|
||||
function handler(success) {
|
||||
let handleCompletion = event => {
|
||||
if (success) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject(event);
|
||||
}
|
||||
};
|
||||
|
||||
return function(event) {
|
||||
this.finishPingRequest(success, startTime, ping).then(() => {
|
||||
if (success) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject(event);
|
||||
}
|
||||
});
|
||||
this.finishPingRequest(success, startTime, ping, isPersisted)
|
||||
.then(() => handleCompletion(event),
|
||||
error => {
|
||||
this._log.error("doPing - Request Success " + success + ", Error " +
|
||||
error);
|
||||
handleCompletion(event);
|
||||
});
|
||||
};
|
||||
}
|
||||
request.addEventListener("error", handler(false).bind(this), false);
|
||||
@@ -252,7 +568,7 @@ let Impl = {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
let utf8Payload = converter.ConvertFromUnicode(JSON.stringify(ping.payload));
|
||||
let utf8Payload = converter.ConvertFromUnicode(JSON.stringify(ping));
|
||||
utf8Payload += converter.Finish();
|
||||
let payloadStream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
@@ -289,13 +605,22 @@ let Impl = {
|
||||
* Perform telemetry initialization for either chrome or content process.
|
||||
*/
|
||||
enableTelemetryRecording: function enableTelemetryRecording(testing) {
|
||||
// Enable base Telemetry recording, if needed.
|
||||
#if !defined(MOZ_WIDGET_ANDROID)
|
||||
Telemetry.canRecordBase =
|
||||
Preferences.get("datareporting.healthreport.service.enabled", false) ||
|
||||
Preferences.get("browser.selfsupport.enabled", false);
|
||||
#else
|
||||
// FHR recording is always "enabled" on Android (data upload is not).
|
||||
Telemetry.canRecordBase = true;
|
||||
#endif
|
||||
|
||||
#ifdef MOZILLA_OFFICIAL
|
||||
if (!Telemetry.canSend && !testing) {
|
||||
if (!Telemetry.isOfficialTelemetry && !testing) {
|
||||
// We can't send data; no point in initializing observers etc.
|
||||
// Only do this for official builds so that e.g. developer builds
|
||||
// still enable Telemetry based on prefs.
|
||||
Telemetry.canRecord = false;
|
||||
Telemetry.canRecordExtended = false;
|
||||
this._log.config("enableTelemetryRecording - Can't send data, disabling Telemetry recording.");
|
||||
return false;
|
||||
}
|
||||
@@ -303,10 +628,10 @@ let Impl = {
|
||||
|
||||
let enabled = Preferences.get(PREF_ENABLED, false);
|
||||
this._server = Preferences.get(PREF_SERVER, undefined);
|
||||
if (!enabled) {
|
||||
// Turn off local telemetry if telemetry is disabled.
|
||||
// This may change once about:telemetry is added.
|
||||
Telemetry.canRecord = false;
|
||||
if (!enabled || !Telemetry.canRecordBase) {
|
||||
// Turn off extended telemetry recording if disabled by preferences or if base/telemetry
|
||||
// telemetry recording is off.
|
||||
Telemetry.canRecordExtended = false;
|
||||
this._log.config("enableTelemetryRecording - Telemetry is disabled, turning off Telemetry recording.");
|
||||
return false;
|
||||
}
|
||||
@@ -316,14 +641,32 @@ let Impl = {
|
||||
|
||||
/**
|
||||
* Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry.
|
||||
*
|
||||
* This delayed initialization means TelemetryPing init can be in the following states:
|
||||
* 1) setupTelemetry was never called
|
||||
* or it was called and
|
||||
* 2) _delayedInitTask was scheduled, but didn't run yet.
|
||||
* 3) _delayedInitTask is currently running.
|
||||
* 4) _delayedInitTask finished running and is nulled out.
|
||||
*/
|
||||
setupTelemetry: function setupTelemetry(testing) {
|
||||
this._initStarted = true;
|
||||
if (testing && !this._log) {
|
||||
this._log = Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX);
|
||||
}
|
||||
|
||||
this._log.trace("setupTelemetry");
|
||||
|
||||
if (this._delayedInitTask) {
|
||||
this._log.error("setupTelemetry - init task already running");
|
||||
return this._delayedInitTask;
|
||||
}
|
||||
|
||||
if (this._initialized && !testing) {
|
||||
this._log.error("setupTelemetry - already initialized");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Initialize some probes that are kept in their own modules
|
||||
this._thirdPartyCookies = new ThirdPartyCookieProbe();
|
||||
this._thirdPartyCookies.init();
|
||||
@@ -343,42 +686,91 @@ let Impl = {
|
||||
// run various late initializers. Otherwise our gathered memory
|
||||
// footprint and other numbers would be too optimistic.
|
||||
let deferred = Promise.defer();
|
||||
let delayedTask = new DeferredTask(function* () {
|
||||
this._initialized = true;
|
||||
this._delayedInitTask = new DeferredTask(function* () {
|
||||
try {
|
||||
this._initialized = true;
|
||||
|
||||
yield TelemetryFile.loadSavedPings();
|
||||
// If we have any TelemetryPings lying around, we'll be aggressive
|
||||
// and try to send them all off ASAP.
|
||||
if (TelemetryFile.pingsOverdue > 0) {
|
||||
this._log.trace("setupChromeProcess - Sending " + TelemetryFile.pingsOverdue +
|
||||
" overdue pings now.");
|
||||
// It doesn't really matter what we pass to this.send as a reason,
|
||||
// since it's never sent to the server. All that this.send does with
|
||||
// the reason is check to make sure it's not a test-ping.
|
||||
yield this.send("overdue-flush");
|
||||
yield TelemetryEnvironment.init();
|
||||
|
||||
yield TelemetryFile.loadSavedPings();
|
||||
// If we have any TelemetryPings lying around, we'll be aggressive
|
||||
// and try to send them all off ASAP.
|
||||
if (TelemetryFile.pingsOverdue > 0) {
|
||||
this._log.trace("setupChromeProcess - Sending " + TelemetryFile.pingsOverdue +
|
||||
" overdue pings now.");
|
||||
// It doesn't really matter what we pass to this.send as a reason,
|
||||
// since it's never sent to the server. All that this.send does with
|
||||
// the reason is check to make sure it's not a test-ping.
|
||||
yield this.sendPersistedPings();
|
||||
}
|
||||
|
||||
if ("@mozilla.org/datareporting/service;1" in Cc) {
|
||||
let drs = Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject;
|
||||
this._clientID = yield drs.getClientID();
|
||||
// Update cached client id.
|
||||
Preferences.set(PREF_CACHED_CLIENTID, this._clientID);
|
||||
} else {
|
||||
// Nuke potentially cached client id.
|
||||
Preferences.reset(PREF_CACHED_CLIENTID);
|
||||
}
|
||||
|
||||
Telemetry.asyncFetchTelemetryData(function () {});
|
||||
deferred.resolve();
|
||||
} catch (e) {
|
||||
deferred.reject(e);
|
||||
} finally {
|
||||
this._delayedInitTask = null;
|
||||
}
|
||||
|
||||
if ("@mozilla.org/datareporting/service;1" in Cc) {
|
||||
let drs = Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject;
|
||||
this._clientID = yield drs.getClientID();
|
||||
// Update cached client id.
|
||||
Preferences.set(PREF_CACHED_CLIENTID, this._clientID);
|
||||
} else {
|
||||
// Nuke potentially cached client id.
|
||||
Preferences.reset(PREF_CACHED_CLIENTID);
|
||||
}
|
||||
|
||||
Telemetry.asyncFetchTelemetryData(function () {});
|
||||
deferred.resolve();
|
||||
|
||||
}.bind(this), testing ? TELEMETRY_TEST_DELAY : TELEMETRY_DELAY);
|
||||
|
||||
delayedTask.arm();
|
||||
AsyncShutdown.sendTelemetry.addBlocker("TelemetryPing: shutting down",
|
||||
() => this.shutdown(),
|
||||
() => this._getState());
|
||||
|
||||
this._delayedInitTask.arm();
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
this._log.trace("shutdown");
|
||||
|
||||
let cleanup = () => {
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
let reset = () => {
|
||||
this._initialized = false;
|
||||
this._initStarted = false;
|
||||
};
|
||||
return this._shutdownBarrier.wait().then(
|
||||
() => TelemetryEnvironment.shutdown().then(reset, reset));
|
||||
};
|
||||
|
||||
// We can be in one the following states here:
|
||||
// 1) setupTelemetry was never called
|
||||
// or it was called and
|
||||
// 2) _delayedInitTask was scheduled, but didn't run yet.
|
||||
// 3) _delayedInitTask is running now.
|
||||
// 4) _delayedInitTask finished running already.
|
||||
|
||||
// This handles 1).
|
||||
if (!this._initStarted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// This handles 4).
|
||||
if (!this._delayedInitTask) {
|
||||
// We already ran the delayed initialization.
|
||||
return cleanup();
|
||||
}
|
||||
|
||||
// This handles 2) and 3).
|
||||
this._delayedInitTask.disarm();
|
||||
return this._delayedInitTask.finalize().then(cleanup);
|
||||
},
|
||||
|
||||
/**
|
||||
* This observer drives telemetry.
|
||||
*/
|
||||
@@ -412,4 +804,27 @@ let Impl = {
|
||||
get clientID() {
|
||||
return this._clientID;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get an object describing the current state of this module for AsyncShutdown diagnostics.
|
||||
*/
|
||||
_getState: function() {
|
||||
return {
|
||||
initialized: this._initialized,
|
||||
initStarted: this._initStarted,
|
||||
haveDelayedInitTask: !!this._delayedInitTask,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* This tells TelemetryPing to uninitialize and save any pending pings.
|
||||
* @param testing Optional. If true, always saves the ping whether Telemetry
|
||||
* can send pings or not, which is used for testing.
|
||||
*/
|
||||
shutdown: function(testing = false) {
|
||||
this.uninstall();
|
||||
if (Telemetry.canSend || testing) {
|
||||
return this.savePendingPings();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,197 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_BackgroundHangTelemetry_h
|
||||
#define mozilla_BackgroundHangTelemetry_h
|
||||
|
||||
#include "mozilla/Array.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/HangAnnotations.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "prinrval.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace Telemetry {
|
||||
|
||||
static const size_t kTimeHistogramBuckets = 8 * sizeof(PRIntervalTime);
|
||||
|
||||
/* TimeHistogram is an efficient histogram that puts time durations into
|
||||
exponential (base 2) buckets; times are accepted in PRIntervalTime and
|
||||
stored in milliseconds. */
|
||||
class TimeHistogram : public mozilla::Array<uint32_t, kTimeHistogramBuckets>
|
||||
{
|
||||
public:
|
||||
TimeHistogram()
|
||||
{
|
||||
mozilla::PodArrayZero(*this);
|
||||
}
|
||||
// Get minimum (inclusive) range of bucket in milliseconds
|
||||
uint32_t GetBucketMin(size_t aBucket) const {
|
||||
MOZ_ASSERT(aBucket < ArrayLength(*this));
|
||||
return (1u << aBucket) & ~1u; // Bucket 0 starts at 0, not 1
|
||||
}
|
||||
// Get maximum (inclusive) range of bucket in milliseconds
|
||||
uint32_t GetBucketMax(size_t aBucket) const {
|
||||
MOZ_ASSERT(aBucket < ArrayLength(*this));
|
||||
return (1u << (aBucket + 1u)) - 1u;
|
||||
}
|
||||
void Add(PRIntervalTime aTime);
|
||||
};
|
||||
|
||||
/* HangStack stores an array of const char pointers,
|
||||
with optional internal storage for strings. */
|
||||
class HangStack : public mozilla::Vector<const char*, 8>
|
||||
{
|
||||
private:
|
||||
typedef mozilla::Vector<const char*, 8> Base;
|
||||
|
||||
// Stack entries can either be a static const char*
|
||||
// or a pointer to within this buffer.
|
||||
mozilla::Vector<char, 0> mBuffer;
|
||||
|
||||
public:
|
||||
HangStack() { }
|
||||
|
||||
HangStack(HangStack&& aOther)
|
||||
: Base(mozilla::Move(aOther))
|
||||
, mBuffer(mozilla::Move(aOther.mBuffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const HangStack& aOther) const {
|
||||
for (size_t i = 0; i < length(); i++) {
|
||||
if (!IsSameAsEntry(operator[](i), aOther[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const HangStack& aOther) const {
|
||||
return !operator==(aOther);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Base::clear();
|
||||
mBuffer.clear();
|
||||
}
|
||||
|
||||
bool IsInBuffer(const char* aEntry) const {
|
||||
return aEntry >= mBuffer.begin() && aEntry < mBuffer.end();
|
||||
}
|
||||
|
||||
bool IsSameAsEntry(const char* aEntry, const char* aOther) const {
|
||||
// If the entry came from the buffer, we need to compare its content;
|
||||
// otherwise we only need to compare its pointer.
|
||||
return IsInBuffer(aEntry) ? !strcmp(aEntry, aOther) : (aEntry == aOther);
|
||||
}
|
||||
|
||||
size_t AvailableBufferSize() const {
|
||||
return mBuffer.capacity() - mBuffer.length();
|
||||
}
|
||||
|
||||
bool EnsureBufferCapacity(size_t aCapacity) {
|
||||
// aCapacity is the minimal capacity and Vector may make the actual
|
||||
// capacity larger, in which case we want to use up all the space.
|
||||
return mBuffer.reserve(aCapacity) &&
|
||||
mBuffer.reserve(mBuffer.capacity());
|
||||
}
|
||||
|
||||
const char* InfallibleAppendViaBuffer(const char* aText, size_t aLength);
|
||||
const char* AppendViaBuffer(const char* aText, size_t aLength);
|
||||
};
|
||||
|
||||
/* A hang histogram consists of a stack associated with the
|
||||
hang, along with a time histogram of the hang times. */
|
||||
class HangHistogram : public TimeHistogram
|
||||
{
|
||||
private:
|
||||
static uint32_t GetHash(const HangStack& aStack);
|
||||
|
||||
HangStack mStack;
|
||||
// Native stack that corresponds to the pseudostack in mStack
|
||||
HangStack mNativeStack;
|
||||
// Use a hash to speed comparisons
|
||||
const uint32_t mHash;
|
||||
// Annotations attributed to this stack
|
||||
HangMonitor::HangAnnotationsVector mAnnotations;
|
||||
|
||||
public:
|
||||
explicit HangHistogram(HangStack&& aStack)
|
||||
: mStack(mozilla::Move(aStack))
|
||||
, mHash(GetHash(mStack))
|
||||
{
|
||||
}
|
||||
HangHistogram(HangHistogram&& aOther)
|
||||
: TimeHistogram(mozilla::Move(aOther))
|
||||
, mStack(mozilla::Move(aOther.mStack))
|
||||
, mNativeStack(mozilla::Move(aOther.mNativeStack))
|
||||
, mHash(mozilla::Move(aOther.mHash))
|
||||
, mAnnotations(mozilla::Move(aOther.mAnnotations))
|
||||
{
|
||||
}
|
||||
bool operator==(const HangHistogram& aOther) const;
|
||||
bool operator!=(const HangHistogram& aOther) const
|
||||
{
|
||||
return !operator==(aOther);
|
||||
}
|
||||
const HangStack& GetStack() const {
|
||||
return mStack;
|
||||
}
|
||||
HangStack& GetNativeStack() {
|
||||
return mNativeStack;
|
||||
}
|
||||
const HangStack& GetNativeStack() const {
|
||||
return mNativeStack;
|
||||
}
|
||||
const HangMonitor::HangAnnotationsVector& GetAnnotations() const {
|
||||
return mAnnotations;
|
||||
}
|
||||
void Add(PRIntervalTime aTime, HangMonitor::HangAnnotationsPtr aAnnotations) {
|
||||
TimeHistogram::Add(aTime);
|
||||
if (aAnnotations) {
|
||||
mAnnotations.append(Move(aAnnotations));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Thread hang stats consist of
|
||||
- thread name
|
||||
- time histogram of all task run times
|
||||
- hang histograms of individual hangs
|
||||
- annotations for each hang
|
||||
*/
|
||||
class ThreadHangStats
|
||||
{
|
||||
private:
|
||||
nsAutoCString mName;
|
||||
|
||||
public:
|
||||
TimeHistogram mActivity;
|
||||
mozilla::Vector<HangHistogram, 4> mHangs;
|
||||
|
||||
explicit ThreadHangStats(const char* aName)
|
||||
: mName(aName)
|
||||
{
|
||||
}
|
||||
ThreadHangStats(ThreadHangStats&& aOther)
|
||||
: mName(mozilla::Move(aOther.mName))
|
||||
, mActivity(mozilla::Move(aOther.mActivity))
|
||||
, mHangs(mozilla::Move(aOther.mHangs))
|
||||
{
|
||||
}
|
||||
const char* GetName() const {
|
||||
return mName.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Telemetry
|
||||
} // namespace mozilla
|
||||
#endif // mozilla_BackgroundHangTelemetry_h
|
||||
@@ -23,7 +23,7 @@ Structure::
|
||||
reason: <string>, // what triggered this ping: "saved-session", "environment-change", "shutdown", ...
|
||||
revision: <string>, // the Histograms.json revision
|
||||
timezoneOffset: <number>, // time-zone offset from UTC, in minutes, for the current locale
|
||||
previousBuildId: <string>,
|
||||
previousBuildId: <string>, // null if this is the first run, or the previous build ID is unknown
|
||||
|
||||
sessionId: <uuid>, // random session id, shared by subsessions
|
||||
subsessionId: <uuid>, // random subsession id
|
||||
@@ -34,7 +34,7 @@ Structure::
|
||||
profileSubsessionCounter: <number>, // the running no. of all subsessions for the whole profile life time
|
||||
|
||||
sessionStartDate: <ISO date>, // daily precision
|
||||
subsessionStartDate: <ISO date>, // daily precision
|
||||
subsessionStartDate: <ISO date>, // daily precision, ISO date in local time
|
||||
subsessionLength: <number>, // the subsession length in seconds
|
||||
},
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ EXTRA_COMPONENTS += [
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'TelemetryEnvironment.jsm',
|
||||
'TelemetryFile.jsm',
|
||||
'TelemetryLog.jsm',
|
||||
'TelemetryStopwatch.jsm',
|
||||
|
||||
@@ -12,7 +12,7 @@ interface nsIFetchTelemetryDataCallback : nsISupports
|
||||
void complete();
|
||||
};
|
||||
|
||||
[scriptable, uuid(c782cf96-7f44-45ac-8d76-e0d1b174e562)]
|
||||
[scriptable, uuid(68e82b42-cad2-411f-857b-b64ea9377929)]
|
||||
interface nsITelemetry : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ interface nsITelemetry : nsISupports
|
||||
const unsigned long DATASET_RELEASE_CHANNEL_OPTIN = 1;
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* An object containing a snapshot from all of the currently registered histograms.
|
||||
* { name1: {data1}, name2:{data2}...}
|
||||
* where data is consists of the following properties:
|
||||
@@ -55,6 +55,14 @@ interface nsITelemetry : nsISupports
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval histogramSnapshots;
|
||||
|
||||
/**
|
||||
* Get a snapshot of the internally duplicated subsession histograms.
|
||||
* @param clear Whether to clear out the subsession histograms after snapshotting.
|
||||
* @return An object as histogramSnapshots, except this contains the internally duplicated histograms for subsession telemetry.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
jsval snapshotSubsessionHistograms([optional] in boolean clear);
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, that the last session took
|
||||
* to shutdown. Reads as 0 to indicate failure.
|
||||
@@ -226,14 +234,31 @@ interface nsITelemetry : nsISupports
|
||||
jsval getKeyedHistogramById(in ACString id);
|
||||
|
||||
/**
|
||||
* Set this to false to disable gathering of telemetry statistics.
|
||||
* A flag indicating if Telemetry can record base data (FHR data). This is true if the
|
||||
* FHR data reporting service or self-support are enabled.
|
||||
*
|
||||
* In the unlikely event that adding a new base probe is needed, please check the data
|
||||
* collection wiki at https://wiki.mozilla.org/Firefox/Data_Collection and talk to the
|
||||
* Telemetry team.
|
||||
*/
|
||||
attribute boolean canRecord;
|
||||
attribute boolean canRecordBase;
|
||||
|
||||
/**
|
||||
* A flag indicating whether Telemetry can submit official results.
|
||||
* A flag indicating if Telemetry is allowed to record extended data. Returns false if
|
||||
* the user hasn't opted into "extended Telemetry" on the Release channel, when the
|
||||
* user has explicitly opted out of Telemetry on Nightly/Aurora/Beta or if manually
|
||||
* set to false during tests.
|
||||
*
|
||||
* Set this to false in tests to disable gathering of extended telemetry statistics.
|
||||
*/
|
||||
readonly attribute boolean canSend;
|
||||
attribute boolean canRecordExtended;
|
||||
|
||||
/**
|
||||
* A flag indicating whether Telemetry can submit official results (for base or extended
|
||||
* data). This is true on official builds with built in support for Mozilla Telemetry
|
||||
* reporting.
|
||||
*/
|
||||
readonly attribute boolean isOfficialTelemetry;
|
||||
|
||||
/** Addon telemetry hooks */
|
||||
|
||||
|
||||
@@ -58,7 +58,17 @@ function createAppInfo(id, name, version, platformVersion) {
|
||||
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
|
||||
}
|
||||
|
||||
// Fake setTimeout and clearTimeout for the daily timer in tests for controllable behavior.
|
||||
function fakeDailyTimers(set, clear) {
|
||||
let session = Components.utils.import("resource://gre/modules/TelemetrySession.jsm");
|
||||
session.Policy.setDailyTimeout = set;
|
||||
session.Policy.clearDailyTimeout = clear;
|
||||
}
|
||||
|
||||
// Set logging preferences for all the tests.
|
||||
Services.prefs.setCharPref("toolkit.telemetry.log.level", "Trace");
|
||||
Services.prefs.setBoolPref("toolkit.telemetry.log.dump", true);
|
||||
TelemetryPing.initLogging();
|
||||
|
||||
// Avoid timers interrupting test behavior.
|
||||
fakeDailyTimers(() => {}, () => {});
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
do_get_profile();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function isRejected(promise) {
|
||||
return new Promise((resolve, reject) => {
|
||||
promise.then(() => resolve(false), () => resolve(true));
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_initAndShutdown() {
|
||||
// Check that init and shutdown work properly.
|
||||
TelemetryEnvironment.init();
|
||||
yield TelemetryEnvironment.shutdown();
|
||||
TelemetryEnvironment.init();
|
||||
yield TelemetryEnvironment.shutdown();
|
||||
|
||||
// A double init should be silently handled.
|
||||
TelemetryEnvironment.init();
|
||||
TelemetryEnvironment.init();
|
||||
|
||||
// getEnvironmentData should return a sane result.
|
||||
let data = yield TelemetryEnvironment.getEnvironmentData();
|
||||
Assert.ok(!!data);
|
||||
|
||||
// The change listener registration should silently fail after shutdown.
|
||||
yield TelemetryEnvironment.shutdown();
|
||||
TelemetryEnvironment.registerChangeListener("foo", () => {});
|
||||
TelemetryEnvironment.unregisterChangeListener("foo");
|
||||
|
||||
// Shutting down again should be ignored.
|
||||
yield TelemetryEnvironment.shutdown();
|
||||
|
||||
// Getting the environment data should reject after shutdown.
|
||||
Assert.ok(yield isRejected(TelemetryEnvironment.getEnvironmentData()));
|
||||
});
|
||||
|
||||
add_task(function* test_changeNotify() {
|
||||
TelemetryEnvironment.init();
|
||||
|
||||
// Register some listeners
|
||||
let results = new Array(4).fill(false);
|
||||
for (let i=0; i<results.length; ++i) {
|
||||
let k = i;
|
||||
TelemetryEnvironment.registerChangeListener("test"+k, () => results[k] = true);
|
||||
}
|
||||
// Trigger environment change notifications.
|
||||
// TODO: test with proper environment changes, not directly.
|
||||
TelemetryEnvironment._onEnvironmentChange("foo");
|
||||
Assert.ok(results.every(val => val), "All change listeners should have been notified.");
|
||||
results.fill(false);
|
||||
TelemetryEnvironment._onEnvironmentChange("bar");
|
||||
Assert.ok(results.every(val => val), "All change listeners should have been notified.");
|
||||
|
||||
// Unregister listeners
|
||||
for (let i=0; i<4; ++i) {
|
||||
TelemetryEnvironment.unregisterChangeListener("test"+i);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
do_test_finished();
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
@@ -168,7 +169,6 @@ function checkPayloadInfo(payload, reason) {
|
||||
// get rid of the non-deterministic field
|
||||
const expected_info = {
|
||||
OS: "XPCShell",
|
||||
appID: "xpcshell@tests.mozilla.org",
|
||||
appVersion: "1",
|
||||
appName: "XPCShell",
|
||||
appBuildID: "2007010101",
|
||||
@@ -182,7 +182,6 @@ function checkPayloadInfo(payload, reason) {
|
||||
|
||||
do_check_eq(payload.info.reason, reason);
|
||||
do_check_true("appUpdateChannel" in payload.info);
|
||||
do_check_true("locale" in payload.info);
|
||||
do_check_true("revision" in payload.info);
|
||||
if (Services.appinfo.isOfficial) {
|
||||
do_check_true(payload.info.revision.startsWith("http"));
|
||||
@@ -194,24 +193,6 @@ function checkPayloadInfo(payload, reason) {
|
||||
do_check_neq(payload.clientID, null);
|
||||
do_check_eq(payload.clientID, gDataReportingClientID);
|
||||
}
|
||||
|
||||
try {
|
||||
// If we've not got nsIGfxInfoDebug, then this will throw and stop us doing
|
||||
// this test.
|
||||
let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
let isOSX = ("nsILocalFileMac" in Components.interfaces);
|
||||
|
||||
if (isWindows || isOSX) {
|
||||
do_check_true("adapterVendorID" in payload.info);
|
||||
do_check_true("adapterDeviceID" in payload.info);
|
||||
if (isWindows) {
|
||||
do_check_true("adapterSubsysID" in payload.info);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (x) {
|
||||
}
|
||||
}
|
||||
|
||||
function checkPayload(request, payload, reason, successfulPings) {
|
||||
@@ -362,17 +343,6 @@ function checkPayload(request, payload, reason, successfulPings) {
|
||||
Assert.deepEqual(expected_keyed_count, keyedHistograms[TELEMETRY_TEST_KEYED_COUNT]);
|
||||
}
|
||||
|
||||
function dummyTheme(id) {
|
||||
return {
|
||||
id: id,
|
||||
name: Math.random().toString(),
|
||||
headerURL: "http://lwttest.invalid/a.png",
|
||||
footerURL: "http://lwttest.invalid/b.png",
|
||||
textcolor: Math.random().toString(),
|
||||
accentcolor: Math.random().toString()
|
||||
};
|
||||
}
|
||||
|
||||
// A fake plugin host for testing flash version telemetry
|
||||
let PluginHost = {
|
||||
getPluginTags: function(countRef) {
|
||||
@@ -435,13 +405,6 @@ function write_fake_failedprofilelocks_file() {
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
try {
|
||||
let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
gfxInfo.spoofVendorID("0xabcd");
|
||||
gfxInfo.spoofDeviceID("0x1234");
|
||||
} catch (x) {
|
||||
// If we can't test gfxInfo, that's fine, we'll note it later.
|
||||
}
|
||||
|
||||
// Addon manager needs a profile directory
|
||||
do_get_profile();
|
||||
@@ -495,7 +458,6 @@ function actualTest() {
|
||||
.QueryInterface(Ci.nsITimerCallback);
|
||||
|
||||
gInternalManager.observe(null, "addons-startup", null);
|
||||
LightweightThemeManager.currentTheme = dummyTheme("1234");
|
||||
|
||||
// fake plugin host for consistent flash version data
|
||||
registerFakePluginHost();
|
||||
@@ -606,6 +568,173 @@ add_task(function* test_saveLoadPing() {
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_checkSubsession() {
|
||||
const COUNT_ID = "TELEMETRY_TEST_COUNT";
|
||||
const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
|
||||
const count = Telemetry.getHistogramById(COUNT_ID);
|
||||
const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
|
||||
const registeredIds =
|
||||
new Set(Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []));
|
||||
|
||||
const stableHistograms = new Set([
|
||||
"TELEMETRY_TEST_FLAG",
|
||||
"TELEMETRY_TEST_COUNT",
|
||||
"TELEMETRY_TEST_RELEASE_OPTOUT",
|
||||
"TELEMETRY_TEST_RELEASE_OPTIN",
|
||||
"STARTUP_CRASH_DETECTED",
|
||||
]);
|
||||
|
||||
const stableKeyedHistograms = new Set([
|
||||
"TELEMETRY_TEST_KEYED_FLAG",
|
||||
"TELEMETRY_TEST_KEYED_COUNT",
|
||||
"TELEMETRY_TEST_KEYED_RELEASE_OPTIN",
|
||||
"TELEMETRY_TEST_KEYED_RELEASE_OPTOUT",
|
||||
]);
|
||||
|
||||
// Compare the two sets of histograms.
|
||||
// The "subsession" histograms should match the registered
|
||||
// "classic" histograms. However, histograms can change
|
||||
// between us collecting the different payloads, so we only
|
||||
// check for deep equality on known stable histograms.
|
||||
checkHistograms = (classic, subsession) => {
|
||||
for (let id of Object.keys(classic)) {
|
||||
if (!registeredIds.has(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assert.ok(id in subsession);
|
||||
if (stableHistograms.has(id)) {
|
||||
Assert.deepEqual(classic[id],
|
||||
subsession[id]);
|
||||
} else {
|
||||
Assert.equal(classic[id].histogram_type,
|
||||
subsession[id].histogram_type);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Same as above, except for keyed histograms.
|
||||
checkKeyedHistograms = (classic, subsession) => {
|
||||
for (let id of Object.keys(classic)) {
|
||||
if (!registeredIds.has(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assert.ok(id in subsession);
|
||||
if (stableKeyedHistograms.has(id)) {
|
||||
Assert.deepEqual(classic[id],
|
||||
subsession[id]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Both classic and subsession payload histograms should start the same.
|
||||
// The payloads should be identical for now except for the reason.
|
||||
count.clear();
|
||||
keyed.clear();
|
||||
let classic = TelemetrySession.getPayload();
|
||||
let subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.equal(classic.info.reason, "gather-payload");
|
||||
Assert.equal(subsession.info.reason, "environment-change");
|
||||
Assert.ok(!(COUNT_ID in classic.histograms));
|
||||
Assert.ok(!(COUNT_ID in subsession.histograms));
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.deepEqual(classic.keyedHistograms[KEYED_ID], {});
|
||||
Assert.deepEqual(subsession.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// Adding values should get picked up in both.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// Values should still reset properly.
|
||||
count.clear();
|
||||
keyed.clear();
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(!(COUNT_ID in classic.histograms));
|
||||
Assert.ok(!(COUNT_ID in subsession.histograms));
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.deepEqual(classic.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// Adding values should get picked up in both.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// We should be able to reset only the subsession histograms.
|
||||
count.clear(true);
|
||||
keyed.clear(true);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(subsession.histograms[COUNT_ID].sum, 0);
|
||||
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
Assert.deepEqual(subsession.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
// Adding values should get picked up in both again.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 2);
|
||||
Assert.equal(subsession.histograms[COUNT_ID].sum, 1);
|
||||
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 2);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 2);
|
||||
Assert.equal(subsession.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(subsession.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
});
|
||||
|
||||
// Checks that an expired histogram file is deleted when loaded.
|
||||
add_task(function* test_runOldPingFile() {
|
||||
let histogramsFile = getSavedHistogramsFile("old-histograms.dat");
|
||||
|
||||
@@ -17,12 +17,12 @@ const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://testing-common/httpd.js", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
let {OS: {File, Path, Constants}} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||
@@ -53,70 +53,66 @@ let gCreatedPings = 0;
|
||||
let gSeenPings = 0;
|
||||
|
||||
/**
|
||||
* Creates some TelemetrySession pings for the current session and
|
||||
* saves them to disk. Each ping gets a unique ID slug based on
|
||||
* an incrementor.
|
||||
* Creates some Telemetry pings for the and saves them to disk. Each ping gets a
|
||||
* unique ID based on an incrementor.
|
||||
*
|
||||
* @param aNum the number of pings to create.
|
||||
* @param aAge the age in milliseconds to offset from now. A value
|
||||
* of 10 would make the ping 10ms older than now, for
|
||||
* example.
|
||||
* @param {Array} aPingInfos An array of ping type objects. Each entry must be an
|
||||
* object containing a "num" field for the number of pings to create and
|
||||
* an "age" field. The latter representing the age in milliseconds to offset
|
||||
* from now. A value of 10 would make the ping 10ms older than now, for
|
||||
* example.
|
||||
* @returns Promise
|
||||
* @resolve an Array with the created pings.
|
||||
* @resolve an Array with the created pings ids.
|
||||
*/
|
||||
function createSavedPings(aNum, aAge) {
|
||||
return Task.spawn(function*(){
|
||||
let pings = [];
|
||||
let age = Date.now() - aAge;
|
||||
let createSavedPings = Task.async(function* (aPingInfos) {
|
||||
let pingIds = [];
|
||||
let now = Date.now();
|
||||
|
||||
for (let i = 0; i < aNum; ++i) {
|
||||
let payload = TelemetrySession.getPayload();
|
||||
let ping = { slug: "test-ping-" + gCreatedPings, reason: "test", payload: payload };
|
||||
|
||||
yield TelemetryFile.savePing(ping);
|
||||
|
||||
if (aAge) {
|
||||
for (let type in aPingInfos) {
|
||||
let num = aPingInfos[type].num;
|
||||
let age = now - aPingInfos[type].age;
|
||||
for (let i = 0; i < num; ++i) {
|
||||
let pingId = yield TelemetryPing.testSavePingToFile("test-ping", {}, { overwrite: true });
|
||||
if (aPingInfos[type].age) {
|
||||
// savePing writes to the file synchronously, so we're good to
|
||||
// modify the lastModifedTime now.
|
||||
let file = getSavePathForPing(ping);
|
||||
yield File.setDates(file, null, age);
|
||||
let filePath = getSavePathForPingId(pingId);
|
||||
yield File.setDates(filePath, null, age);
|
||||
}
|
||||
gCreatedPings++;
|
||||
pings.push(ping);
|
||||
pingIds.push(pingId);
|
||||
}
|
||||
return pings;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return pingIds;
|
||||
});
|
||||
|
||||
/**
|
||||
* Deletes locally saved pings in aPings if they
|
||||
* exist.
|
||||
* Deletes locally saved pings if they exist.
|
||||
*
|
||||
* @param aPings an Array of pings to delete.
|
||||
* @param aPingIds an Array of ping ids to delete.
|
||||
* @returns Promise
|
||||
*/
|
||||
function clearPings(aPings) {
|
||||
return Task.spawn(function*() {
|
||||
for (let ping of aPings) {
|
||||
let path = getSavePathForPing(ping);
|
||||
yield File.remove(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
let clearPings = Task.async(function* (aPingIds) {
|
||||
for (let pingId of aPingIds) {
|
||||
let filePath = getSavePathForPingId(pingId);
|
||||
yield File.remove(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns a handle for the file that aPing should be
|
||||
* Returns a handle for the file that a ping should be
|
||||
* stored in locally.
|
||||
*
|
||||
* @returns path
|
||||
*/
|
||||
function getSavePathForPing(aPing) {
|
||||
return Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, aPing.slug);
|
||||
function getSavePathForPingId(aPingId) {
|
||||
return Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, aPingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the number of TelemetrySession pings received by the
|
||||
* HttpServer is not equal to aExpectedNum.
|
||||
* Check if the number of Telemetry pings received by the HttpServer is not equal
|
||||
* to aExpectedNum.
|
||||
*
|
||||
* @param aExpectedNum the number of pings we expect to receive.
|
||||
*/
|
||||
@@ -125,30 +121,28 @@ function assertReceivedPings(aExpectedNum) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if any pings in aPings is saved locally.
|
||||
* Throws if any pings with the id in aPingIds is saved locally.
|
||||
*
|
||||
* @param aPings an Array of pings to check.
|
||||
* @param aPingIds an Array of pings ids to check.
|
||||
* @returns Promise
|
||||
*/
|
||||
function assertNotSaved(aPings) {
|
||||
return Task.spawn(function*() {
|
||||
let saved = 0;
|
||||
for (let ping of aPings) {
|
||||
let file = getSavePathForPing(ping);
|
||||
if (yield File.exists()) {
|
||||
saved++;
|
||||
}
|
||||
let assertNotSaved = Task.async(function* (aPingIds) {
|
||||
let saved = 0;
|
||||
for (let id of aPingIds) {
|
||||
let filePath = getSavePathForPingId(id);
|
||||
if (yield File.exists(filePath)) {
|
||||
saved++;
|
||||
}
|
||||
if (saved > 0) {
|
||||
do_throw("Found " + saved + " unexpected saved pings.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (saved > 0) {
|
||||
do_throw("Found " + saved + " unexpected saved pings.");
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Our handler function for the HttpServer that simply
|
||||
* increments the gSeenPings global when it successfully
|
||||
* receives and decodes a TelemetrySession payload.
|
||||
* receives and decodes a Telemetry payload.
|
||||
*
|
||||
* @param aRequest the HTTP request sent from HttpServer.
|
||||
*/
|
||||
@@ -174,7 +168,6 @@ function stopHttpServer() {
|
||||
* Reset Telemetry state.
|
||||
*/
|
||||
function resetTelemetry() {
|
||||
TelemetrySession.uninstall();
|
||||
// Quick and dirty way to clear TelemetryFile's pendingPings
|
||||
// collection, and put it back in its initial state.
|
||||
let gen = TelemetryFile.popPendingPings();
|
||||
@@ -189,10 +182,6 @@ function startTelemetry() {
|
||||
return TelemetryPing.setup();
|
||||
}
|
||||
|
||||
function startTelemetrySession() {
|
||||
return TelemetrySession.setup();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
gHttpServer.registerPrefixHandler("/submit/telemetry/", pingHandler);
|
||||
gHttpServer.start(-1);
|
||||
@@ -209,13 +198,26 @@ function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the tests by making sure the ping storage directory is available, otherwise
|
||||
* |TelemetryPing.testSaveDirectoryToFile| could fail.
|
||||
*/
|
||||
add_task(function* setupEnvironment() {
|
||||
yield TelemetryPing.setup();
|
||||
|
||||
let directory = TelemetryFile.pingDirectoryPath;
|
||||
yield File.makeDir(directory, { ignoreExisting: true, unixMode: OS.Constants.S_IRWXU });
|
||||
|
||||
yield resetTelemetry();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that pings that are considered too old are just chucked out
|
||||
* immediately and never sent.
|
||||
*/
|
||||
add_task(function* test_expired_pings_are_deleted() {
|
||||
yield startTelemetrySession();
|
||||
let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
|
||||
let pingTypes = [{ num: EXPIRED_PINGS, age: EXPIRED_PING_FILE_AGE }];
|
||||
let expiredPings = yield createSavedPings(pingTypes);
|
||||
yield startTelemetry();
|
||||
assertReceivedPings(0);
|
||||
yield assertNotSaved(expiredPings);
|
||||
@@ -226,8 +228,8 @@ add_task(function* test_expired_pings_are_deleted() {
|
||||
* Test that really recent pings are not sent on Telemetry initialization.
|
||||
*/
|
||||
add_task(function* test_recent_pings_not_sent() {
|
||||
yield startTelemetrySession();
|
||||
let recentPings = yield createSavedPings(RECENT_PINGS);
|
||||
let pingTypes = [{ num: RECENT_PINGS }];
|
||||
let recentPings = yield createSavedPings(pingTypes);
|
||||
yield startTelemetry();
|
||||
assertReceivedPings(0);
|
||||
yield resetTelemetry();
|
||||
@@ -238,17 +240,20 @@ add_task(function* test_recent_pings_not_sent() {
|
||||
* Test that only the most recent LRU_PINGS pings are kept at startup.
|
||||
*/
|
||||
add_task(function* test_most_recent_pings_kept() {
|
||||
yield startTelemetrySession();
|
||||
let head = yield createSavedPings(LRU_PINGS);
|
||||
let tail = yield createSavedPings(3, ONE_MINUTE_MS);
|
||||
let pings = head.concat(tail);
|
||||
let pingTypes = [
|
||||
{ num: LRU_PINGS },
|
||||
{ num: 3, age: ONE_MINUTE_MS },
|
||||
];
|
||||
let pings = yield createSavedPings(pingTypes);
|
||||
let head = pings.slice(0, LRU_PINGS);
|
||||
let tail = pings.slice(-3);
|
||||
|
||||
yield startTelemetry();
|
||||
let gen = TelemetryFile.popPendingPings();
|
||||
|
||||
for (let item of gen) {
|
||||
for (let p of tail) {
|
||||
do_check_neq(p.slug, item.slug);
|
||||
for (let id of tail) {
|
||||
do_check_neq(id, item.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,10 +268,15 @@ add_task(function* test_most_recent_pings_kept() {
|
||||
* should just be deleted.
|
||||
*/
|
||||
add_task(function* test_overdue_pings_trigger_send() {
|
||||
yield startTelemetrySession();
|
||||
let recentPings = yield createSavedPings(RECENT_PINGS);
|
||||
let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
|
||||
let overduePings = yield createSavedPings(OVERDUE_PINGS, OVERDUE_PING_FILE_AGE);
|
||||
let pingTypes = [
|
||||
{ num: RECENT_PINGS },
|
||||
{ num: EXPIRED_PINGS, age: EXPIRED_PING_FILE_AGE },
|
||||
{ num: OVERDUE_PINGS, age: OVERDUE_PING_FILE_AGE },
|
||||
];
|
||||
let pings = yield createSavedPings(pingTypes);
|
||||
let recentPings = pings.slice(0, RECENT_PINGS);
|
||||
let expiredPings = pings.slice(RECENT_PINGS, RECENT_PINGS + EXPIRED_PINGS);
|
||||
let overduePings = pings.slice(-OVERDUE_PINGS);
|
||||
|
||||
yield startTelemetry();
|
||||
assertReceivedPings(TOTAL_EXPECTED_PINGS);
|
||||
|
||||
@@ -0,0 +1,953 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
/* This testcase triggers two telemetry pings.
|
||||
*
|
||||
* Telemetry code keeps histograms of past telemetry pings. The first
|
||||
* ping populates these histograms. One of those histograms is then
|
||||
* checked in the second request.
|
||||
*/
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
|
||||
Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
|
||||
const PING_FORMAT_VERSION = 2;
|
||||
const PING_TYPE_MAIN = "main";
|
||||
|
||||
const REASON_SAVED_SESSION = "saved-session";
|
||||
const REASON_TEST_PING = "test-ping";
|
||||
const REASON_DAILY = "daily";
|
||||
const REASON_ENVIRONMENT_CHANGE = "environment-change";
|
||||
|
||||
const PLATFORM_VERSION = "1.9.2";
|
||||
const APP_VERSION = "1";
|
||||
const APP_ID = "xpcshell@tests.mozilla.org";
|
||||
const APP_NAME = "XPCShell";
|
||||
|
||||
const IGNORE_HISTOGRAM = "test::ignore_me";
|
||||
const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED";
|
||||
const IGNORE_CLONED_HISTOGRAM = "test::ignore_me_also";
|
||||
const ADDON_NAME = "Telemetry test addon";
|
||||
const ADDON_HISTOGRAM = "addon-histogram";
|
||||
// Add some unicode characters here to ensure that sending them works correctly.
|
||||
const SHUTDOWN_TIME = 10000;
|
||||
const FAILED_PROFILE_LOCK_ATTEMPTS = 2;
|
||||
|
||||
// Constants from prio.h for nsIFileOutputStream.init
|
||||
const PR_WRONLY = 0x2;
|
||||
const PR_CREATE_FILE = 0x8;
|
||||
const PR_TRUNCATE = 0x20;
|
||||
const RW_OWNER = parseInt("0600", 8);
|
||||
|
||||
const NUMBER_OF_THREADS_TO_LAUNCH = 30;
|
||||
let gNumberOfThreadsLaunched = 0;
|
||||
|
||||
const SEC_IN_ONE_DAY = 24 * 60 * 60;
|
||||
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
|
||||
|
||||
const PREF_BRANCH = "toolkit.telemetry.";
|
||||
const PREF_ENABLED = PREF_BRANCH + "enabled";
|
||||
const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
|
||||
const PREF_FHR_SERVICE_ENABLED = "datareporting.healthreport.service.enabled";
|
||||
|
||||
const HAS_DATAREPORTINGSERVICE = "@mozilla.org/datareporting/service;1" in Cc;
|
||||
const SESSION_RECORDER_EXPECTED = HAS_DATAREPORTINGSERVICE &&
|
||||
Preferences.get(PREF_FHR_SERVICE_ENABLED, true);
|
||||
|
||||
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
|
||||
let gHttpServer = new HttpServer();
|
||||
let gServerStarted = false;
|
||||
let gRequestIterator = null;
|
||||
let gDataReportingClientID = null;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gDatareportingService",
|
||||
() => Cc["@mozilla.org/datareporting/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject);
|
||||
|
||||
function sendPing() {
|
||||
TelemetrySession.gatherStartup();
|
||||
if (gServerStarted) {
|
||||
TelemetryPing.setServer("http://localhost:" + gHttpServer.identity.primaryPort);
|
||||
return TelemetrySession.testPing();
|
||||
} else {
|
||||
TelemetryPing.setServer("http://doesnotexist");
|
||||
return TelemetrySession.testPing();
|
||||
}
|
||||
}
|
||||
|
||||
function wrapWithExceptionHandler(f) {
|
||||
function wrapper(...args) {
|
||||
try {
|
||||
f(...args);
|
||||
} catch (ex if typeof(ex) == 'object') {
|
||||
dump("Caught exception: " + ex.message + "\n");
|
||||
dump(ex.stack);
|
||||
do_test_finished();
|
||||
}
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function fakeNow(date) {
|
||||
let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
|
||||
session.Policy.now = () => new Date(date.getTime());
|
||||
}
|
||||
|
||||
function futureDate(date, offset) {
|
||||
return new Date(date.getTime() + offset);
|
||||
}
|
||||
|
||||
function fakeNow(date) {
|
||||
let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
|
||||
session.Policy.now = () => date;
|
||||
}
|
||||
|
||||
function registerPingHandler(handler) {
|
||||
gHttpServer.registerPrefixHandler("/submit/telemetry/",
|
||||
wrapWithExceptionHandler(handler));
|
||||
}
|
||||
|
||||
function setupTestData() {
|
||||
Telemetry.newHistogram(IGNORE_HISTOGRAM, "never", Telemetry.HISTOGRAM_BOOLEAN);
|
||||
Telemetry.histogramFrom(IGNORE_CLONED_HISTOGRAM, IGNORE_HISTOGRAM_TO_CLONE);
|
||||
Services.startup.interrupted = true;
|
||||
Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM,
|
||||
Telemetry.HISTOGRAM_LINEAR,
|
||||
1, 5, 6);
|
||||
let h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
|
||||
h1.add(1);
|
||||
let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
|
||||
h2.add();
|
||||
|
||||
let k1 = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
|
||||
k1.add("a");
|
||||
k1.add("a");
|
||||
k1.add("b");
|
||||
}
|
||||
|
||||
function getSavedPingFile(basename) {
|
||||
let tmpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
let pingFile = tmpDir.clone();
|
||||
pingFile.append(basename);
|
||||
if (pingFile.exists()) {
|
||||
pingFile.remove(true);
|
||||
}
|
||||
do_register_cleanup(function () {
|
||||
try {
|
||||
pingFile.remove(true);
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
return pingFile;
|
||||
}
|
||||
|
||||
function decodeRequestPayload(request) {
|
||||
let s = request.bodyInputStream;
|
||||
let payload = null;
|
||||
let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON)
|
||||
|
||||
if (request.getHeader("content-encoding") == "gzip") {
|
||||
let observer = {
|
||||
buffer: "",
|
||||
onStreamComplete: function(loader, context, status, length, result) {
|
||||
this.buffer = String.fromCharCode.apply(this, result);
|
||||
}
|
||||
};
|
||||
|
||||
let scs = Cc["@mozilla.org/streamConverters;1"]
|
||||
.getService(Ci.nsIStreamConverterService);
|
||||
let listener = Cc["@mozilla.org/network/stream-loader;1"]
|
||||
.createInstance(Ci.nsIStreamLoader);
|
||||
listener.init(observer);
|
||||
let converter = scs.asyncConvertData("gzip", "uncompressed",
|
||||
listener, null);
|
||||
converter.onStartRequest(null, null);
|
||||
converter.onDataAvailable(null, null, s, 0, s.available());
|
||||
converter.onStopRequest(null, null, null);
|
||||
let unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
unicodeConverter.charset = "UTF-8";
|
||||
let utf8string = unicodeConverter.ConvertToUnicode(observer.buffer);
|
||||
utf8string += unicodeConverter.Finish();
|
||||
payload = decoder.decode(utf8string);
|
||||
} else {
|
||||
payload = decoder.decodeFromStream(s, s.available());
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
function checkPingFormat(aPing, aType, aHasClientId, aHasEnvironment) {
|
||||
const MANDATORY_PING_FIELDS = [
|
||||
"type", "id", "creationDate", "version", "application", "payload"
|
||||
];
|
||||
|
||||
const APPLICATION_TEST_DATA = {
|
||||
buildId: "2007010101",
|
||||
name: APP_NAME,
|
||||
version: APP_VERSION,
|
||||
vendor: "Mozilla",
|
||||
platformVersion: PLATFORM_VERSION,
|
||||
xpcomAbi: "noarch-spidermonkey",
|
||||
};
|
||||
|
||||
// Check that the ping contains all the mandatory fields.
|
||||
for (let f of MANDATORY_PING_FIELDS) {
|
||||
Assert.ok(f in aPing, f + "must be available.");
|
||||
}
|
||||
|
||||
Assert.equal(aPing.type, aType, "The ping must have the correct type.");
|
||||
Assert.equal(aPing.version, PING_FORMAT_VERSION, "The ping must have the correct version.");
|
||||
|
||||
// Test the application section.
|
||||
for (let f in APPLICATION_TEST_DATA) {
|
||||
Assert.equal(aPing.application[f], APPLICATION_TEST_DATA[f],
|
||||
f + " must have the correct value.");
|
||||
}
|
||||
|
||||
// We can't check the values for channel and architecture. Just make
|
||||
// sure they are in.
|
||||
Assert.ok("architecture" in aPing.application,
|
||||
"The application section must have an architecture field.");
|
||||
Assert.ok("channel" in aPing.application,
|
||||
"The application section must have a channel field.");
|
||||
|
||||
// Check the clientId and environment fields, as needed.
|
||||
Assert.equal("clientId" in aPing, aHasClientId);
|
||||
Assert.equal("environment" in aPing, aHasEnvironment);
|
||||
}
|
||||
|
||||
function checkPayload(payload, reason, successfulPings) {
|
||||
Assert.ok(payload.simpleMeasurements.uptime >= 0);
|
||||
Assert.equal(payload.simpleMeasurements.startupInterrupted, 1);
|
||||
Assert.equal(payload.simpleMeasurements.shutdownDuration, SHUTDOWN_TIME);
|
||||
Assert.equal(payload.simpleMeasurements.savedPings, 1);
|
||||
Assert.ok("maximalNumberOfConcurrentThreads" in payload.simpleMeasurements);
|
||||
Assert.ok(payload.simpleMeasurements.maximalNumberOfConcurrentThreads >= gNumberOfThreadsLaunched);
|
||||
|
||||
let activeTicks = payload.simpleMeasurements.activeTicks;
|
||||
Assert.ok(SESSION_RECORDER_EXPECTED ? activeTicks >= 0 : activeTicks == -1);
|
||||
|
||||
Assert.equal(payload.simpleMeasurements.failedProfileLockCount,
|
||||
FAILED_PROFILE_LOCK_ATTEMPTS);
|
||||
let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
let failedProfileLocksFile = profileDirectory.clone();
|
||||
failedProfileLocksFile.append("Telemetry.FailedProfileLocks.txt");
|
||||
Assert.ok(!failedProfileLocksFile.exists());
|
||||
|
||||
|
||||
let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
if (isWindows) {
|
||||
Assert.ok(payload.simpleMeasurements.startupSessionRestoreReadBytes > 0);
|
||||
Assert.ok(payload.simpleMeasurements.startupSessionRestoreWriteBytes > 0);
|
||||
}
|
||||
|
||||
const TELEMETRY_PING = "TELEMETRY_PING";
|
||||
const TELEMETRY_SUCCESS = "TELEMETRY_SUCCESS";
|
||||
const TELEMETRY_TEST_FLAG = "TELEMETRY_TEST_FLAG";
|
||||
const TELEMETRY_TEST_COUNT = "TELEMETRY_TEST_COUNT";
|
||||
const TELEMETRY_TEST_KEYED_FLAG = "TELEMETRY_TEST_KEYED_FLAG";
|
||||
const TELEMETRY_TEST_KEYED_COUNT = "TELEMETRY_TEST_KEYED_COUNT";
|
||||
const READ_SAVED_PING_SUCCESS = "READ_SAVED_PING_SUCCESS";
|
||||
|
||||
Assert.ok(TELEMETRY_PING in payload.histograms);
|
||||
Assert.ok(READ_SAVED_PING_SUCCESS in payload.histograms);
|
||||
Assert.ok(TELEMETRY_TEST_FLAG in payload.histograms);
|
||||
Assert.ok(TELEMETRY_TEST_COUNT in payload.histograms);
|
||||
|
||||
let rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
|
||||
for (let name of rh) {
|
||||
if (/SQLITE/.test(name) && name in payload.histograms) {
|
||||
let histogramName = ("STARTUP_" + name);
|
||||
Assert.ok(histogramName in payload.histograms, histogramName + " must be available.");
|
||||
}
|
||||
}
|
||||
Assert.ok(!(IGNORE_HISTOGRAM in payload.histograms));
|
||||
Assert.ok(!(IGNORE_CLONED_HISTOGRAM in payload.histograms));
|
||||
|
||||
// Flag histograms should automagically spring to life.
|
||||
const expected_flag = {
|
||||
range: [1, 2],
|
||||
bucket_count: 3,
|
||||
histogram_type: 3,
|
||||
values: {0:1, 1:0},
|
||||
sum: 0,
|
||||
sum_squares_lo: 0,
|
||||
sum_squares_hi: 0
|
||||
};
|
||||
let flag = payload.histograms[TELEMETRY_TEST_FLAG];
|
||||
Assert.equal(uneval(flag), uneval(expected_flag));
|
||||
|
||||
// We should have a test count.
|
||||
const expected_count = {
|
||||
range: [1, 2],
|
||||
bucket_count: 3,
|
||||
histogram_type: 4,
|
||||
values: {0:1, 1:0},
|
||||
sum: 1,
|
||||
sum_squares_lo: 1,
|
||||
sum_squares_hi: 0,
|
||||
};
|
||||
let count = payload.histograms[TELEMETRY_TEST_COUNT];
|
||||
Assert.equal(uneval(count), uneval(expected_count));
|
||||
|
||||
// There should be one successful report from the previous telemetry ping.
|
||||
const expected_tc = {
|
||||
range: [1, 2],
|
||||
bucket_count: 3,
|
||||
histogram_type: 2,
|
||||
values: {0:2, 1:successfulPings, 2:0},
|
||||
sum: successfulPings,
|
||||
sum_squares_lo: successfulPings,
|
||||
sum_squares_hi: 0
|
||||
};
|
||||
let tc = payload.histograms[TELEMETRY_SUCCESS];
|
||||
Assert.equal(uneval(tc), uneval(expected_tc));
|
||||
|
||||
let h = payload.histograms[READ_SAVED_PING_SUCCESS];
|
||||
Assert.equal(h.values[0], 1);
|
||||
|
||||
// The ping should include data from memory reporters. We can't check that
|
||||
// this data is correct, because we can't control the values returned by the
|
||||
// memory reporters. But we can at least check that the data is there.
|
||||
//
|
||||
// It's important to check for the presence of reporters with a mix of units,
|
||||
// because TelemetryPing has separate logic for each one. But we can't
|
||||
// currently check UNITS_COUNT_CUMULATIVE or UNITS_PERCENTAGE because
|
||||
// Telemetry doesn't touch a memory reporter with these units that's
|
||||
// available on all platforms.
|
||||
|
||||
Assert.ok('MEMORY_JS_GC_HEAP' in payload.histograms); // UNITS_BYTES
|
||||
Assert.ok('MEMORY_JS_COMPARTMENTS_SYSTEM' in payload.histograms); // UNITS_COUNT
|
||||
|
||||
// We should have included addon histograms.
|
||||
Assert.ok("addonHistograms" in payload);
|
||||
Assert.ok(ADDON_NAME in payload.addonHistograms);
|
||||
Assert.ok(ADDON_HISTOGRAM in payload.addonHistograms[ADDON_NAME]);
|
||||
|
||||
Assert.ok(("mainThread" in payload.slowSQL) &&
|
||||
("otherThreads" in payload.slowSQL));
|
||||
|
||||
// Check keyed histogram payload.
|
||||
|
||||
Assert.ok("keyedHistograms" in payload);
|
||||
let keyedHistograms = payload.keyedHistograms;
|
||||
Assert.ok(TELEMETRY_TEST_KEYED_FLAG in keyedHistograms);
|
||||
Assert.ok(TELEMETRY_TEST_KEYED_COUNT in keyedHistograms);
|
||||
|
||||
Assert.deepEqual({}, keyedHistograms[TELEMETRY_TEST_KEYED_FLAG]);
|
||||
|
||||
const expected_keyed_count = {
|
||||
"a": {
|
||||
range: [1, 2],
|
||||
bucket_count: 3,
|
||||
histogram_type: 4,
|
||||
values: {0:2, 1:0},
|
||||
sum: 2,
|
||||
sum_squares_lo: 2,
|
||||
sum_squares_hi: 0,
|
||||
},
|
||||
"b": {
|
||||
range: [1, 2],
|
||||
bucket_count: 3,
|
||||
histogram_type: 4,
|
||||
values: {0:1, 1:0},
|
||||
sum: 1,
|
||||
sum_squares_lo: 1,
|
||||
sum_squares_hi: 0,
|
||||
},
|
||||
};
|
||||
Assert.deepEqual(expected_keyed_count, keyedHistograms[TELEMETRY_TEST_KEYED_COUNT]);
|
||||
}
|
||||
|
||||
function writeStringToFile(file, contents) {
|
||||
let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
|
||||
.createInstance(Ci.nsIFileOutputStream);
|
||||
ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
|
||||
RW_OWNER, ostream.DEFER_OPEN);
|
||||
ostream.write(contents, contents.length);
|
||||
ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
|
||||
ostream.close();
|
||||
}
|
||||
|
||||
function write_fake_shutdown_file() {
|
||||
let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
let file = profileDirectory.clone();
|
||||
file.append("Telemetry.ShutdownTime.txt");
|
||||
let contents = "" + SHUTDOWN_TIME;
|
||||
writeStringToFile(file, contents);
|
||||
}
|
||||
|
||||
function write_fake_failedprofilelocks_file() {
|
||||
let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
let file = profileDirectory.clone();
|
||||
file.append("Telemetry.FailedProfileLocks.txt");
|
||||
let contents = "" + FAILED_PROFILE_LOCK_ATTEMPTS;
|
||||
writeStringToFile(file, contents);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
// Addon manager needs a profile directory
|
||||
do_get_profile();
|
||||
loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
|
||||
|
||||
Services.prefs.setBoolPref(PREF_ENABLED, true);
|
||||
Services.prefs.setBoolPref(PREF_FHR_UPLOAD_ENABLED, true);
|
||||
|
||||
// Send the needed startup notifications to the datareporting service
|
||||
// to ensure that it has been initialized.
|
||||
if (HAS_DATAREPORTINGSERVICE) {
|
||||
gDatareportingService.observe(null, "app-startup", null);
|
||||
gDatareportingService.observe(null, "profile-after-change", null);
|
||||
}
|
||||
|
||||
// Make it look like we've previously failed to lock a profile a couple times.
|
||||
write_fake_failedprofilelocks_file();
|
||||
|
||||
// Make it look like we've shutdown before.
|
||||
write_fake_shutdown_file();
|
||||
|
||||
let currentMaxNumberOfThreads = Telemetry.maximalNumberOfConcurrentThreads;
|
||||
do_check_true(currentMaxNumberOfThreads > 0);
|
||||
|
||||
// Try to augment the maximal number of threads currently launched
|
||||
let threads = [];
|
||||
try {
|
||||
for (let i = 0; i < currentMaxNumberOfThreads + 10; ++i) {
|
||||
threads.push(Services.tm.newThread(0));
|
||||
}
|
||||
} catch (ex) {
|
||||
// If memory is too low, it is possible that not all threads will be launched.
|
||||
}
|
||||
gNumberOfThreadsLaunched = threads.length;
|
||||
|
||||
do_check_true(Telemetry.maximalNumberOfConcurrentThreads >= gNumberOfThreadsLaunched);
|
||||
|
||||
do_register_cleanup(function() {
|
||||
threads.forEach(function(thread) {
|
||||
thread.shutdown();
|
||||
});
|
||||
});
|
||||
|
||||
Telemetry.asyncFetchTelemetryData(wrapWithExceptionHandler(run_next_test));
|
||||
}
|
||||
|
||||
add_task(function* asyncSetup() {
|
||||
yield TelemetrySession.setup();
|
||||
yield TelemetryPing.setup();
|
||||
|
||||
if (HAS_DATAREPORTINGSERVICE) {
|
||||
// force getSessionRecorder()==undefined to check the payload's activeTicks
|
||||
gDatareportingService.simulateNoSessionRecorder();
|
||||
}
|
||||
|
||||
// When no DRS or no DRS.getSessionRecorder(), activeTicks should be -1.
|
||||
do_check_eq(TelemetrySession.getPayload().simpleMeasurements.activeTicks, -1);
|
||||
|
||||
if (HAS_DATAREPORTINGSERVICE) {
|
||||
// Restore normal behavior for getSessionRecorder()
|
||||
gDatareportingService.simulateRestoreSessionRecorder();
|
||||
|
||||
gDataReportingClientID = yield gDatareportingService.getClientID();
|
||||
|
||||
// We should have cached the client id now. Lets confirm that by
|
||||
// checking the client id before the async ping setup is finished.
|
||||
let promisePingSetup = TelemetryPing.reset();
|
||||
do_check_eq(TelemetryPing.clientID, gDataReportingClientID);
|
||||
yield promisePingSetup;
|
||||
}
|
||||
});
|
||||
|
||||
// Ensures that expired histograms are not part of the payload.
|
||||
add_task(function* test_expiredHistogram() {
|
||||
let histogram_id = "FOOBAR";
|
||||
let dummy = Telemetry.newHistogram(histogram_id, "30", Telemetry.HISTOGRAM_EXPONENTIAL, 1, 2, 3);
|
||||
|
||||
dummy.add(1);
|
||||
|
||||
do_check_eq(TelemetrySession.getPayload()["histograms"][histogram_id], undefined);
|
||||
do_check_eq(TelemetrySession.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
|
||||
});
|
||||
|
||||
// Checks that an invalid histogram file is deleted if TelemetryFile fails to parse it.
|
||||
add_task(function* test_runInvalidJSON() {
|
||||
let pingFile = getSavedPingFile("invalid-histograms.dat");
|
||||
|
||||
writeStringToFile(pingFile, "this.is.invalid.JSON");
|
||||
do_check_true(pingFile.exists());
|
||||
|
||||
yield TelemetryFile.testLoadHistograms(pingFile);
|
||||
do_check_false(pingFile.exists());
|
||||
});
|
||||
|
||||
// Sends a ping to a non existing server. If we remove this test, we won't get
|
||||
// all the histograms we need in the main ping.
|
||||
add_task(function* test_noServerPing() {
|
||||
yield sendPing();
|
||||
// We need two pings in order to make sure STARTUP_MEMORY_STORAGE_SQLIE histograms
|
||||
// are initialised. See bug 1131585.
|
||||
yield sendPing();
|
||||
});
|
||||
|
||||
// Checks that a sent ping is correctly received by a dummy http server.
|
||||
add_task(function* test_simplePing() {
|
||||
gHttpServer.start(-1);
|
||||
gServerStarted = true;
|
||||
gRequestIterator = Iterator(new Request());
|
||||
|
||||
yield sendPing();
|
||||
let request = yield gRequestIterator.next();
|
||||
let ping = decodeRequestPayload(request);
|
||||
|
||||
checkPingFormat(ping, PING_TYPE_MAIN, true, true);
|
||||
});
|
||||
|
||||
// Saves the current session histograms, reloads them, performs a ping
|
||||
// and checks that the dummy http server received both the previously
|
||||
// saved histograms and the new ones.
|
||||
add_task(function* test_saveLoadPing() {
|
||||
let histogramsFile = getSavedPingFile("saved-histograms.dat");
|
||||
|
||||
setupTestData();
|
||||
yield TelemetrySession.testSaveHistograms(histogramsFile);
|
||||
yield TelemetryFile.testLoadHistograms(histogramsFile);
|
||||
yield sendPing();
|
||||
|
||||
// Get requests received by dummy server.
|
||||
let request1 = yield gRequestIterator.next();
|
||||
let request2 = yield gRequestIterator.next();
|
||||
|
||||
Assert.equal(request1.getHeader("content-type"), "application/json; charset=UTF-8",
|
||||
"The request must have the correct content-type.");
|
||||
Assert.equal(request2.getHeader("content-type"), "application/json; charset=UTF-8",
|
||||
"The request must have the correct content-type.");
|
||||
|
||||
// We decode both requests to check for the |reason|.
|
||||
let ping1 = decodeRequestPayload(request1);
|
||||
let ping2 = decodeRequestPayload(request2);
|
||||
|
||||
checkPingFormat(ping1, PING_TYPE_MAIN, true, true);
|
||||
checkPingFormat(ping2, PING_TYPE_MAIN, true, true);
|
||||
|
||||
// Check we have the correct two requests. Ordering is not guaranteed.
|
||||
if (ping1.payload.info.reason === REASON_TEST_PING) {
|
||||
// Until we change MainPing according to bug 1120982, common ping payload
|
||||
// will contain another nested payload.
|
||||
checkPayload(ping1.payload, REASON_TEST_PING, 1);
|
||||
checkPayload(ping2.payload, REASON_SAVED_SESSION, 1);
|
||||
} else {
|
||||
checkPayload(ping1.payload, REASON_SAVED_SESSION, 1);
|
||||
checkPayload(ping2.payload, REASON_TEST_PING, 1);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_checkSubsession() {
|
||||
let now = new Date(2020, 1, 1, 12, 0, 0);
|
||||
let expectedDate = new Date(2020, 1, 1, 0, 0, 0);
|
||||
fakeNow(now);
|
||||
TelemetrySession.setup();
|
||||
|
||||
const COUNT_ID = "TELEMETRY_TEST_COUNT";
|
||||
const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
|
||||
const count = Telemetry.getHistogramById(COUNT_ID);
|
||||
const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
|
||||
const registeredIds =
|
||||
new Set(Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []));
|
||||
|
||||
const stableHistograms = new Set([
|
||||
"TELEMETRY_TEST_FLAG",
|
||||
"TELEMETRY_TEST_COUNT",
|
||||
"TELEMETRY_TEST_RELEASE_OPTOUT",
|
||||
"TELEMETRY_TEST_RELEASE_OPTIN",
|
||||
"STARTUP_CRASH_DETECTED",
|
||||
]);
|
||||
|
||||
const stableKeyedHistograms = new Set([
|
||||
"TELEMETRY_TEST_KEYED_FLAG",
|
||||
"TELEMETRY_TEST_KEYED_COUNT",
|
||||
"TELEMETRY_TEST_KEYED_RELEASE_OPTIN",
|
||||
"TELEMETRY_TEST_KEYED_RELEASE_OPTOUT",
|
||||
]);
|
||||
|
||||
// Compare the two sets of histograms.
|
||||
// The "subsession" histograms should match the registered
|
||||
// "classic" histograms. However, histograms can change
|
||||
// between us collecting the different payloads, so we only
|
||||
// check for deep equality on known stable histograms.
|
||||
checkHistograms = (classic, subsession) => {
|
||||
for (let id of Object.keys(classic)) {
|
||||
if (!registeredIds.has(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assert.ok(id in subsession);
|
||||
if (stableHistograms.has(id)) {
|
||||
Assert.deepEqual(classic[id],
|
||||
subsession[id]);
|
||||
} else {
|
||||
Assert.equal(classic[id].histogram_type,
|
||||
subsession[id].histogram_type);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Same as above, except for keyed histograms.
|
||||
checkKeyedHistograms = (classic, subsession) => {
|
||||
for (let id of Object.keys(classic)) {
|
||||
if (!registeredIds.has(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assert.ok(id in subsession);
|
||||
if (stableKeyedHistograms.has(id)) {
|
||||
Assert.deepEqual(classic[id],
|
||||
subsession[id]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Both classic and subsession payload histograms should start the same.
|
||||
// The payloads should be identical for now except for the reason.
|
||||
count.clear();
|
||||
keyed.clear();
|
||||
let classic = TelemetrySession.getPayload();
|
||||
let subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.equal(classic.info.reason, "gather-payload");
|
||||
Assert.equal(subsession.info.reason, "environment-change");
|
||||
Assert.ok(!(COUNT_ID in classic.histograms));
|
||||
Assert.ok(!(COUNT_ID in subsession.histograms));
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.deepEqual(classic.keyedHistograms[KEYED_ID], {});
|
||||
Assert.deepEqual(subsession.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// Adding values should get picked up in both.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// Values should still reset properly.
|
||||
count.clear();
|
||||
keyed.clear();
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(!(COUNT_ID in classic.histograms));
|
||||
Assert.ok(!(COUNT_ID in subsession.histograms));
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.deepEqual(classic.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// Adding values should get picked up in both.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// We should be able to reset only the subsession histograms.
|
||||
// First check that "snapshot and clear" still returns the old state...
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change", true);
|
||||
|
||||
let subsessionStartDate = new Date(classic.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
|
||||
subsessionStartDate = new Date(subsession.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
|
||||
checkHistograms(classic.histograms, subsession.histograms);
|
||||
checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
|
||||
|
||||
// ... then check that the next snapshot shows the subsession
|
||||
// histograms got reset.
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(subsession.histograms[COUNT_ID].sum, 0);
|
||||
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
Assert.deepEqual(subsession.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
// Adding values should get picked up in both again.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
classic = TelemetrySession.getPayload();
|
||||
subsession = TelemetrySession.getPayload("environment-change");
|
||||
|
||||
Assert.ok(COUNT_ID in classic.histograms);
|
||||
Assert.ok(COUNT_ID in subsession.histograms);
|
||||
Assert.equal(classic.histograms[COUNT_ID].sum, 2);
|
||||
Assert.equal(subsession.histograms[COUNT_ID].sum, 1);
|
||||
|
||||
Assert.ok(KEYED_ID in classic.keyedHistograms);
|
||||
Assert.ok(KEYED_ID in subsession.keyedHistograms);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 2);
|
||||
Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 2);
|
||||
Assert.equal(subsession.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(subsession.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
});
|
||||
|
||||
add_task(function* test_dailyCollection() {
|
||||
let now = new Date(2030, 1, 1, 12, 0, 0);
|
||||
let nowDay = new Date(2030, 1, 1, 0, 0, 0);
|
||||
let timerCallback = null;
|
||||
let timerDelay = null;
|
||||
|
||||
gRequestIterator = Iterator(new Request());
|
||||
|
||||
fakeNow(now);
|
||||
fakeDailyTimers((callback, timeout) => {
|
||||
dump("fake setDailyTimeout(" + callback + ", " + timeout + ")\n");
|
||||
timerCallback = callback;
|
||||
timerDelay = timeout;
|
||||
return 1;
|
||||
}, () => {});
|
||||
|
||||
// Init and check timer.
|
||||
yield TelemetrySession.setup();
|
||||
TelemetryPing.setServer("http://localhost:" + gHttpServer.identity.primaryPort);
|
||||
|
||||
Assert.ok(!!timerCallback);
|
||||
Assert.ok(Number.isFinite(timerDelay));
|
||||
let timerDate = futureDate(now, timerDelay);
|
||||
let expectedDate = futureDate(nowDay, MS_IN_ONE_DAY);
|
||||
Assert.equal(timerDate.toISOString(), expectedDate.toISOString());
|
||||
|
||||
// Set histograms to expected state.
|
||||
const COUNT_ID = "TELEMETRY_TEST_COUNT";
|
||||
const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
|
||||
const count = Telemetry.getHistogramById(COUNT_ID);
|
||||
const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
|
||||
|
||||
count.clear();
|
||||
keyed.clear();
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
keyed.add("b", 1);
|
||||
|
||||
// Trigger and collect daily ping.
|
||||
yield timerCallback();
|
||||
let request = yield gRequestIterator.next();
|
||||
Assert.ok(!!request);
|
||||
let ping = decodeRequestPayload(request);
|
||||
|
||||
Assert.equal(ping.type, PING_TYPE_MAIN);
|
||||
Assert.equal(ping.payload.info.reason, REASON_DAILY);
|
||||
let subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), nowDay.toISOString());
|
||||
|
||||
Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["b"].sum, 2);
|
||||
|
||||
// Trigger and collect another ping. The histograms should be reset.
|
||||
yield timerCallback();
|
||||
request = yield gRequestIterator.next();
|
||||
Assert.ok(!!request);
|
||||
ping = decodeRequestPayload(request);
|
||||
|
||||
Assert.equal(ping.type, PING_TYPE_MAIN);
|
||||
Assert.equal(ping.payload.info.reason, REASON_DAILY);
|
||||
subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), nowDay.toISOString());
|
||||
|
||||
Assert.equal(ping.payload.histograms[COUNT_ID].sum, 0);
|
||||
Assert.deepEqual(ping.payload.keyedHistograms[KEYED_ID], {});
|
||||
|
||||
// Trigger and collect another daily ping, with the histograms being set again.
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
|
||||
yield timerCallback();
|
||||
request = yield gRequestIterator.next();
|
||||
Assert.ok(!!request);
|
||||
ping = decodeRequestPayload(request);
|
||||
|
||||
Assert.equal(ping.type, PING_TYPE_MAIN);
|
||||
Assert.equal(ping.payload.info.reason, REASON_DAILY);
|
||||
subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), nowDay.toISOString());
|
||||
|
||||
Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["b"].sum, 1);
|
||||
});
|
||||
|
||||
add_task(function* test_environmentChange() {
|
||||
let now = new Date(2040, 1, 1, 12, 0, 0);
|
||||
let nowDay = new Date(2040, 1, 1, 0, 0, 0);
|
||||
let timerCallback = null;
|
||||
let timerDelay = null;
|
||||
|
||||
gRequestIterator = Iterator(new Request());
|
||||
|
||||
fakeNow(now);
|
||||
fakeDailyTimers(() => {}, () => {});
|
||||
|
||||
const PREF_TEST = "toolkit.telemetry.test.pref1";
|
||||
Preferences.reset(PREF_TEST);
|
||||
let prefsToWatch = {};
|
||||
prefsToWatch[PREF_TEST] = TelemetryEnvironment.RECORD_PREF_VALUE;
|
||||
|
||||
// Setup.
|
||||
yield TelemetrySession.setup();
|
||||
TelemetryPing.setServer("http://localhost:" + gHttpServer.identity.primaryPort);
|
||||
TelemetryEnvironment._watchPreferences(prefsToWatch);
|
||||
|
||||
// Set histograms to expected state.
|
||||
const COUNT_ID = "TELEMETRY_TEST_COUNT";
|
||||
const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
|
||||
const count = Telemetry.getHistogramById(COUNT_ID);
|
||||
const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
|
||||
|
||||
count.clear();
|
||||
keyed.clear();
|
||||
count.add(1);
|
||||
keyed.add("a", 1);
|
||||
keyed.add("b", 1);
|
||||
|
||||
// Trigger and collect environment-change ping.
|
||||
Preferences.set(PREF_TEST, 1);
|
||||
let request = yield gRequestIterator.next();
|
||||
Assert.ok(!!request);
|
||||
let ping = decodeRequestPayload(request);
|
||||
|
||||
Assert.equal(ping.type, PING_TYPE_MAIN);
|
||||
Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], 1);
|
||||
Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
|
||||
let subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), nowDay.toISOString());
|
||||
|
||||
Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
|
||||
Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
|
||||
|
||||
// Trigger and collect another ping. The histograms should be reset.
|
||||
Preferences.set(PREF_TEST, 2);
|
||||
request = yield gRequestIterator.next();
|
||||
Assert.ok(!!request);
|
||||
ping = decodeRequestPayload(request);
|
||||
|
||||
Assert.equal(ping.type, PING_TYPE_MAIN);
|
||||
Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], 2);
|
||||
Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
|
||||
subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
|
||||
Assert.equal(subsessionStartDate.toISOString(), nowDay.toISOString());
|
||||
|
||||
Assert.equal(ping.payload.histograms[COUNT_ID].sum, 0);
|
||||
Assert.deepEqual(ping.payload.keyedHistograms[KEYED_ID], {});
|
||||
});
|
||||
|
||||
// Checks that an expired histogram file is deleted when loaded.
|
||||
add_task(function* test_runOldPingFile() {
|
||||
let histogramsFile = getSavedPingFile("old-histograms.dat");
|
||||
|
||||
yield TelemetrySession.testSaveHistograms(histogramsFile);
|
||||
do_check_true(histogramsFile.exists());
|
||||
let mtime = histogramsFile.lastModifiedTime;
|
||||
histogramsFile.lastModifiedTime = mtime - (14 * 24 * 60 * 60 * 1000 + 60000); // 14 days, 1m
|
||||
|
||||
yield TelemetryFile.testLoadHistograms(histogramsFile);
|
||||
do_check_false(histogramsFile.exists());
|
||||
});
|
||||
|
||||
add_task(function* test_savedSessionClientID() {
|
||||
// Assure that we store the ping properly when saving sessions on shutdown.
|
||||
// We make the TelemetrySession shutdown to trigger a session save.
|
||||
const dir = TelemetryFile.pingDirectoryPath;
|
||||
yield OS.File.removeDir(dir, {ignoreAbsent: true});
|
||||
yield OS.File.makeDir(dir);
|
||||
yield TelemetrySession.shutdown();
|
||||
|
||||
yield TelemetryFile.loadSavedPings();
|
||||
Assert.equal(TelemetryFile.pingsLoaded, 1);
|
||||
let ping = TelemetryFile.popPendingPings().next();
|
||||
Assert.equal(ping.value.clientId, gDataReportingClientID);
|
||||
});
|
||||
|
||||
add_task(function* stopServer(){
|
||||
gHttpServer.stop(do_test_finished);
|
||||
});
|
||||
|
||||
// An iterable sequence of http requests
|
||||
function Request() {
|
||||
let defers = [];
|
||||
let current = 0;
|
||||
|
||||
function RequestIterator() {}
|
||||
|
||||
// Returns a promise that resolves to the next http request
|
||||
RequestIterator.prototype.next = function() {
|
||||
let deferred = defers[current++];
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
this.__iterator__ = function(){
|
||||
return new RequestIterator();
|
||||
}
|
||||
|
||||
registerPingHandler((request, response) => {
|
||||
let deferred = defers[defers.length - 1];
|
||||
defers.push(Promise.defer());
|
||||
deferred.resolve(request);
|
||||
});
|
||||
|
||||
defers.push(Promise.defer());
|
||||
}
|
||||
@@ -355,10 +355,10 @@ function test_addons() {
|
||||
function test_privateMode() {
|
||||
var h = Telemetry.newHistogram("test::private_mode_boolean", "never", Telemetry.HISTOGRAM_BOOLEAN);
|
||||
var orig = h.snapshot();
|
||||
Telemetry.canRecord = false;
|
||||
Telemetry.canRecordExtended = false;
|
||||
h.add(1);
|
||||
do_check_eq(uneval(orig), uneval(h.snapshot()));
|
||||
Telemetry.canRecord = true;
|
||||
Telemetry.canRecordExtended = true;
|
||||
h.add(1);
|
||||
do_check_neq(uneval(orig), uneval(h.snapshot()));
|
||||
}
|
||||
@@ -391,7 +391,7 @@ function numberRange(lower, upper)
|
||||
function test_keyed_boolean_histogram()
|
||||
{
|
||||
const KEYED_ID = "test::keyed::boolean";
|
||||
KEYS = ["key"+(i+1) for (i of numberRange(0, 2))];
|
||||
let KEYS = ["key"+(i+1) for (i of numberRange(0, 2))];
|
||||
KEYS.push("漢語");
|
||||
let histogramBase = {
|
||||
"min": 1,
|
||||
@@ -605,6 +605,134 @@ function test_datasets()
|
||||
Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
|
||||
}
|
||||
|
||||
function test_subsession() {
|
||||
const ID = "TELEMETRY_TEST_COUNT";
|
||||
const FLAG = "TELEMETRY_TEST_FLAG";
|
||||
let h = Telemetry.getHistogramById(ID);
|
||||
let flag = Telemetry.getHistogramById(FLAG);
|
||||
|
||||
// Both original and duplicate should start out the same.
|
||||
h.clear();
|
||||
let snapshot = Telemetry.histogramSnapshots;
|
||||
let subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.ok(!(ID in snapshot));
|
||||
Assert.ok(!(ID in subsession));
|
||||
|
||||
// They should instantiate and pick-up the count.
|
||||
h.add(1);
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.ok(ID in snapshot);
|
||||
Assert.ok(ID in subsession);
|
||||
Assert.equal(snapshot[ID].sum, 1);
|
||||
Assert.equal(subsession[ID].sum, 1);
|
||||
|
||||
// They should still reset properly.
|
||||
h.clear();
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.ok(!(ID in snapshot));
|
||||
Assert.ok(!(ID in subsession));
|
||||
|
||||
// Both should instantiate and pick-up the count.
|
||||
h.add(1);
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.equal(snapshot[ID].sum, 1);
|
||||
Assert.equal(subsession[ID].sum, 1);
|
||||
|
||||
// Check that we are able to only reset the duplicate histogram.
|
||||
h.clear(true);
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.ok(ID in snapshot);
|
||||
Assert.ok(ID in subsession);
|
||||
Assert.equal(snapshot[ID].sum, 1);
|
||||
Assert.equal(subsession[ID].sum, 0);
|
||||
|
||||
// Both should register the next count.
|
||||
h.add(1);
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.equal(snapshot[ID].sum, 2);
|
||||
Assert.equal(subsession[ID].sum, 1);
|
||||
|
||||
// Retrieve a subsession snapshot and pass the flag to
|
||||
// clear subsession histograms too.
|
||||
h.clear();
|
||||
flag.clear();
|
||||
h.add(1);
|
||||
flag.add(1);
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms(true);
|
||||
Assert.ok(ID in snapshot);
|
||||
Assert.ok(ID in subsession);
|
||||
Assert.ok(FLAG in snapshot);
|
||||
Assert.ok(FLAG in subsession);
|
||||
Assert.equal(snapshot[ID].sum, 1);
|
||||
Assert.equal(subsession[ID].sum, 1);
|
||||
Assert.equal(snapshot[FLAG].sum, 1);
|
||||
Assert.equal(subsession[FLAG].sum, 1);
|
||||
|
||||
// The next subsesssion snapshot should show the histograms
|
||||
// got reset.
|
||||
snapshot = Telemetry.histogramSnapshots;
|
||||
subsession = Telemetry.snapshotSubsessionHistograms();
|
||||
Assert.ok(ID in snapshot);
|
||||
Assert.ok(ID in subsession);
|
||||
Assert.ok(FLAG in snapshot);
|
||||
Assert.ok(FLAG in subsession);
|
||||
Assert.equal(snapshot[ID].sum, 1);
|
||||
Assert.equal(subsession[ID].sum, 0);
|
||||
Assert.equal(snapshot[FLAG].sum, 1);
|
||||
Assert.equal(subsession[FLAG].sum, 0);
|
||||
}
|
||||
|
||||
function test_keyed_subsession() {
|
||||
let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
|
||||
const KEY = "foo";
|
||||
|
||||
// Both original and subsession should start out the same.
|
||||
h.clear();
|
||||
Assert.ok(!(KEY in h.snapshot()));
|
||||
Assert.ok(!(KEY in h.subsessionSnapshot()));
|
||||
Assert.equal(h.snapshot(KEY).sum, 0);
|
||||
Assert.equal(h.subsessionSnapshot(KEY).sum, 0);
|
||||
|
||||
// Both should register the flag.
|
||||
h.add(KEY, 1);
|
||||
Assert.ok(KEY in h.snapshot());
|
||||
Assert.ok(KEY in h.subsessionSnapshot());
|
||||
Assert.equal(h.snapshot(KEY).sum, 1);
|
||||
Assert.equal(h.subsessionSnapshot(KEY).sum, 1);
|
||||
|
||||
// Check that we are able to only reset the subsession histogram.
|
||||
h.clear(true);
|
||||
Assert.ok(KEY in h.snapshot());
|
||||
Assert.ok(!(KEY in h.subsessionSnapshot()));
|
||||
Assert.equal(h.snapshot(KEY).sum, 1);
|
||||
Assert.equal(h.subsessionSnapshot(KEY).sum, 0);
|
||||
|
||||
// Setting the flag again should make both match again.
|
||||
h.add(KEY, 1);
|
||||
Assert.ok(KEY in h.snapshot());
|
||||
Assert.ok(KEY in h.subsessionSnapshot());
|
||||
Assert.equal(h.snapshot(KEY).sum, 1);
|
||||
Assert.equal(h.subsessionSnapshot(KEY).sum, 1);
|
||||
|
||||
// Check that "snapshot and clear" works properly.
|
||||
let snapshot = h.snapshot();
|
||||
let subsession = h.snapshotSubsessionAndClear();
|
||||
Assert.ok(KEY in snapshot);
|
||||
Assert.ok(KEY in subsession);
|
||||
Assert.equal(snapshot[KEY].sum, 1);
|
||||
Assert.equal(subsession[KEY].sum, 1);
|
||||
|
||||
subsession = h.subsessionSnapshot();
|
||||
Assert.ok(!(KEY in subsession));
|
||||
Assert.equal(h.subsessionSnapshot(KEY).sum, 0);
|
||||
}
|
||||
|
||||
function generateUUID() {
|
||||
let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
|
||||
// strip {}
|
||||
@@ -640,4 +768,6 @@ function run_test()
|
||||
test_expired_histogram();
|
||||
test_keyed_histogram();
|
||||
test_datasets();
|
||||
test_subsession();
|
||||
test_keyed_subsession();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ tail =
|
||||
skip-if = toolkit == 'gonk'
|
||||
|
||||
[test_nsITelemetry.js]
|
||||
[test_TelemetryEnvironment.js]
|
||||
[test_TelemetryFlagClear.js]
|
||||
[test_TelemetryLateWrites.js]
|
||||
[test_TelemetryLockCount.js]
|
||||
@@ -17,5 +18,6 @@ skip-if = toolkit == 'gonk'
|
||||
[test_ThirdPartyCookieProbe.js]
|
||||
[test_TelemetrySendOldPings.js]
|
||||
skip-if = debug == true || os == "android" # Disabled due to intermittent orange on Android
|
||||
[test_TelemetrySession.js]
|
||||
[test_ThreadHangStats.js]
|
||||
run-sequentially = Bug 1046307, test can fail intermittently when CPU load is high
|
||||
|
||||
@@ -389,7 +389,7 @@ void
|
||||
nsTerminator::StartWriter()
|
||||
{
|
||||
|
||||
if (!Telemetry::CanRecord()) {
|
||||
if (!Telemetry::CanRecordExtended()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIFile> profLD;
|
||||
@@ -473,7 +473,7 @@ nsTerminator::UpdateHeartbeat(const char* aTopic)
|
||||
void
|
||||
nsTerminator::UpdateTelemetry()
|
||||
{
|
||||
if (!Telemetry::CanRecord() || !gWriteReady) {
|
||||
if (!Telemetry::CanRecordExtended() || !gWriteReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ add_task(function* actualTest() {
|
||||
do_check_true(simpleMeasurements.bar > 1); // bar was included
|
||||
do_check_eq(undefined, simpleMeasurements.baz); // baz wasn't included since it wasn't added
|
||||
|
||||
yield TelemetrySession.shutdown();
|
||||
yield TelemetrySession.shutdown(false);
|
||||
|
||||
do_test_finished();
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user