/src/mozilla-central/dom/cache/AutoUtils.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "mozilla/dom/cache/AutoUtils.h" |
8 | | |
9 | | #include "mozilla/Unused.h" |
10 | | #include "mozilla/dom/InternalHeaders.h" |
11 | | #include "mozilla/dom/InternalRequest.h" |
12 | | #include "mozilla/dom/cache/CacheParent.h" |
13 | | #include "mozilla/dom/cache/CacheStreamControlParent.h" |
14 | | #include "mozilla/dom/cache/ReadStream.h" |
15 | | #include "mozilla/dom/cache/SavedTypes.h" |
16 | | #include "mozilla/dom/cache/StreamList.h" |
17 | | #include "mozilla/dom/cache/TypeUtils.h" |
18 | | #include "mozilla/ipc/IPCStreamUtils.h" |
19 | | #include "mozilla/ipc/PBackgroundParent.h" |
20 | | #include "nsCRT.h" |
21 | | #include "nsHttp.h" |
22 | | |
23 | | using mozilla::Unused; |
24 | | using mozilla::dom::cache::CacheReadStream; |
25 | | using mozilla::dom::cache::CacheReadStreamOrVoid; |
26 | | using mozilla::ipc::AutoIPCStream; |
27 | | using mozilla::ipc::PBackgroundParent; |
28 | | |
29 | | namespace { |
30 | | |
31 | | enum CleanupAction |
32 | | { |
33 | | Forget, |
34 | | Delete |
35 | | }; |
36 | | |
37 | | void |
38 | | CleanupChild(CacheReadStream& aReadStream, CleanupAction aAction) |
39 | 0 | { |
40 | 0 | // fds cleaned up by mStreamCleanupList |
41 | 0 | // PChildToParentStream actors cleaned up by mStreamCleanupList |
42 | 0 | } |
43 | | |
44 | | void |
45 | | CleanupChild(CacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction) |
46 | 0 | { |
47 | 0 | if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) { |
48 | 0 | return; |
49 | 0 | } |
50 | 0 | |
51 | 0 | CleanupChild(aReadStreamOrVoid.get_CacheReadStream(), aAction); |
52 | 0 | } |
53 | | |
54 | | } // namespace |
55 | | |
56 | | namespace mozilla { |
57 | | namespace dom { |
58 | | namespace cache { |
59 | | |
60 | | // -------------------------------------------- |
61 | | |
62 | | AutoChildOpArgs::AutoChildOpArgs(TypeUtils* aTypeUtils, |
63 | | const CacheOpArgs& aOpArgs, |
64 | | uint32_t aEntryCount) |
65 | | : mTypeUtils(aTypeUtils) |
66 | | , mOpArgs(aOpArgs) |
67 | | , mSent(false) |
68 | 0 | { |
69 | 0 | MOZ_DIAGNOSTIC_ASSERT(mTypeUtils); |
70 | 0 | MOZ_RELEASE_ASSERT(aEntryCount != 0); |
71 | 0 | // We are using AutoIPCStream objects to cleanup target IPCStream |
72 | 0 | // structures embedded in our CacheOpArgs. These IPCStream structs |
73 | 0 | // must not move once we attach our AutoIPCStream to them. Therefore, |
74 | 0 | // its important that any arrays containing streams are pre-sized for |
75 | 0 | // the number of entries we have in order to avoid realloc moving |
76 | 0 | // things around on us. |
77 | 0 | if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) { |
78 | 0 | CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs(); |
79 | 0 | args.requestResponseList().SetCapacity(aEntryCount); |
80 | 0 | } else { |
81 | 0 | MOZ_DIAGNOSTIC_ASSERT(aEntryCount == 1); |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | AutoChildOpArgs::~AutoChildOpArgs() |
86 | 0 | { |
87 | 0 | CleanupAction action = mSent ? Forget : Delete; |
88 | 0 |
|
89 | 0 | switch(mOpArgs.type()) { |
90 | 0 | case CacheOpArgs::TCacheMatchArgs: |
91 | 0 | { |
92 | 0 | CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs(); |
93 | 0 | CleanupChild(args.request().body(), action); |
94 | 0 | break; |
95 | 0 | } |
96 | 0 | case CacheOpArgs::TCacheMatchAllArgs: |
97 | 0 | { |
98 | 0 | CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs(); |
99 | 0 | if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) { |
100 | 0 | break; |
101 | 0 | } |
102 | 0 | CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action); |
103 | 0 | break; |
104 | 0 | } |
105 | 0 | case CacheOpArgs::TCachePutAllArgs: |
106 | 0 | { |
107 | 0 | CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs(); |
108 | 0 | auto& list = args.requestResponseList(); |
109 | 0 | for (uint32_t i = 0; i < list.Length(); ++i) { |
110 | 0 | CleanupChild(list[i].request().body(), action); |
111 | 0 | CleanupChild(list[i].response().body(), action); |
112 | 0 | } |
113 | 0 | break; |
114 | 0 | } |
115 | 0 | case CacheOpArgs::TCacheDeleteArgs: |
116 | 0 | { |
117 | 0 | CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs(); |
118 | 0 | CleanupChild(args.request().body(), action); |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | case CacheOpArgs::TCacheKeysArgs: |
122 | 0 | { |
123 | 0 | CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs(); |
124 | 0 | if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) { |
125 | 0 | break; |
126 | 0 | } |
127 | 0 | CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action); |
128 | 0 | break; |
129 | 0 | } |
130 | 0 | case CacheOpArgs::TStorageMatchArgs: |
131 | 0 | { |
132 | 0 | StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs(); |
133 | 0 | CleanupChild(args.request().body(), action); |
134 | 0 | break; |
135 | 0 | } |
136 | 0 | default: |
137 | 0 | // Other types do not need cleanup |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | |
141 | 0 | mStreamCleanupList.Clear(); |
142 | 0 | } |
143 | | |
144 | | void |
145 | | AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction, |
146 | | SchemeAction aSchemeAction, ErrorResult& aRv) |
147 | 0 | { |
148 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
149 | 0 |
|
150 | 0 | switch(mOpArgs.type()) { |
151 | 0 | case CacheOpArgs::TCacheMatchArgs: |
152 | 0 | { |
153 | 0 | CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs(); |
154 | 0 | mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction, |
155 | 0 | aSchemeAction, mStreamCleanupList, aRv); |
156 | 0 | break; |
157 | 0 | } |
158 | 0 | case CacheOpArgs::TCacheMatchAllArgs: |
159 | 0 | { |
160 | 0 | CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs(); |
161 | 0 | MOZ_DIAGNOSTIC_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t); |
162 | 0 | args.requestOrVoid() = CacheRequest(); |
163 | 0 | mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(), |
164 | 0 | aRequest, aBodyAction, aSchemeAction, |
165 | 0 | mStreamCleanupList, aRv); |
166 | 0 | break; |
167 | 0 | } |
168 | 0 | case CacheOpArgs::TCacheDeleteArgs: |
169 | 0 | { |
170 | 0 | CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs(); |
171 | 0 | mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction, |
172 | 0 | aSchemeAction, mStreamCleanupList, aRv); |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | case CacheOpArgs::TCacheKeysArgs: |
176 | 0 | { |
177 | 0 | CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs(); |
178 | 0 | MOZ_DIAGNOSTIC_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t); |
179 | 0 | args.requestOrVoid() = CacheRequest(); |
180 | 0 | mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(), |
181 | 0 | aRequest, aBodyAction, aSchemeAction, |
182 | 0 | mStreamCleanupList, aRv); |
183 | 0 | break; |
184 | 0 | } |
185 | 0 | case CacheOpArgs::TStorageMatchArgs: |
186 | 0 | { |
187 | 0 | StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs(); |
188 | 0 | mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction, |
189 | 0 | aSchemeAction, mStreamCleanupList, aRv); |
190 | 0 | break; |
191 | 0 | } |
192 | 0 | default: |
193 | 0 | MOZ_CRASH("Cache args type cannot send a Request!"); |
194 | 0 | } |
195 | 0 | } |
196 | | |
197 | | namespace { |
198 | | |
199 | | bool |
200 | | MatchInPutList(InternalRequest* aRequest, |
201 | | const nsTArray<CacheRequestResponse>& aPutList) |
202 | 0 | { |
203 | 0 | MOZ_DIAGNOSTIC_ASSERT(aRequest); |
204 | 0 |
|
205 | 0 | // This method implements the SW spec QueryCache algorithm against an |
206 | 0 | // in memory array of Request/Response objects. This essentially the |
207 | 0 | // same algorithm that is implemented in DBSchema.cpp. Unfortunately |
208 | 0 | // we cannot unify them because when operating against the real database |
209 | 0 | // we don't want to load all request/response objects into memory. |
210 | 0 |
|
211 | 0 | // Note, we can skip the check for a invalid request method because |
212 | 0 | // Cache should only call into here with a GET or HEAD. |
213 | | #ifdef DEBUG |
214 | | nsAutoCString method; |
215 | | aRequest->GetMethod(method); |
216 | | MOZ_ASSERT(method.LowerCaseEqualsLiteral("get") || |
217 | | method.LowerCaseEqualsLiteral("head")); |
218 | | #endif |
219 | |
|
220 | 0 | RefPtr<InternalHeaders> requestHeaders = aRequest->Headers(); |
221 | 0 |
|
222 | 0 | for (uint32_t i = 0; i < aPutList.Length(); ++i) { |
223 | 0 | const CacheRequest& cachedRequest = aPutList[i].request(); |
224 | 0 | const CacheResponse& cachedResponse = aPutList[i].response(); |
225 | 0 |
|
226 | 0 | nsAutoCString url; |
227 | 0 | aRequest->GetURL(url); |
228 | 0 |
|
229 | 0 | nsAutoCString requestUrl(cachedRequest.urlWithoutQuery()); |
230 | 0 | requestUrl.Append(cachedRequest.urlQuery()); |
231 | 0 |
|
232 | 0 | // If the URLs don't match, then just skip to the next entry. |
233 | 0 | if (url != requestUrl) { |
234 | 0 | continue; |
235 | 0 | } |
236 | 0 | |
237 | 0 | RefPtr<InternalHeaders> cachedRequestHeaders = |
238 | 0 | TypeUtils::ToInternalHeaders(cachedRequest.headers()); |
239 | 0 |
|
240 | 0 | RefPtr<InternalHeaders> cachedResponseHeaders = |
241 | 0 | TypeUtils::ToInternalHeaders(cachedResponse.headers()); |
242 | 0 |
|
243 | 0 | nsCString varyHeaders; |
244 | 0 | ErrorResult rv; |
245 | 0 | cachedResponseHeaders->Get(NS_LITERAL_CSTRING("vary"), varyHeaders, rv); |
246 | 0 | MOZ_ALWAYS_TRUE(!rv.Failed()); |
247 | 0 |
|
248 | 0 | // Assume the vary headers match until we find a conflict |
249 | 0 | bool varyHeadersMatch = true; |
250 | 0 |
|
251 | 0 | char* rawBuffer = varyHeaders.BeginWriting(); |
252 | 0 | char* token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer); |
253 | 0 | for (; token; |
254 | 0 | token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer)) { |
255 | 0 | nsDependentCString header(token); |
256 | 0 | MOZ_DIAGNOSTIC_ASSERT(!header.EqualsLiteral("*"), |
257 | 0 | "We should have already caught this in " |
258 | 0 | "TypeUtils::ToPCacheResponseWithoutBody()"); |
259 | 0 |
|
260 | 0 | ErrorResult headerRv; |
261 | 0 | nsAutoCString value; |
262 | 0 | requestHeaders->Get(header, value, headerRv); |
263 | 0 | if (NS_WARN_IF(headerRv.Failed())) { |
264 | 0 | headerRv.SuppressException(); |
265 | 0 | MOZ_DIAGNOSTIC_ASSERT(value.IsEmpty()); |
266 | 0 | } |
267 | 0 |
|
268 | 0 | nsAutoCString cachedValue; |
269 | 0 | cachedRequestHeaders->Get(header, cachedValue, headerRv); |
270 | 0 | if (NS_WARN_IF(headerRv.Failed())) { |
271 | 0 | headerRv.SuppressException(); |
272 | 0 | MOZ_DIAGNOSTIC_ASSERT(cachedValue.IsEmpty()); |
273 | 0 | } |
274 | 0 |
|
275 | 0 | if (value != cachedValue) { |
276 | 0 | varyHeadersMatch = false; |
277 | 0 | break; |
278 | 0 | } |
279 | 0 | } |
280 | 0 |
|
281 | 0 | // URL was equal and all vary headers match! |
282 | 0 | if (varyHeadersMatch) { |
283 | 0 | return true; |
284 | 0 | } |
285 | 0 | } |
286 | 0 |
|
287 | 0 | return false; |
288 | 0 | } |
289 | | |
290 | | } // namespace |
291 | | |
292 | | void |
293 | | AutoChildOpArgs::Add(JSContext* aCx, InternalRequest* aRequest, |
294 | | BodyAction aBodyAction, SchemeAction aSchemeAction, |
295 | | Response& aResponse, ErrorResult& aRv) |
296 | 0 | { |
297 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
298 | 0 |
|
299 | 0 | switch(mOpArgs.type()) { |
300 | 0 | case CacheOpArgs::TCachePutAllArgs: |
301 | 0 | { |
302 | 0 | CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs(); |
303 | 0 |
|
304 | 0 | // Throw an error if a request/response pair would mask another |
305 | 0 | // request/response pair in the same PutAll operation. This is |
306 | 0 | // step 2.3.2.3 from the "Batch Cache Operations" spec algorithm. |
307 | 0 | if (MatchInPutList(aRequest, args.requestResponseList())) { |
308 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); |
309 | 0 | return; |
310 | 0 | } |
311 | 0 | |
312 | 0 | // Ensure that we don't realloc the array since this can result |
313 | 0 | // in our AutoIPCStream objects to reference the wrong memory |
314 | 0 | // location. This should never happen and is a UAF if it does. |
315 | 0 | // Therefore make this a release assertion. |
316 | 0 | MOZ_RELEASE_ASSERT(args.requestResponseList().Length() < |
317 | 0 | args.requestResponseList().Capacity()); |
318 | 0 |
|
319 | 0 | // The FileDescriptorSetChild asserts in its destructor that all fds have |
320 | 0 | // been removed. The copy constructor, however, simply duplicates the |
321 | 0 | // fds without removing any. This means each temporary and copy must be |
322 | 0 | // explicitly cleaned up. |
323 | 0 | // |
324 | 0 | // Avoid a lot of this hassle by making sure we only create one here. On |
325 | 0 | // error we remove it. |
326 | 0 | CacheRequestResponse& pair = *args.requestResponseList().AppendElement(); |
327 | 0 | pair.request().body() = void_t(); |
328 | 0 | pair.response().body() = void_t(); |
329 | 0 |
|
330 | 0 | mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction, |
331 | 0 | aSchemeAction, mStreamCleanupList, aRv); |
332 | 0 | if (!aRv.Failed()) { |
333 | 0 | mTypeUtils->ToCacheResponse(aCx, pair.response(), aResponse, |
334 | 0 | mStreamCleanupList, aRv); |
335 | 0 | } |
336 | 0 |
|
337 | 0 | if (aRv.Failed()) { |
338 | 0 | CleanupChild(pair.request().body(), Delete); |
339 | 0 | args.requestResponseList().RemoveElementAt( |
340 | 0 | args.requestResponseList().Length() - 1); |
341 | 0 | } |
342 | 0 |
|
343 | 0 | break; |
344 | 0 | } |
345 | 0 | default: |
346 | 0 | MOZ_CRASH("Cache args type cannot send a Request/Response pair!"); |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | | const CacheOpArgs& |
351 | | AutoChildOpArgs::SendAsOpArgs() |
352 | 0 | { |
353 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
354 | 0 | mSent = true; |
355 | 0 | for (UniquePtr<AutoIPCStream>& autoStream : mStreamCleanupList) { |
356 | 0 | autoStream->TakeOptionalValue(); |
357 | 0 | } |
358 | 0 | return mOpArgs; |
359 | 0 | } |
360 | | |
361 | | // -------------------------------------------- |
362 | | |
363 | | AutoParentOpResult::AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager, |
364 | | const CacheOpResult& aOpResult, |
365 | | uint32_t aEntryCount) |
366 | | : mManager(aManager) |
367 | | , mOpResult(aOpResult) |
368 | | , mStreamControl(nullptr) |
369 | | , mSent(false) |
370 | 0 | { |
371 | 0 | MOZ_DIAGNOSTIC_ASSERT(mManager); |
372 | 0 | MOZ_RELEASE_ASSERT(aEntryCount != 0); |
373 | 0 | // We are using AutoIPCStream objects to cleanup target IPCStream |
374 | 0 | // structures embedded in our CacheOpArgs. These IPCStream structs |
375 | 0 | // must not move once we attach our AutoIPCStream to them. Therefore, |
376 | 0 | // its important that any arrays containing streams are pre-sized for |
377 | 0 | // the number of entries we have in order to avoid realloc moving |
378 | 0 | // things around on us. |
379 | 0 | if (mOpResult.type() == CacheOpResult::TCacheMatchAllResult) { |
380 | 0 | CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult(); |
381 | 0 | result.responseList().SetCapacity(aEntryCount); |
382 | 0 | } else if (mOpResult.type() == CacheOpResult::TCacheKeysResult) { |
383 | 0 | CacheKeysResult& result = mOpResult.get_CacheKeysResult(); |
384 | 0 | result.requestList().SetCapacity(aEntryCount); |
385 | 0 | } else { |
386 | 0 | MOZ_DIAGNOSTIC_ASSERT(aEntryCount == 1); |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | | AutoParentOpResult::~AutoParentOpResult() |
391 | 0 | { |
392 | 0 | CleanupAction action = mSent ? Forget : Delete; |
393 | 0 |
|
394 | 0 | switch (mOpResult.type()) { |
395 | 0 | case CacheOpResult::TStorageOpenResult: |
396 | 0 | { |
397 | 0 | StorageOpenResult& result = mOpResult.get_StorageOpenResult(); |
398 | 0 | if (action == Forget || result.actorParent() == nullptr) { |
399 | 0 | break; |
400 | 0 | } |
401 | 0 | Unused << PCacheParent::Send__delete__(result.actorParent()); |
402 | 0 | break; |
403 | 0 | } |
404 | 0 | default: |
405 | 0 | // other types do not need additional clean up |
406 | 0 | break; |
407 | 0 | } |
408 | 0 | |
409 | 0 | if (action == Delete && mStreamControl) { |
410 | 0 | Unused << PCacheStreamControlParent::Send__delete__(mStreamControl); |
411 | 0 | } |
412 | 0 |
|
413 | 0 | mStreamCleanupList.Clear(); |
414 | 0 | } |
415 | | |
416 | | void |
417 | | AutoParentOpResult::Add(CacheId aOpenedCacheId, Manager* aManager) |
418 | 0 | { |
419 | 0 | MOZ_DIAGNOSTIC_ASSERT(mOpResult.type() == CacheOpResult::TStorageOpenResult); |
420 | 0 | MOZ_DIAGNOSTIC_ASSERT(mOpResult.get_StorageOpenResult().actorParent() == nullptr); |
421 | 0 | mOpResult.get_StorageOpenResult().actorParent() = |
422 | 0 | mManager->SendPCacheConstructor(new CacheParent(aManager, aOpenedCacheId)); |
423 | 0 | } |
424 | | |
425 | | void |
426 | | AutoParentOpResult::Add(const SavedResponse& aSavedResponse, |
427 | | StreamList* aStreamList) |
428 | 0 | { |
429 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
430 | 0 |
|
431 | 0 | switch (mOpResult.type()) { |
432 | 0 | case CacheOpResult::TCacheMatchResult: |
433 | 0 | { |
434 | 0 | CacheMatchResult& result = mOpResult.get_CacheMatchResult(); |
435 | 0 | MOZ_DIAGNOSTIC_ASSERT(result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t); |
436 | 0 | result.responseOrVoid() = aSavedResponse.mValue; |
437 | 0 | SerializeResponseBody(aSavedResponse, aStreamList, |
438 | 0 | &result.responseOrVoid().get_CacheResponse()); |
439 | 0 | break; |
440 | 0 | } |
441 | 0 | case CacheOpResult::TCacheMatchAllResult: |
442 | 0 | { |
443 | 0 | CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult(); |
444 | 0 | // Ensure that we don't realloc the array since this can result |
445 | 0 | // in our AutoIPCStream objects to reference the wrong memory |
446 | 0 | // location. This should never happen and is a UAF if it does. |
447 | 0 | // Therefore make this a release assertion. |
448 | 0 | MOZ_RELEASE_ASSERT(result.responseList().Length() < |
449 | 0 | result.responseList().Capacity()); |
450 | 0 | result.responseList().AppendElement(aSavedResponse.mValue); |
451 | 0 | SerializeResponseBody(aSavedResponse, aStreamList, |
452 | 0 | &result.responseList().LastElement()); |
453 | 0 | break; |
454 | 0 | } |
455 | 0 | case CacheOpResult::TStorageMatchResult: |
456 | 0 | { |
457 | 0 | StorageMatchResult& result = mOpResult.get_StorageMatchResult(); |
458 | 0 | MOZ_DIAGNOSTIC_ASSERT(result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t); |
459 | 0 | result.responseOrVoid() = aSavedResponse.mValue; |
460 | 0 | SerializeResponseBody(aSavedResponse, aStreamList, |
461 | 0 | &result.responseOrVoid().get_CacheResponse()); |
462 | 0 | break; |
463 | 0 | } |
464 | 0 | default: |
465 | 0 | MOZ_CRASH("Cache result type cannot handle returning a Response!"); |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | | void |
470 | | AutoParentOpResult::Add(const SavedRequest& aSavedRequest, |
471 | | StreamList* aStreamList) |
472 | 0 | { |
473 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
474 | 0 |
|
475 | 0 | switch (mOpResult.type()) { |
476 | 0 | case CacheOpResult::TCacheKeysResult: |
477 | 0 | { |
478 | 0 | CacheKeysResult& result = mOpResult.get_CacheKeysResult(); |
479 | 0 | // Ensure that we don't realloc the array since this can result |
480 | 0 | // in our AutoIPCStream objects to reference the wrong memory |
481 | 0 | // location. This should never happen and is a UAF if it does. |
482 | 0 | // Therefore make this a release assertion. |
483 | 0 | MOZ_RELEASE_ASSERT(result.requestList().Length() < |
484 | 0 | result.requestList().Capacity()); |
485 | 0 | result.requestList().AppendElement(aSavedRequest.mValue); |
486 | 0 | CacheRequest& request = result.requestList().LastElement(); |
487 | 0 |
|
488 | 0 | if (!aSavedRequest.mHasBodyId) { |
489 | 0 | request.body() = void_t(); |
490 | 0 | break; |
491 | 0 | } |
492 | 0 | |
493 | 0 | request.body() = CacheReadStream(); |
494 | 0 | SerializeReadStream(aSavedRequest.mBodyId, aStreamList, |
495 | 0 | &request.body().get_CacheReadStream()); |
496 | 0 | break; |
497 | 0 | } |
498 | 0 | default: |
499 | 0 | MOZ_CRASH("Cache result type cannot handle returning a Request!"); |
500 | 0 | } |
501 | 0 | } |
502 | | |
503 | | const CacheOpResult& |
504 | | AutoParentOpResult::SendAsOpResult() |
505 | 0 | { |
506 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
507 | 0 | mSent = true; |
508 | 0 | for (UniquePtr<AutoIPCStream>& autoStream : mStreamCleanupList) { |
509 | 0 | autoStream->TakeOptionalValue(); |
510 | 0 | } |
511 | 0 | return mOpResult; |
512 | 0 | } |
513 | | |
514 | | void |
515 | | AutoParentOpResult::SerializeResponseBody(const SavedResponse& aSavedResponse, |
516 | | StreamList* aStreamList, |
517 | | CacheResponse* aResponseOut) |
518 | 0 | { |
519 | 0 | MOZ_DIAGNOSTIC_ASSERT(aResponseOut); |
520 | 0 |
|
521 | 0 | if (!aSavedResponse.mHasBodyId) { |
522 | 0 | aResponseOut->body() = void_t(); |
523 | 0 | return; |
524 | 0 | } |
525 | 0 | |
526 | 0 | aResponseOut->body() = CacheReadStream(); |
527 | 0 | SerializeReadStream(aSavedResponse.mBodyId, aStreamList, |
528 | 0 | &aResponseOut->body().get_CacheReadStream()); |
529 | 0 | } |
530 | | |
531 | | void |
532 | | AutoParentOpResult::SerializeReadStream(const nsID& aId, StreamList* aStreamList, |
533 | | CacheReadStream* aReadStreamOut) |
534 | 0 | { |
535 | 0 | MOZ_DIAGNOSTIC_ASSERT(aStreamList); |
536 | 0 | MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut); |
537 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mSent); |
538 | 0 |
|
539 | 0 | nsCOMPtr<nsIInputStream> stream = aStreamList->Extract(aId); |
540 | 0 |
|
541 | 0 | if (!mStreamControl) { |
542 | 0 | mStreamControl = static_cast<CacheStreamControlParent*>( |
543 | 0 | mManager->SendPCacheStreamControlConstructor(new CacheStreamControlParent())); |
544 | 0 |
|
545 | 0 | // If this failed, then the child process is gone. Warn and allow actor |
546 | 0 | // cleanup to proceed as normal. |
547 | 0 | if (!mStreamControl) { |
548 | 0 | NS_WARNING("Cache failed to create stream control actor."); |
549 | 0 | return; |
550 | 0 | } |
551 | 0 | } |
552 | 0 |
|
553 | 0 | aStreamList->SetStreamControl(mStreamControl); |
554 | 0 |
|
555 | 0 | RefPtr<ReadStream> readStream = ReadStream::Create(mStreamControl, |
556 | 0 | aId, stream); |
557 | 0 | ErrorResult rv; |
558 | 0 | readStream->Serialize(aReadStreamOut, mStreamCleanupList, rv); |
559 | 0 | MOZ_DIAGNOSTIC_ASSERT(!rv.Failed()); |
560 | 0 | } |
561 | | |
562 | | } // namespace cache |
563 | | } // namespace dom |
564 | | } // namespace mozilla |