Bug 1688354 [wpt PR 27298] - Treat 'rem' as an absolute unit for font size, a=testonly
[gecko.git] / dom / cache / CacheOpParent.cpp
blob55ffa402b57d4ab77b642893e024db261a4d4de3
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/. */
7 #include "mozilla/dom/cache/CacheOpParent.h"
9 #include "mozilla/StaticPrefs_browser.h"
10 #include "mozilla/Unused.h"
11 #include "mozilla/dom/cache/AutoUtils.h"
12 #include "mozilla/dom/cache/ManagerId.h"
13 #include "mozilla/dom/cache/ReadStream.h"
14 #include "mozilla/dom/cache/SavedTypes.h"
15 #include "mozilla/ipc/FileDescriptorSetParent.h"
16 #include "mozilla/ipc/InputStreamUtils.h"
17 #include "mozilla/ipc/IPCStreamUtils.h"
19 namespace mozilla::dom::cache {
21 using mozilla::ipc::FileDescriptorSetParent;
22 using mozilla::ipc::PBackgroundParent;
24 CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager, CacheId aCacheId,
25 const CacheOpArgs& aOpArgs)
26 : mIpcManager(aIpcManager),
27 mCacheId(aCacheId),
28 mNamespace(INVALID_NAMESPACE),
29 mOpArgs(aOpArgs) {
30 MOZ_DIAGNOSTIC_ASSERT(mIpcManager);
33 CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager,
34 Namespace aNamespace, const CacheOpArgs& aOpArgs)
35 : mIpcManager(aIpcManager),
36 mCacheId(INVALID_CACHE_ID),
37 mNamespace(aNamespace),
38 mOpArgs(aOpArgs) {
39 MOZ_DIAGNOSTIC_ASSERT(mIpcManager);
42 CacheOpParent::~CacheOpParent() { NS_ASSERT_OWNINGTHREAD(CacheOpParent); }
44 void CacheOpParent::Execute(const SafeRefPtr<ManagerId>& aManagerId) {
45 NS_ASSERT_OWNINGTHREAD(CacheOpParent);
46 MOZ_DIAGNOSTIC_ASSERT(!mManager);
47 MOZ_DIAGNOSTIC_ASSERT(!mVerifier);
49 auto managerOrErr = cache::Manager::AcquireCreateIfNonExistent(aManagerId);
50 if (NS_WARN_IF(managerOrErr.isErr())) {
51 ErrorResult result(managerOrErr.unwrapErr());
52 Unused << Send__delete__(this, std::move(result), void_t());
53 return;
56 Execute(managerOrErr.unwrap());
59 void CacheOpParent::Execute(SafeRefPtr<cache::Manager> aManager) {
60 NS_ASSERT_OWNINGTHREAD(CacheOpParent);
61 MOZ_DIAGNOSTIC_ASSERT(!mManager);
62 MOZ_DIAGNOSTIC_ASSERT(!mVerifier);
64 mManager = std::move(aManager);
66 // Handle put op
67 if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
68 MOZ_DIAGNOSTIC_ASSERT(mCacheId != INVALID_CACHE_ID);
70 const CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
71 const nsTArray<CacheRequestResponse>& list = args.requestResponseList();
73 AutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
74 AutoTArray<nsCOMPtr<nsIInputStream>, 256> responseStreamList;
76 for (uint32_t i = 0; i < list.Length(); ++i) {
77 requestStreamList.AppendElement(
78 DeserializeCacheStream(list[i].request().body()));
79 responseStreamList.AppendElement(
80 DeserializeCacheStream(list[i].response().body()));
83 mManager->ExecutePutAll(this, mCacheId, args.requestResponseList(),
84 requestStreamList, responseStreamList);
85 return;
88 // Handle all other cache ops
89 if (mCacheId != INVALID_CACHE_ID) {
90 MOZ_DIAGNOSTIC_ASSERT(mNamespace == INVALID_NAMESPACE);
91 mManager->ExecuteCacheOp(this, mCacheId, mOpArgs);
92 return;
95 // Handle all storage ops
96 MOZ_DIAGNOSTIC_ASSERT(mNamespace != INVALID_NAMESPACE);
97 mManager->ExecuteStorageOp(this, mNamespace, mOpArgs);
100 void CacheOpParent::WaitForVerification(PrincipalVerifier* aVerifier) {
101 NS_ASSERT_OWNINGTHREAD(CacheOpParent);
102 MOZ_DIAGNOSTIC_ASSERT(!mManager);
103 MOZ_DIAGNOSTIC_ASSERT(!mVerifier);
105 mVerifier = aVerifier;
106 mVerifier->AddListener(*this);
109 void CacheOpParent::ActorDestroy(ActorDestroyReason aReason) {
110 NS_ASSERT_OWNINGTHREAD(CacheOpParent);
112 if (mVerifier) {
113 mVerifier->RemoveListener(*this);
114 mVerifier = nullptr;
117 if (mManager) {
118 mManager->RemoveListener(this);
119 mManager = nullptr;
122 mIpcManager = nullptr;
125 void CacheOpParent::OnPrincipalVerified(
126 nsresult aRv, const SafeRefPtr<ManagerId>& aManagerId) {
127 NS_ASSERT_OWNINGTHREAD(CacheOpParent);
129 mVerifier->RemoveListener(*this);
130 mVerifier = nullptr;
132 if (NS_WARN_IF(NS_FAILED(aRv))) {
133 ErrorResult result(aRv);
134 Unused << Send__delete__(this, std::move(result), void_t());
135 return;
138 Execute(aManagerId);
141 void CacheOpParent::OnOpComplete(ErrorResult&& aRv,
142 const CacheOpResult& aResult,
143 CacheId aOpenedCacheId,
144 const Maybe<StreamInfo>& aStreamInfo) {
145 NS_ASSERT_OWNINGTHREAD(CacheOpParent);
146 MOZ_DIAGNOSTIC_ASSERT(mIpcManager);
147 MOZ_DIAGNOSTIC_ASSERT(mManager);
149 // Never send an op-specific result if we have an error. Instead, send
150 // void_t() to ensure that we don't leak actors on the child side.
151 if (NS_WARN_IF(aRv.Failed())) {
152 Unused << Send__delete__(this, std::move(aRv), void_t());
153 return;
156 if (aStreamInfo.isSome()) {
157 ProcessCrossOriginResourcePolicyHeader(aRv,
158 aStreamInfo->mSavedResponseList);
159 if (NS_WARN_IF(aRv.Failed())) {
160 Unused << Send__delete__(this, std::move(aRv), void_t());
161 return;
165 uint32_t entryCount =
166 std::max(1lu, aStreamInfo ? static_cast<unsigned long>(std::max(
167 aStreamInfo->mSavedResponseList.Length(),
168 aStreamInfo->mSavedRequestList.Length()))
169 : 0lu);
171 // The result must contain the appropriate type at this point. It may
172 // or may not contain the additional result data yet. For types that
173 // do not need special processing, it should already be set. If the
174 // result requires actor-specific operations, then we do that below.
175 // If the type and data types don't match, then we will trigger an
176 // assertion in AutoParentOpResult::Add().
177 AutoParentOpResult result(mIpcManager, aResult, entryCount);
179 if (aOpenedCacheId != INVALID_CACHE_ID) {
180 result.Add(aOpenedCacheId, mManager.clonePtr());
183 if (aStreamInfo) {
184 const auto& streamInfo = *aStreamInfo;
186 for (const auto& savedResponse : streamInfo.mSavedResponseList) {
187 result.Add(savedResponse, streamInfo.mStreamList);
190 for (const auto& savedRequest : streamInfo.mSavedRequestList) {
191 result.Add(savedRequest, streamInfo.mStreamList);
195 Unused << Send__delete__(this, std::move(aRv), result.SendAsOpResult());
198 already_AddRefed<nsIInputStream> CacheOpParent::DeserializeCacheStream(
199 const Maybe<CacheReadStream>& aMaybeStream) {
200 if (aMaybeStream.isNothing()) {
201 return nullptr;
204 nsCOMPtr<nsIInputStream> stream;
205 const CacheReadStream& readStream = aMaybeStream.ref();
207 // Option 1: One of our own ReadStreams was passed back to us with a stream
208 // control actor.
209 stream = ReadStream::Create(readStream);
210 if (stream) {
211 return stream.forget();
214 // Option 2: A stream was serialized using normal methods or passed
215 // as a PChildToParentStream actor. Use the standard method for
216 // extracting the resulting stream.
217 return DeserializeIPCStream(readStream.stream());
220 void CacheOpParent::ProcessCrossOriginResourcePolicyHeader(
221 ErrorResult& aRv, const nsTArray<SavedResponse>& aResponses) {
222 if (!StaticPrefs::browser_tabs_remote_useCrossOriginEmbedderPolicy()) {
223 return;
225 // Only checking for match/matchAll.
226 nsILoadInfo::CrossOriginEmbedderPolicy loadingCOEP =
227 nsILoadInfo::EMBEDDER_POLICY_NULL;
228 Maybe<PrincipalInfo> principalInfo;
229 switch (mOpArgs.type()) {
230 case CacheOpArgs::TCacheMatchArgs: {
231 loadingCOEP =
232 mOpArgs.get_CacheMatchArgs().request().loadingEmbedderPolicy();
233 principalInfo = mOpArgs.get_CacheMatchArgs().request().principalInfo();
234 break;
236 case CacheOpArgs::TCacheMatchAllArgs: {
237 if (mOpArgs.get_CacheMatchAllArgs().maybeRequest().isSome()) {
238 loadingCOEP = mOpArgs.get_CacheMatchAllArgs()
239 .maybeRequest()
240 .ref()
241 .loadingEmbedderPolicy();
242 principalInfo = mOpArgs.get_CacheMatchAllArgs()
243 .maybeRequest()
244 .ref()
245 .principalInfo();
247 break;
249 default: {
250 return;
254 // skip checking if the request has no principal for same-origin/same-site
255 // checking.
256 if (principalInfo.isNothing() ||
257 principalInfo.ref().type() != PrincipalInfo::TContentPrincipalInfo) {
258 return;
260 const ContentPrincipalInfo& contentPrincipalInfo =
261 principalInfo.ref().get_ContentPrincipalInfo();
263 for (auto it = aResponses.cbegin(); it != aResponses.cend(); ++it) {
264 if (it->mValue.type() != ResponseType::Opaque &&
265 it->mValue.type() != ResponseType::Opaqueredirect) {
266 continue;
269 const auto& headers = it->mValue.headers();
270 const auto corpHeaderIt =
271 std::find_if(headers.cbegin(), headers.cend(), [](const auto& header) {
272 return header.name().EqualsLiteral("Cross-Origin-Resource-Policy");
275 // According to https://github.com/w3c/ServiceWorker/issues/1490, the cache
276 // response is expected with CORP header, otherwise, throw the type error.
277 // Note that this is different with the CORP checking for fetch metioned in
278 // https://wicg.github.io/cross-origin-embedder-policy/#corp-check.
279 // For fetch, if the response has no CORP header, "same-origin" checking
280 // will be performed.
281 if (corpHeaderIt == headers.cend() &&
282 loadingCOEP == nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP) {
283 aRv.ThrowTypeError("Response is expected with CORP header.");
284 return;
287 // Skip the case if the response has no principal for same-origin/same-site
288 // checking.
289 if (it->mValue.principalInfo().isNothing() ||
290 it->mValue.principalInfo().ref().type() !=
291 PrincipalInfo::TContentPrincipalInfo) {
292 continue;
295 const ContentPrincipalInfo& responseContentPrincipalInfo =
296 it->mValue.principalInfo().ref().get_ContentPrincipalInfo();
298 const auto& corp =
299 corpHeaderIt == headers.cend() ? EmptyCString() : corpHeaderIt->value();
301 if (corp.EqualsLiteral("same-origin")) {
302 if (responseContentPrincipalInfo == contentPrincipalInfo) {
303 aRv.ThrowTypeError("Response is expected from same origin.");
304 return;
306 } else if (corp.EqualsLiteral("same-site")) {
307 if (!responseContentPrincipalInfo.baseDomain().Equals(
308 contentPrincipalInfo.baseDomain())) {
309 aRv.ThrowTypeError("Response is expected from same site.");
310 return;
316 } // namespace mozilla::dom::cache