Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_SyncedContextInlines_h
8
#define mozilla_dom_SyncedContextInlines_h
9
10
#include "mozilla/dom/SyncedContext.h"
11
#include "mozilla/dom/BrowsingContextGroup.h"
12
#include "mozilla/dom/ContentParent.h"
13
#include "mozilla/dom/ContentChild.h"
14
15
namespace mozilla {
16
namespace dom {
17
namespace syncedcontext {
18
19
template <typename Context>
20
static nsCString FormatValidationError(IndexSet aFailedFields,
21
const char* prefix) {
22
MOZ_ASSERT(!aFailedFields.isEmpty());
23
nsCString error(prefix);
24
bool first = true;
25
for (auto idx : aFailedFields) {
26
if (!first) {
27
error.Append(", ");
28
}
29
first = false;
30
error.Append(Context::FieldIndexToName(idx));
31
}
32
return error;
33
}
34
35
template <typename Context>
36
nsresult Transaction<Context>::Commit(Context* aOwner) {
37
if (NS_WARN_IF(aOwner->IsDiscarded())) {
38
return NS_ERROR_FAILURE;
39
}
40
41
IndexSet failedFields = Validate(aOwner, nullptr);
42
if (!failedFields.isEmpty()) {
43
nsCString error = FormatValidationError<Context>(
44
failedFields, "CanSet failed for field(s): ");
45
MOZ_CRASH_UNSAFE_PRINTF("%s", error.get());
46
}
47
48
if (XRE_IsContentProcess()) {
49
ContentChild* cc = ContentChild::GetSingleton();
50
51
// Increment the field epoch for fields affected by this transaction.
52
uint64_t epoch = cc->NextBrowsingContextFieldEpoch();
53
EachIndex([&](auto idx) {
54
if (GetAt(idx, mMaybeFields)) {
55
GetAt(idx, GetFieldStorage(aOwner).mEpochs) = epoch;
56
}
57
});
58
59
// Tell our derived class to send the correct "Commit" IPC message.
60
aOwner->SendCommitTransaction(cc, *this, epoch);
61
} else {
62
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
63
64
// Tell our derived class to send the correct "Commit" IPC messages.
65
BrowsingContextGroup* group = aOwner->Group();
66
group->EachParent([&](ContentParent* aParent) {
67
aOwner->SendCommitTransaction(aParent, *this,
68
aParent->GetBrowsingContextFieldEpoch());
69
});
70
}
71
72
Apply(aOwner);
73
return NS_OK;
74
}
75
76
template <typename Context>
77
mozilla::ipc::IPCResult Transaction<Context>::CommitFromIPC(
78
const MaybeDiscarded<Context>& aOwner, ContentParent* aSource) {
79
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
80
if (aOwner.IsNullOrDiscarded()) {
81
MOZ_LOG(Context::GetLog(), LogLevel::Debug,
82
("IPC: Trying to send a message to dead or detached context"));
83
return IPC_OK();
84
}
85
Context* owner = aOwner.get();
86
87
// Validate that the set from content is allowed before continuing.
88
IndexSet failedFields = Validate(owner, aSource);
89
if (!failedFields.isEmpty()) {
90
nsCString error = FormatValidationError<Context>(
91
failedFields,
92
"Invalid Transaction from Child - CanSet failed for field(s): ");
93
return IPC_FAIL(aSource, error.get());
94
}
95
96
BrowsingContextGroup* group = owner->Group();
97
group->EachOtherParent(aSource, [&](ContentParent* aParent) {
98
owner->SendCommitTransaction(aParent, *this,
99
aParent->GetBrowsingContextFieldEpoch());
100
});
101
102
Apply(owner);
103
return IPC_OK();
104
}
105
106
template <typename Context>
107
mozilla::ipc::IPCResult Transaction<Context>::CommitFromIPC(
108
const MaybeDiscarded<Context>& aOwner, uint64_t aEpoch,
109
ContentChild* aSource) {
110
MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess());
111
if (aOwner.IsNullOrDiscarded()) {
112
MOZ_LOG(Context::GetLog(), LogLevel::Debug,
113
("ChildIPC: Trying to send a message to dead or detached context"));
114
return IPC_OK();
115
}
116
Context* owner = aOwner.get();
117
118
// Clear any fields which have been obsoleted by the epoch.
119
EachIndex([&](auto idx) {
120
auto& field = GetAt(idx, mMaybeFields);
121
if (field && GetAt(idx, GetFieldStorage(owner).mEpochs) > aEpoch) {
122
field.reset();
123
}
124
});
125
126
Apply(owner);
127
return IPC_OK();
128
}
129
130
template <typename Context>
131
void Transaction<Context>::Apply(Context* aOwner) {
132
EachIndex([&](auto idx) {
133
if (auto& txnField = GetAt(idx, mMaybeFields)) {
134
GetAt(idx, GetFieldStorage(aOwner).mFields) = std::move(*txnField);
135
aOwner->DidSet(idx);
136
txnField.reset();
137
}
138
});
139
}
140
141
template <typename Context>
142
IndexSet Transaction<Context>::Validate(Context* aOwner,
143
ContentParent* aSource) {
144
IndexSet failedFields;
145
// Validate that the set from content is allowed before continuing.
146
EachIndex([&](auto idx) {
147
const auto& field = GetAt(idx, mMaybeFields);
148
if (field && NS_WARN_IF(!aOwner->CanSet(idx, *field, aSource))) {
149
failedFields += idx;
150
}
151
});
152
return failedFields;
153
}
154
155
template <typename Context>
156
void Transaction<Context>::Write(IPC::Message* aMsg,
157
mozilla::ipc::IProtocol* aActor) const {
158
WriteIPDLParam(aMsg, aActor, mMaybeFields);
159
}
160
161
template <typename Context>
162
bool Transaction<Context>::Read(const IPC::Message* aMsg, PickleIterator* aIter,
163
mozilla::ipc::IProtocol* aActor) {
164
return ReadIPDLParam(aMsg, aIter, aActor, &mMaybeFields);
165
}
166
167
} // namespace syncedcontext
168
} // namespace dom
169
} // namespace mozilla
170
171
#endif // !defined(mozilla_dom_SyncedContextInlines_h)