/src/mozilla-central/dom/simpledb/ActorsParent.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 file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "ActorsParent.h" |
8 | | |
9 | | #include "mozilla/Unused.h" |
10 | | #include "mozilla/dom/PBackgroundSDBConnectionParent.h" |
11 | | #include "mozilla/dom/PBackgroundSDBRequestParent.h" |
12 | | #include "mozilla/dom/quota/Client.h" |
13 | | #include "mozilla/dom/quota/FileStreams.h" |
14 | | #include "mozilla/dom/quota/MemoryOutputStream.h" |
15 | | #include "mozilla/dom/quota/QuotaManager.h" |
16 | | #include "mozilla/dom/quota/UsageInfo.h" |
17 | | #include "mozilla/ipc/BackgroundParent.h" |
18 | | #include "mozilla/ipc/PBackgroundParent.h" |
19 | | #include "mozilla/ipc/PBackgroundSharedTypes.h" |
20 | | #include "nsIFileStreams.h" |
21 | | #include "nsIDirectoryEnumerator.h" |
22 | | #include "nsStringStream.h" |
23 | | #include "prio.h" |
24 | | #include "SimpleDBCommon.h" |
25 | | |
26 | | #define DISABLE_ASSERTS_FOR_FUZZING 0 |
27 | | |
28 | | #if DISABLE_ASSERTS_FOR_FUZZING |
29 | | #define ASSERT_UNLESS_FUZZING(...) do { } while (0) |
30 | | #else |
31 | 0 | #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__) |
32 | | #endif |
33 | | |
34 | | namespace mozilla { |
35 | | namespace dom { |
36 | | |
37 | | using namespace mozilla::dom::quota; |
38 | | using namespace mozilla::ipc; |
39 | | |
40 | | namespace { |
41 | | |
42 | | /******************************************************************************* |
43 | | * Constants |
44 | | ******************************************************************************/ |
45 | | |
46 | | const uint32_t kCopyBufferSize = 32768; |
47 | | |
48 | | /******************************************************************************* |
49 | | * Actor class declarations |
50 | | ******************************************************************************/ |
51 | | |
52 | | class StreamHelper final |
53 | | : public Runnable |
54 | | { |
55 | | nsCOMPtr<nsIEventTarget> mOwningEventTarget; |
56 | | nsCOMPtr<nsIFileStream> mFileStream; |
57 | | nsCOMPtr<nsIRunnable> mCallback; |
58 | | |
59 | | public: |
60 | | StreamHelper(nsIFileStream* aFileStream, |
61 | | nsIRunnable* aCallback); |
62 | | |
63 | | void |
64 | | AsyncClose(); |
65 | | |
66 | | private: |
67 | | ~StreamHelper() override; |
68 | | |
69 | | void |
70 | | RunOnBackgroundThread(); |
71 | | |
72 | | void |
73 | | RunOnIOThread(); |
74 | | |
75 | | NS_DECL_NSIRUNNABLE |
76 | | }; |
77 | | |
78 | | class Connection final |
79 | | : public PBackgroundSDBConnectionParent |
80 | | { |
81 | | RefPtr<DirectoryLock> mDirectoryLock; |
82 | | nsCOMPtr<nsIFileStream> mFileStream; |
83 | | const PrincipalInfo mPrincipalInfo; |
84 | | nsCString mOrigin; |
85 | | nsString mName; |
86 | | |
87 | | bool mRunningRequest; |
88 | | bool mOpen; |
89 | | bool mAllowedToClose; |
90 | | bool mActorDestroyed; |
91 | | |
92 | | public: |
93 | | explicit Connection(const PrincipalInfo& aPrincipalInfo); |
94 | | |
95 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::Connection) |
96 | | |
97 | | nsIFileStream* |
98 | | GetFileStream() const |
99 | 0 | { |
100 | 0 | AssertIsOnIOThread(); |
101 | 0 |
|
102 | 0 | return mFileStream; |
103 | 0 | } |
104 | | |
105 | | const PrincipalInfo& |
106 | | GetPrincipalInfo() const |
107 | 0 | { |
108 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
109 | 0 |
|
110 | 0 | return mPrincipalInfo; |
111 | 0 | } |
112 | | |
113 | | const nsCString& |
114 | | Origin() const |
115 | 0 | { |
116 | 0 | AssertIsOnBackgroundThread(); |
117 | 0 | MOZ_ASSERT(!mOrigin.IsEmpty()); |
118 | 0 |
|
119 | 0 | return mOrigin; |
120 | 0 | } |
121 | | |
122 | | const nsString& |
123 | | Name() const |
124 | 0 | { |
125 | 0 | AssertIsOnBackgroundThread(); |
126 | 0 | MOZ_ASSERT(!mName.IsEmpty()); |
127 | 0 |
|
128 | 0 | return mName; |
129 | 0 | } |
130 | | |
131 | | void |
132 | | OnNewRequest(); |
133 | | |
134 | | void |
135 | | OnRequestFinished(); |
136 | | |
137 | | void |
138 | | OnOpen(const nsACString& aOrigin, |
139 | | const nsAString& aName, |
140 | | already_AddRefed<DirectoryLock> aDirectoryLock, |
141 | | already_AddRefed<nsIFileStream> aFileStream); |
142 | | |
143 | | void |
144 | | OnClose(); |
145 | | |
146 | | void |
147 | | AllowToClose(); |
148 | | |
149 | | private: |
150 | | ~Connection(); |
151 | | |
152 | | void |
153 | | MaybeCloseStream(); |
154 | | |
155 | | bool |
156 | | VerifyRequestParams(const SDBRequestParams& aParams) const; |
157 | | |
158 | | // IPDL methods. |
159 | | virtual void |
160 | | ActorDestroy(ActorDestroyReason aWhy) override; |
161 | | |
162 | | mozilla::ipc::IPCResult |
163 | | RecvDeleteMe() override; |
164 | | |
165 | | virtual PBackgroundSDBRequestParent* |
166 | | AllocPBackgroundSDBRequestParent(const SDBRequestParams& aParams) override; |
167 | | |
168 | | virtual mozilla::ipc::IPCResult |
169 | | RecvPBackgroundSDBRequestConstructor(PBackgroundSDBRequestParent* aActor, |
170 | | const SDBRequestParams& aParams) |
171 | | override; |
172 | | |
173 | | virtual bool |
174 | | DeallocPBackgroundSDBRequestParent(PBackgroundSDBRequestParent* aActor) |
175 | | override; |
176 | | }; |
177 | | |
178 | | class ConnectionOperationBase |
179 | | : public Runnable |
180 | | , public PBackgroundSDBRequestParent |
181 | | { |
182 | | nsCOMPtr<nsIEventTarget> mOwningEventTarget; |
183 | | RefPtr<Connection> mConnection; |
184 | | nsresult mResultCode; |
185 | | Atomic<bool> mOperationMayProceed; |
186 | | bool mActorDestroyed; |
187 | | |
188 | | public: |
189 | | nsIEventTarget* |
190 | | OwningEventTarget() const |
191 | 0 | { |
192 | 0 | MOZ_ASSERT(mOwningEventTarget); |
193 | 0 |
|
194 | 0 | return mOwningEventTarget; |
195 | 0 | } |
196 | | |
197 | | bool |
198 | | IsOnOwningThread() const |
199 | 0 | { |
200 | 0 | MOZ_ASSERT(mOwningEventTarget); |
201 | 0 |
|
202 | 0 | bool current; |
203 | 0 | return |
204 | 0 | NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(¤t)) && current; |
205 | 0 | } |
206 | | |
207 | | void |
208 | | AssertIsOnOwningThread() const |
209 | 0 | { |
210 | 0 | MOZ_ASSERT(IsOnBackgroundThread()); |
211 | 0 | MOZ_ASSERT(IsOnOwningThread()); |
212 | 0 | } |
213 | | |
214 | | Connection* |
215 | | GetConnection() const |
216 | 0 | { |
217 | 0 | MOZ_ASSERT(mConnection); |
218 | 0 |
|
219 | 0 | return mConnection; |
220 | 0 | } |
221 | | |
222 | | nsresult |
223 | | ResultCode() const |
224 | 0 | { |
225 | 0 | return mResultCode; |
226 | 0 | } |
227 | | |
228 | | void |
229 | | MaybeSetFailureCode(nsresult aErrorCode) |
230 | 0 | { |
231 | 0 | MOZ_ASSERT(NS_FAILED(aErrorCode)); |
232 | 0 |
|
233 | 0 | if (NS_SUCCEEDED(mResultCode)) { |
234 | 0 | mResultCode = aErrorCode; |
235 | 0 | } |
236 | 0 | } |
237 | | |
238 | | // May be called on any thread, but you should call IsActorDestroyed() if |
239 | | // you know you're on the background thread because it is slightly faster. |
240 | | bool |
241 | | OperationMayProceed() const |
242 | 0 | { |
243 | 0 | return mOperationMayProceed; |
244 | 0 | } |
245 | | |
246 | | bool |
247 | | IsActorDestroyed() const |
248 | 0 | { |
249 | 0 | AssertIsOnOwningThread(); |
250 | 0 |
|
251 | 0 | return mActorDestroyed; |
252 | 0 | } |
253 | | |
254 | | // May be overridden by subclasses if they need to perform work on the |
255 | | // background thread before being dispatched but must always call the base |
256 | | // class implementation. Returning false will kill the child actors and |
257 | | // prevent dispatch. |
258 | | virtual bool |
259 | | Init(); |
260 | | |
261 | | virtual nsresult |
262 | | Dispatch(); |
263 | | |
264 | | // This callback will be called on the background thread before releasing the |
265 | | // final reference to this request object. Subclasses may perform any |
266 | | // additional cleanup here but must always call the base class implementation. |
267 | | virtual void |
268 | | Cleanup(); |
269 | | |
270 | | protected: |
271 | | ConnectionOperationBase(Connection* aConnection) |
272 | | : Runnable("dom::ConnectionOperationBase") |
273 | | , mOwningEventTarget(GetCurrentThreadEventTarget()) |
274 | | , mConnection(aConnection) |
275 | | , mResultCode(NS_OK) |
276 | | , mOperationMayProceed(true) |
277 | | , mActorDestroyed(false) |
278 | 0 | { |
279 | 0 | AssertIsOnOwningThread(); |
280 | 0 | } |
281 | | |
282 | | ~ConnectionOperationBase() override; |
283 | | |
284 | | void |
285 | | SendResults(); |
286 | | |
287 | | void |
288 | | DatabaseWork(); |
289 | | |
290 | | // Methods that subclasses must implement. |
291 | | virtual nsresult |
292 | | DoDatabaseWork(nsIFileStream* aFileStream) = 0; |
293 | | |
294 | | // Subclasses use this override to set the IPDL response value. |
295 | | virtual void |
296 | | GetResponse(SDBRequestResponse& aResponse) = 0; |
297 | | |
298 | | // A method that subclasses may implement. |
299 | | virtual void |
300 | | OnSuccess(); |
301 | | |
302 | | private: |
303 | | NS_IMETHOD |
304 | | Run() override; |
305 | | |
306 | | // IPDL methods. |
307 | | void |
308 | | ActorDestroy(ActorDestroyReason aWhy) override; |
309 | | }; |
310 | | |
311 | | class OpenOp final |
312 | | : public ConnectionOperationBase |
313 | | , public OpenDirectoryListener |
314 | | { |
315 | | enum class State |
316 | | { |
317 | | // Just created on the PBackground thread, dispatched to the main thread. |
318 | | // Next step is FinishOpen. |
319 | | Initial, |
320 | | |
321 | | // Opening directory or initializing quota manager on the PBackground |
322 | | // thread. Next step is either DirectoryOpenPending if quota manager is |
323 | | // already initialized or QuotaManagerPending if quota manager needs to be |
324 | | // initialized. |
325 | | FinishOpen, |
326 | | |
327 | | // Waiting for quota manager initialization to complete on the PBackground |
328 | | // thread. Next step is either SendingResults if initialization failed or |
329 | | // DirectoryOpenPending if initialization succeeded. |
330 | | QuotaManagerPending, |
331 | | |
332 | | // Waiting for directory open allowed on the PBackground thread. The next |
333 | | // step is either SendingResults if directory lock failed to acquire, or |
334 | | // DatabaseWorkOpen if directory lock is acquired. |
335 | | DirectoryOpenPending, |
336 | | |
337 | | // Waiting to do/doing work on the QuotaManager IO thread. Its next step is |
338 | | // SendingResults. |
339 | | DatabaseWorkOpen, |
340 | | |
341 | | // Waiting to send/sending results on the PBackground thread. Next step is |
342 | | // Completed. |
343 | | SendingResults, |
344 | | |
345 | | // All done. |
346 | | Completed |
347 | | }; |
348 | | |
349 | | const SDBRequestOpenParams mParams; |
350 | | RefPtr<DirectoryLock> mDirectoryLock; |
351 | | nsCOMPtr<nsIFileStream> mFileStream; |
352 | | nsCString mSuffix; |
353 | | nsCString mGroup; |
354 | | nsCString mOrigin; |
355 | | State mState; |
356 | | bool mFileStreamOpen; |
357 | | |
358 | | public: |
359 | | OpenOp(Connection* aConnection, const SDBRequestParams& aParams); |
360 | | |
361 | | nsresult |
362 | | Dispatch() override; |
363 | | |
364 | | private: |
365 | | ~OpenOp() override; |
366 | | |
367 | | nsresult |
368 | | Open(); |
369 | | |
370 | | nsresult |
371 | | FinishOpen(); |
372 | | |
373 | | nsresult |
374 | | QuotaManagerOpen(); |
375 | | |
376 | | nsresult |
377 | | OpenDirectory(); |
378 | | |
379 | | nsresult |
380 | | SendToIOThread(); |
381 | | |
382 | | nsresult |
383 | | DatabaseWork(); |
384 | | |
385 | | void |
386 | | StreamClosedCallback(); |
387 | | |
388 | | // ConnectionOperationBase overrides |
389 | | nsresult |
390 | | DoDatabaseWork(nsIFileStream* aFileStream) override; |
391 | | |
392 | | void |
393 | | GetResponse(SDBRequestResponse& aResponse) override; |
394 | | |
395 | | void |
396 | | OnSuccess() override; |
397 | | |
398 | | void |
399 | | Cleanup() override; |
400 | | |
401 | | NS_DECL_ISUPPORTS_INHERITED |
402 | | |
403 | | NS_IMETHOD |
404 | | Run() override; |
405 | | |
406 | | // OpenDirectoryListener overrides. |
407 | | void |
408 | | DirectoryLockAcquired(DirectoryLock* aLock) override; |
409 | | |
410 | | void |
411 | | DirectoryLockFailed() override; |
412 | | }; |
413 | | |
414 | | class SeekOp final |
415 | | : public ConnectionOperationBase |
416 | | { |
417 | | const SDBRequestSeekParams mParams; |
418 | | |
419 | | public: |
420 | | SeekOp(Connection* aConnection, |
421 | | const SDBRequestParams& aParams); |
422 | | |
423 | | private: |
424 | | ~SeekOp() override = default; |
425 | | |
426 | | nsresult |
427 | | DoDatabaseWork(nsIFileStream* aFileStream) override; |
428 | | |
429 | | void |
430 | | GetResponse(SDBRequestResponse& aResponse) override; |
431 | | }; |
432 | | |
433 | | class ReadOp final |
434 | | : public ConnectionOperationBase |
435 | | { |
436 | | const SDBRequestReadParams mParams; |
437 | | |
438 | | RefPtr<MemoryOutputStream> mOutputStream; |
439 | | |
440 | | public: |
441 | | ReadOp(Connection* aConnection, |
442 | | const SDBRequestParams& aParams); |
443 | | |
444 | | bool |
445 | | Init() override; |
446 | | |
447 | | private: |
448 | 0 | ~ReadOp() override = default; |
449 | | |
450 | | nsresult |
451 | | DoDatabaseWork(nsIFileStream* aFileStream) override; |
452 | | |
453 | | void |
454 | | GetResponse(SDBRequestResponse& aResponse) override; |
455 | | }; |
456 | | |
457 | | class WriteOp final |
458 | | : public ConnectionOperationBase |
459 | | { |
460 | | const SDBRequestWriteParams mParams; |
461 | | |
462 | | nsCOMPtr<nsIInputStream> mInputStream; |
463 | | |
464 | | uint64_t mSize; |
465 | | |
466 | | public: |
467 | | WriteOp(Connection* aConnection, |
468 | | const SDBRequestParams& aParams); |
469 | | |
470 | | bool |
471 | | Init() override; |
472 | | |
473 | | private: |
474 | 0 | ~WriteOp() override = default; |
475 | | |
476 | | nsresult |
477 | | DoDatabaseWork(nsIFileStream* aFileStream) override; |
478 | | |
479 | | void |
480 | | GetResponse(SDBRequestResponse& aResponse) override; |
481 | | }; |
482 | | |
483 | | class CloseOp final |
484 | | : public ConnectionOperationBase |
485 | | { |
486 | | public: |
487 | | explicit CloseOp(Connection* aConnection); |
488 | | |
489 | | private: |
490 | | ~CloseOp() override = default; |
491 | | |
492 | | nsresult |
493 | | DoDatabaseWork(nsIFileStream* aFileStream) override; |
494 | | |
495 | | void |
496 | | GetResponse(SDBRequestResponse& aResponse) override; |
497 | | |
498 | | void |
499 | | OnSuccess() override; |
500 | | }; |
501 | | |
502 | | /******************************************************************************* |
503 | | * Other class declarations |
504 | | ******************************************************************************/ |
505 | | |
506 | | class QuotaClient final |
507 | | : public mozilla::dom::quota::Client |
508 | | { |
509 | | static QuotaClient* sInstance; |
510 | | |
511 | | bool mShutdownRequested; |
512 | | |
513 | | public: |
514 | | QuotaClient(); |
515 | | |
516 | | static bool |
517 | | IsShuttingDownOnBackgroundThread() |
518 | 0 | { |
519 | 0 | AssertIsOnBackgroundThread(); |
520 | 0 |
|
521 | 0 | if (sInstance) { |
522 | 0 | return sInstance->IsShuttingDown(); |
523 | 0 | } |
524 | 0 | |
525 | 0 | return QuotaManager::IsShuttingDown(); |
526 | 0 | } |
527 | | |
528 | | static bool |
529 | | IsShuttingDownOnNonBackgroundThread() |
530 | 0 | { |
531 | 0 | MOZ_ASSERT(!IsOnBackgroundThread()); |
532 | 0 |
|
533 | 0 | return QuotaManager::IsShuttingDown(); |
534 | 0 | } |
535 | | |
536 | | bool |
537 | | IsShuttingDown() const |
538 | 0 | { |
539 | 0 | AssertIsOnBackgroundThread(); |
540 | 0 |
|
541 | 0 | return mShutdownRequested; |
542 | 0 | } |
543 | | |
544 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(QuotaClient, override) |
545 | | |
546 | | Type |
547 | | GetType() override; |
548 | | |
549 | | nsresult |
550 | | InitOrigin(PersistenceType aPersistenceType, |
551 | | const nsACString& aGroup, |
552 | | const nsACString& aOrigin, |
553 | | const AtomicBool& aCanceled, |
554 | | UsageInfo* aUsageInfo) override; |
555 | | |
556 | | nsresult |
557 | | GetUsageForOrigin(PersistenceType aPersistenceType, |
558 | | const nsACString& aGroup, |
559 | | const nsACString& aOrigin, |
560 | | const AtomicBool& aCanceled, |
561 | | UsageInfo* aUsageInfo) override; |
562 | | |
563 | | void |
564 | | OnOriginClearCompleted(PersistenceType aPersistenceType, |
565 | | const nsACString& aOrigin) |
566 | | override; |
567 | | |
568 | | void |
569 | | ReleaseIOThreadObjects() override; |
570 | | |
571 | | void |
572 | | AbortOperations(const nsACString& aOrigin) override; |
573 | | |
574 | | void |
575 | | AbortOperationsForProcess(ContentParentId aContentParentId) override; |
576 | | |
577 | | void |
578 | | StartIdleMaintenance() override; |
579 | | |
580 | | void |
581 | | StopIdleMaintenance() override; |
582 | | |
583 | | void |
584 | | ShutdownWorkThreads() override; |
585 | | |
586 | | private: |
587 | | ~QuotaClient() override; |
588 | | }; |
589 | | |
590 | | /******************************************************************************* |
591 | | * Globals |
592 | | ******************************************************************************/ |
593 | | |
594 | | typedef nsTArray<RefPtr<Connection>> ConnectionArray; |
595 | | |
596 | | StaticAutoPtr<ConnectionArray> gOpenConnections; |
597 | | |
598 | | } // namespace |
599 | | |
600 | | /******************************************************************************* |
601 | | * Exported functions |
602 | | ******************************************************************************/ |
603 | | |
604 | | PBackgroundSDBConnectionParent* |
605 | | AllocPBackgroundSDBConnectionParent(const PrincipalInfo& aPrincipalInfo) |
606 | 0 | { |
607 | 0 | AssertIsOnBackgroundThread(); |
608 | 0 |
|
609 | 0 | if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) { |
610 | 0 | return nullptr; |
611 | 0 | } |
612 | 0 | |
613 | 0 | if (NS_WARN_IF(aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo)) { |
614 | 0 | ASSERT_UNLESS_FUZZING(); |
615 | 0 | return nullptr; |
616 | 0 | } |
617 | 0 |
|
618 | 0 | RefPtr<Connection> actor = new Connection(aPrincipalInfo); |
619 | 0 |
|
620 | 0 | return actor.forget().take(); |
621 | 0 | } |
622 | | |
623 | | bool |
624 | | RecvPBackgroundSDBConnectionConstructor(PBackgroundSDBConnectionParent* aActor, |
625 | | const PrincipalInfo& aPrincipalInfo) |
626 | 0 | { |
627 | 0 | AssertIsOnBackgroundThread(); |
628 | 0 | MOZ_ASSERT(aActor); |
629 | 0 | MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread()); |
630 | 0 |
|
631 | 0 | return true; |
632 | 0 | } |
633 | | |
634 | | bool |
635 | | DeallocPBackgroundSDBConnectionParent(PBackgroundSDBConnectionParent* aActor) |
636 | 0 | { |
637 | 0 | AssertIsOnBackgroundThread(); |
638 | 0 | MOZ_ASSERT(aActor); |
639 | 0 |
|
640 | 0 | RefPtr<Connection> actor = dont_AddRef(static_cast<Connection*>(aActor)); |
641 | 0 | return true; |
642 | 0 | } |
643 | | |
644 | | namespace simpledb { |
645 | | |
646 | | already_AddRefed<mozilla::dom::quota::Client> |
647 | | CreateQuotaClient() |
648 | 0 | { |
649 | 0 | AssertIsOnBackgroundThread(); |
650 | 0 |
|
651 | 0 | RefPtr<QuotaClient> client = new QuotaClient(); |
652 | 0 | return client.forget(); |
653 | 0 | } |
654 | | |
655 | | } // namespace simpledb |
656 | | |
657 | | /******************************************************************************* |
658 | | * StreamHelper |
659 | | ******************************************************************************/ |
660 | | |
661 | | StreamHelper::StreamHelper(nsIFileStream* aFileStream, |
662 | | nsIRunnable* aCallback) |
663 | | : Runnable("dom::StreamHelper") |
664 | | , mOwningEventTarget(GetCurrentThreadEventTarget()) |
665 | | , mFileStream(aFileStream) |
666 | | , mCallback(aCallback) |
667 | 0 | { |
668 | 0 | AssertIsOnBackgroundThread(); |
669 | 0 | MOZ_ASSERT(aFileStream); |
670 | 0 | MOZ_ASSERT(aCallback); |
671 | 0 | } |
672 | | |
673 | | StreamHelper::~StreamHelper() |
674 | 0 | { |
675 | 0 | MOZ_ASSERT(!mFileStream); |
676 | 0 | MOZ_ASSERT(!mCallback); |
677 | 0 | } |
678 | | |
679 | | void |
680 | | StreamHelper::AsyncClose() |
681 | 0 | { |
682 | 0 | AssertIsOnBackgroundThread(); |
683 | 0 |
|
684 | 0 | QuotaManager* quotaManager = QuotaManager::Get(); |
685 | 0 | MOZ_ASSERT(quotaManager); |
686 | 0 |
|
687 | 0 | MOZ_ALWAYS_SUCCEEDS( |
688 | 0 | quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL)); |
689 | 0 | } |
690 | | |
691 | | void |
692 | | StreamHelper::RunOnBackgroundThread() |
693 | 0 | { |
694 | 0 | AssertIsOnBackgroundThread(); |
695 | 0 |
|
696 | 0 | nsCOMPtr<nsIFileStream> fileStream; |
697 | 0 | mFileStream.swap(fileStream); |
698 | 0 |
|
699 | 0 | nsCOMPtr<nsIRunnable> callback; |
700 | 0 | mCallback.swap(callback); |
701 | 0 |
|
702 | 0 | callback->Run(); |
703 | 0 | } |
704 | | |
705 | | void |
706 | | StreamHelper::RunOnIOThread() |
707 | 0 | { |
708 | 0 | AssertIsOnIOThread(); |
709 | 0 | MOZ_ASSERT(mFileStream); |
710 | 0 |
|
711 | 0 | nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(mFileStream); |
712 | 0 | MOZ_ASSERT(inputStream); |
713 | 0 |
|
714 | 0 | nsresult rv = inputStream->Close(); |
715 | 0 | Unused << NS_WARN_IF(NS_FAILED(rv)); |
716 | 0 |
|
717 | 0 | MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)); |
718 | 0 | } |
719 | | |
720 | | NS_IMETHODIMP |
721 | | StreamHelper::Run() |
722 | 0 | { |
723 | 0 | MOZ_ASSERT(mCallback); |
724 | 0 |
|
725 | 0 | if (IsOnBackgroundThread()) { |
726 | 0 | RunOnBackgroundThread(); |
727 | 0 | } else { |
728 | 0 | RunOnIOThread(); |
729 | 0 | } |
730 | 0 |
|
731 | 0 | return NS_OK; |
732 | 0 | } |
733 | | |
734 | | /******************************************************************************* |
735 | | * Connection |
736 | | ******************************************************************************/ |
737 | | |
738 | | Connection::Connection(const PrincipalInfo& aPrincipalInfo) |
739 | | : mPrincipalInfo(aPrincipalInfo) |
740 | | , mRunningRequest(false) |
741 | | , mOpen(false) |
742 | | , mAllowedToClose(false) |
743 | | , mActorDestroyed(false) |
744 | 0 | { |
745 | 0 | AssertIsOnBackgroundThread(); |
746 | 0 | MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread()); |
747 | 0 | } |
748 | | |
749 | | Connection::~Connection() |
750 | 0 | { |
751 | 0 | MOZ_ASSERT(!mRunningRequest); |
752 | 0 | MOZ_ASSERT(!mOpen); |
753 | 0 | MOZ_ASSERT(mActorDestroyed); |
754 | 0 | } |
755 | | |
756 | | void |
757 | | Connection::OnNewRequest() |
758 | 0 | { |
759 | 0 | AssertIsOnBackgroundThread(); |
760 | 0 | MOZ_ASSERT(!mRunningRequest); |
761 | 0 |
|
762 | 0 | mRunningRequest = true; |
763 | 0 | } |
764 | | |
765 | | void |
766 | | Connection::OnRequestFinished() |
767 | 0 | { |
768 | 0 | AssertIsOnBackgroundThread(); |
769 | 0 | MOZ_ASSERT(mRunningRequest); |
770 | 0 |
|
771 | 0 | mRunningRequest = false; |
772 | 0 |
|
773 | 0 | MaybeCloseStream(); |
774 | 0 | } |
775 | | |
776 | | void |
777 | | Connection::OnOpen(const nsACString& aOrigin, |
778 | | const nsAString& aName, |
779 | | already_AddRefed<DirectoryLock> aDirectoryLock, |
780 | | already_AddRefed<nsIFileStream> aFileStream) |
781 | 0 | { |
782 | 0 | AssertIsOnBackgroundThread(); |
783 | 0 | MOZ_ASSERT(!aOrigin.IsEmpty()); |
784 | 0 | MOZ_ASSERT(!aName.IsEmpty()); |
785 | 0 | MOZ_ASSERT(mOrigin.IsEmpty()); |
786 | 0 | MOZ_ASSERT(mName.IsEmpty()); |
787 | 0 | MOZ_ASSERT(!mDirectoryLock); |
788 | 0 | MOZ_ASSERT(!mFileStream); |
789 | 0 | MOZ_ASSERT(!mOpen); |
790 | 0 |
|
791 | 0 | mOrigin = aOrigin; |
792 | 0 | mName = aName; |
793 | 0 | mDirectoryLock = aDirectoryLock; |
794 | 0 | mFileStream = aFileStream; |
795 | 0 | mOpen = true; |
796 | 0 |
|
797 | 0 | if (!gOpenConnections) { |
798 | 0 | gOpenConnections = new ConnectionArray(); |
799 | 0 | } |
800 | 0 |
|
801 | 0 | gOpenConnections->AppendElement(this); |
802 | 0 | } |
803 | | |
804 | | void |
805 | | Connection::OnClose() |
806 | 0 | { |
807 | 0 | AssertIsOnBackgroundThread(); |
808 | 0 | MOZ_ASSERT(!mOrigin.IsEmpty()); |
809 | 0 | MOZ_ASSERT(mDirectoryLock); |
810 | 0 | MOZ_ASSERT(mFileStream); |
811 | 0 | MOZ_ASSERT(mOpen); |
812 | 0 |
|
813 | 0 | mOrigin.Truncate(); |
814 | 0 | mName.Truncate(); |
815 | 0 | mDirectoryLock = nullptr; |
816 | 0 | mFileStream = nullptr; |
817 | 0 | mOpen = false; |
818 | 0 |
|
819 | 0 | MOZ_ASSERT(gOpenConnections); |
820 | 0 | gOpenConnections->RemoveElement(this); |
821 | 0 |
|
822 | 0 | if (gOpenConnections->IsEmpty()) { |
823 | 0 | gOpenConnections = nullptr; |
824 | 0 | } |
825 | 0 |
|
826 | 0 | if (mAllowedToClose && !mActorDestroyed) { |
827 | 0 | Unused << SendClosed(); |
828 | 0 | } |
829 | 0 | } |
830 | | |
831 | | void |
832 | | Connection::AllowToClose() |
833 | 0 | { |
834 | 0 | AssertIsOnBackgroundThread(); |
835 | 0 |
|
836 | 0 | if (mAllowedToClose) { |
837 | 0 | return; |
838 | 0 | } |
839 | 0 | |
840 | 0 | mAllowedToClose = true; |
841 | 0 |
|
842 | 0 | if (!mActorDestroyed) { |
843 | 0 | Unused << SendAllowToClose(); |
844 | 0 | } |
845 | 0 |
|
846 | 0 | MaybeCloseStream(); |
847 | 0 | } |
848 | | |
849 | | void |
850 | | Connection::MaybeCloseStream() |
851 | 0 | { |
852 | 0 | AssertIsOnBackgroundThread(); |
853 | 0 |
|
854 | 0 | if (!mRunningRequest && |
855 | 0 | mOpen && |
856 | 0 | mAllowedToClose) { |
857 | 0 | nsCOMPtr<nsIRunnable> callback = |
858 | 0 | NewRunnableMethod("dom::Connection::OnClose", |
859 | 0 | this, |
860 | 0 | &Connection::OnClose); |
861 | 0 |
|
862 | 0 | RefPtr<StreamHelper> helper = new StreamHelper(mFileStream, callback); |
863 | 0 | helper->AsyncClose(); |
864 | 0 | } |
865 | 0 | } |
866 | | |
867 | | bool |
868 | | Connection::VerifyRequestParams(const SDBRequestParams& aParams) const |
869 | 0 | { |
870 | 0 | AssertIsOnBackgroundThread(); |
871 | 0 | MOZ_ASSERT(aParams.type() != SDBRequestParams::T__None); |
872 | 0 |
|
873 | 0 | switch (aParams.type()) { |
874 | 0 | case SDBRequestParams::TSDBRequestOpenParams: { |
875 | 0 | if (NS_WARN_IF(mOpen)) { |
876 | 0 | ASSERT_UNLESS_FUZZING(); |
877 | 0 | return false; |
878 | 0 | } |
879 | 0 |
|
880 | 0 | break; |
881 | 0 | } |
882 | 0 |
|
883 | 0 | case SDBRequestParams::TSDBRequestSeekParams: |
884 | 0 | case SDBRequestParams::TSDBRequestReadParams: |
885 | 0 | case SDBRequestParams::TSDBRequestWriteParams: |
886 | 0 | case SDBRequestParams::TSDBRequestCloseParams: { |
887 | 0 | if (NS_WARN_IF(!mOpen)) { |
888 | 0 | ASSERT_UNLESS_FUZZING(); |
889 | 0 | return false; |
890 | 0 | } |
891 | 0 |
|
892 | 0 | break; |
893 | 0 | } |
894 | 0 |
|
895 | 0 | default: |
896 | 0 | MOZ_CRASH("Should never get here!"); |
897 | 0 | } |
898 | 0 |
|
899 | 0 | return true; |
900 | 0 | } |
901 | | |
902 | | void |
903 | | Connection::ActorDestroy(ActorDestroyReason aWhy) |
904 | 0 | { |
905 | 0 | AssertIsOnBackgroundThread(); |
906 | 0 | MOZ_ASSERT(!mActorDestroyed); |
907 | 0 |
|
908 | 0 | mActorDestroyed = true; |
909 | 0 |
|
910 | 0 | AllowToClose(); |
911 | 0 | } |
912 | | |
913 | | mozilla::ipc::IPCResult |
914 | | Connection::RecvDeleteMe() |
915 | 0 | { |
916 | 0 | AssertIsOnBackgroundThread(); |
917 | 0 | MOZ_ASSERT(!mActorDestroyed); |
918 | 0 |
|
919 | 0 | IProtocol* mgr = Manager(); |
920 | 0 | if (!PBackgroundSDBConnectionParent::Send__delete__(this)) { |
921 | 0 | return IPC_FAIL_NO_REASON(mgr); |
922 | 0 | } |
923 | 0 |
|
924 | 0 | return IPC_OK(); |
925 | 0 | } |
926 | | |
927 | | PBackgroundSDBRequestParent* |
928 | | Connection::AllocPBackgroundSDBRequestParent(const SDBRequestParams& aParams) |
929 | 0 | { |
930 | 0 | AssertIsOnBackgroundThread(); |
931 | 0 | MOZ_ASSERT(aParams.type() != SDBRequestParams::T__None); |
932 | 0 |
|
933 | 0 | if (aParams.type() == SDBRequestParams::TSDBRequestOpenParams && |
934 | 0 | NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) { |
935 | 0 | return nullptr; |
936 | 0 | } |
937 | 0 | |
938 | 0 | if (mAllowedToClose) { |
939 | 0 | return nullptr; |
940 | 0 | } |
941 | 0 | |
942 | | #ifdef DEBUG |
943 | | // Always verify parameters in DEBUG builds! |
944 | | bool trustParams = false; |
945 | | #else |
946 | 0 | PBackgroundParent* backgroundActor = Manager(); |
947 | 0 | MOZ_ASSERT(backgroundActor); |
948 | 0 |
|
949 | 0 | bool trustParams = !BackgroundParent::IsOtherProcessActor(backgroundActor); |
950 | 0 | #endif |
951 | 0 |
|
952 | 0 | if (NS_WARN_IF(!trustParams && !VerifyRequestParams(aParams))) { |
953 | 0 | ASSERT_UNLESS_FUZZING(); |
954 | 0 | return nullptr; |
955 | 0 | } |
956 | 0 |
|
957 | 0 | if (NS_WARN_IF(mRunningRequest)) { |
958 | 0 | ASSERT_UNLESS_FUZZING(); |
959 | 0 | return nullptr; |
960 | 0 | } |
961 | 0 |
|
962 | 0 | RefPtr<ConnectionOperationBase> actor; |
963 | 0 |
|
964 | 0 | switch (aParams.type()) { |
965 | 0 | case SDBRequestParams::TSDBRequestOpenParams: |
966 | 0 | actor = new OpenOp(this, aParams); |
967 | 0 | break; |
968 | 0 |
|
969 | 0 | case SDBRequestParams::TSDBRequestSeekParams: |
970 | 0 | actor = new SeekOp(this, aParams); |
971 | 0 | break; |
972 | 0 |
|
973 | 0 | case SDBRequestParams::TSDBRequestReadParams: |
974 | 0 | actor = new ReadOp(this, aParams); |
975 | 0 | break; |
976 | 0 |
|
977 | 0 | case SDBRequestParams::TSDBRequestWriteParams: |
978 | 0 | actor = new WriteOp(this, aParams); |
979 | 0 | break; |
980 | 0 |
|
981 | 0 | case SDBRequestParams::TSDBRequestCloseParams: |
982 | 0 | actor = new CloseOp(this); |
983 | 0 | break; |
984 | 0 |
|
985 | 0 | default: |
986 | 0 | MOZ_CRASH("Should never get here!"); |
987 | 0 | } |
988 | 0 |
|
989 | 0 | // Transfer ownership to IPDL. |
990 | 0 | return actor.forget().take(); |
991 | 0 | } |
992 | | |
993 | | mozilla::ipc::IPCResult |
994 | | Connection::RecvPBackgroundSDBRequestConstructor( |
995 | | PBackgroundSDBRequestParent* aActor, |
996 | | const SDBRequestParams& aParams) |
997 | 0 | { |
998 | 0 | AssertIsOnBackgroundThread(); |
999 | 0 | MOZ_ASSERT(aActor); |
1000 | 0 | MOZ_ASSERT(aParams.type() != SDBRequestParams::T__None); |
1001 | 0 | MOZ_ASSERT_IF(aParams.type() == SDBRequestParams::TSDBRequestOpenParams, |
1002 | 0 | !QuotaClient::IsShuttingDownOnBackgroundThread()); |
1003 | 0 | MOZ_ASSERT(!mAllowedToClose); |
1004 | 0 | MOZ_ASSERT(!mRunningRequest); |
1005 | 0 |
|
1006 | 0 | auto* op = static_cast<ConnectionOperationBase*>(aActor); |
1007 | 0 |
|
1008 | 0 | if (NS_WARN_IF(!op->Init())) { |
1009 | 0 | op->Cleanup(); |
1010 | 0 | return IPC_FAIL_NO_REASON(this); |
1011 | 0 | } |
1012 | 0 |
|
1013 | 0 | if (NS_WARN_IF(NS_FAILED(op->Dispatch()))) { |
1014 | 0 | op->Cleanup(); |
1015 | 0 | return IPC_FAIL_NO_REASON(this); |
1016 | 0 | } |
1017 | 0 |
|
1018 | 0 | return IPC_OK(); |
1019 | 0 | } |
1020 | | |
1021 | | bool |
1022 | | Connection::DeallocPBackgroundSDBRequestParent( |
1023 | | PBackgroundSDBRequestParent* aActor) |
1024 | 0 | { |
1025 | 0 | AssertIsOnBackgroundThread(); |
1026 | 0 | MOZ_ASSERT(aActor); |
1027 | 0 |
|
1028 | 0 | // Transfer ownership back from IPDL. |
1029 | 0 | RefPtr<ConnectionOperationBase> actor = |
1030 | 0 | dont_AddRef(static_cast<ConnectionOperationBase*>(aActor)); |
1031 | 0 | return true; |
1032 | 0 | } |
1033 | | |
1034 | | /******************************************************************************* |
1035 | | * ConnectionOperationBase |
1036 | | ******************************************************************************/ |
1037 | | |
1038 | | ConnectionOperationBase::~ConnectionOperationBase() |
1039 | 0 | { |
1040 | 0 | MOZ_ASSERT(!mConnection, |
1041 | 0 | "ConnectionOperationBase::Cleanup() was not called by a subclass!"); |
1042 | 0 | MOZ_ASSERT(mActorDestroyed); |
1043 | 0 | } |
1044 | | |
1045 | | bool |
1046 | | ConnectionOperationBase::Init() |
1047 | 0 | { |
1048 | 0 | AssertIsOnBackgroundThread(); |
1049 | 0 | MOZ_ASSERT(mConnection); |
1050 | 0 |
|
1051 | 0 | mConnection->OnNewRequest(); |
1052 | 0 |
|
1053 | 0 | return true; |
1054 | 0 | } |
1055 | | |
1056 | | nsresult |
1057 | | ConnectionOperationBase::Dispatch() |
1058 | 0 | { |
1059 | 0 | if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) || |
1060 | 0 | IsActorDestroyed()) { |
1061 | 0 | return NS_ERROR_FAILURE; |
1062 | 0 | } |
1063 | 0 | |
1064 | 0 | QuotaManager* quotaManager = QuotaManager::Get(); |
1065 | 0 | MOZ_ASSERT(quotaManager); |
1066 | 0 |
|
1067 | 0 | nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL); |
1068 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1069 | 0 | return rv; |
1070 | 0 | } |
1071 | 0 | |
1072 | 0 | return NS_OK; |
1073 | 0 | } |
1074 | | |
1075 | | void |
1076 | | ConnectionOperationBase::Cleanup() |
1077 | 0 | { |
1078 | 0 | AssertIsOnOwningThread(); |
1079 | 0 | MOZ_ASSERT(mConnection); |
1080 | 0 |
|
1081 | 0 | mConnection->OnRequestFinished(); |
1082 | 0 |
|
1083 | 0 | mConnection = nullptr; |
1084 | 0 | } |
1085 | | |
1086 | | void |
1087 | | ConnectionOperationBase::SendResults() |
1088 | 0 | { |
1089 | 0 | AssertIsOnOwningThread(); |
1090 | 0 |
|
1091 | 0 | if (IsActorDestroyed()) { |
1092 | 0 | MaybeSetFailureCode(NS_ERROR_FAILURE); |
1093 | 0 | } else { |
1094 | 0 | SDBRequestResponse response; |
1095 | 0 |
|
1096 | 0 | if (NS_SUCCEEDED(mResultCode)) { |
1097 | 0 | GetResponse(response); |
1098 | 0 |
|
1099 | 0 | MOZ_ASSERT(response.type() != SDBRequestResponse::T__None); |
1100 | 0 | MOZ_ASSERT(response.type() != SDBRequestResponse::Tnsresult); |
1101 | 0 | } else { |
1102 | 0 | response = mResultCode; |
1103 | 0 | } |
1104 | 0 |
|
1105 | 0 | Unused << |
1106 | 0 | PBackgroundSDBRequestParent::Send__delete__(this, response); |
1107 | 0 |
|
1108 | 0 | if (NS_SUCCEEDED(mResultCode)) { |
1109 | 0 | OnSuccess(); |
1110 | 0 | } |
1111 | 0 | } |
1112 | 0 |
|
1113 | 0 | Cleanup(); |
1114 | 0 | } |
1115 | | |
1116 | | void |
1117 | | ConnectionOperationBase::DatabaseWork() |
1118 | 0 | { |
1119 | 0 | AssertIsOnIOThread(); |
1120 | 0 | MOZ_ASSERT(NS_SUCCEEDED(mResultCode)); |
1121 | 0 |
|
1122 | 0 | if (!OperationMayProceed()) { |
1123 | 0 | // The operation was canceled in some way, likely because the child process |
1124 | 0 | // has crashed. |
1125 | 0 | mResultCode = NS_ERROR_FAILURE; |
1126 | 0 | } else { |
1127 | 0 | nsIFileStream* fileStream = mConnection->GetFileStream(); |
1128 | 0 | MOZ_ASSERT(fileStream); |
1129 | 0 |
|
1130 | 0 | nsresult rv = DoDatabaseWork(fileStream); |
1131 | 0 | if (NS_FAILED(rv)) { |
1132 | 0 | mResultCode = rv; |
1133 | 0 | } |
1134 | 0 | } |
1135 | 0 |
|
1136 | 0 | MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)); |
1137 | 0 | } |
1138 | | |
1139 | | void |
1140 | | ConnectionOperationBase::OnSuccess() |
1141 | 0 | { |
1142 | 0 | AssertIsOnOwningThread(); |
1143 | 0 | } |
1144 | | |
1145 | | NS_IMETHODIMP |
1146 | | ConnectionOperationBase::Run() |
1147 | 0 | { |
1148 | 0 | if (IsOnBackgroundThread()) { |
1149 | 0 | SendResults(); |
1150 | 0 | } else { |
1151 | 0 | DatabaseWork(); |
1152 | 0 | } |
1153 | 0 |
|
1154 | 0 | return NS_OK; |
1155 | 0 | } |
1156 | | |
1157 | | void |
1158 | | ConnectionOperationBase::ActorDestroy(ActorDestroyReason aWhy) |
1159 | 0 | { |
1160 | 0 | AssertIsOnBackgroundThread(); |
1161 | 0 |
|
1162 | 0 | mOperationMayProceed = false; |
1163 | 0 | mActorDestroyed = true; |
1164 | 0 | } |
1165 | | |
1166 | | OpenOp::OpenOp(Connection* aConnection, const SDBRequestParams& aParams) |
1167 | | : ConnectionOperationBase(aConnection) |
1168 | | , mParams(aParams.get_SDBRequestOpenParams()) |
1169 | | , mState(State::Initial) |
1170 | | , mFileStreamOpen(false) |
1171 | 0 | { |
1172 | 0 | MOZ_ASSERT(aParams.type() == SDBRequestParams::TSDBRequestOpenParams); |
1173 | 0 | } |
1174 | | |
1175 | | OpenOp::~OpenOp() |
1176 | 0 | { |
1177 | 0 | MOZ_ASSERT(!mDirectoryLock); |
1178 | 0 | MOZ_ASSERT(!mFileStream); |
1179 | 0 | MOZ_ASSERT(!mFileStreamOpen); |
1180 | 0 | MOZ_ASSERT_IF(OperationMayProceed(), |
1181 | 0 | mState == State::Initial || mState == State::Completed); |
1182 | 0 | } |
1183 | | |
1184 | | nsresult |
1185 | | OpenOp::Dispatch() |
1186 | 0 | { |
1187 | 0 | MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this)); |
1188 | 0 |
|
1189 | 0 | return NS_OK; |
1190 | 0 | } |
1191 | | |
1192 | | nsresult |
1193 | | OpenOp::Open() |
1194 | 0 | { |
1195 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1196 | 0 | MOZ_ASSERT(mState == State::Initial); |
1197 | 0 |
|
1198 | 0 | if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) || |
1199 | 0 | !OperationMayProceed()) { |
1200 | 0 | return NS_ERROR_FAILURE; |
1201 | 0 | } |
1202 | 0 | |
1203 | 0 | if (NS_WARN_IF(!Preferences::GetBool(kPrefSimpleDBEnabled, false))) { |
1204 | 0 | return NS_ERROR_UNEXPECTED; |
1205 | 0 | } |
1206 | 0 | |
1207 | 0 | const PrincipalInfo& principalInfo = GetConnection()->GetPrincipalInfo(); |
1208 | 0 |
|
1209 | 0 | if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) { |
1210 | 0 | QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin); |
1211 | 0 | } else { |
1212 | 0 | MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo); |
1213 | 0 |
|
1214 | 0 | nsresult rv; |
1215 | 0 | nsCOMPtr<nsIPrincipal> principal = |
1216 | 0 | PrincipalInfoToPrincipal(principalInfo, &rv); |
1217 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1218 | 0 | return rv; |
1219 | 0 | } |
1220 | 0 | |
1221 | 0 | rv = QuotaManager::GetInfoFromPrincipal(principal, |
1222 | 0 | &mSuffix, |
1223 | 0 | &mGroup, |
1224 | 0 | &mOrigin); |
1225 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1226 | 0 | return rv; |
1227 | 0 | } |
1228 | 0 | } |
1229 | 0 | |
1230 | 0 | mState = State::FinishOpen; |
1231 | 0 | MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL)); |
1232 | 0 |
|
1233 | 0 | return NS_OK; |
1234 | 0 | } |
1235 | | |
1236 | | nsresult |
1237 | | OpenOp::FinishOpen() |
1238 | 0 | { |
1239 | 0 | AssertIsOnOwningThread(); |
1240 | 0 | MOZ_ASSERT(mState == State::FinishOpen); |
1241 | 0 |
|
1242 | 0 | if (gOpenConnections) { |
1243 | 0 | for (Connection* connection : *gOpenConnections) { |
1244 | 0 | if (connection->Origin() == mOrigin && |
1245 | 0 | connection->Name() == mParams.name()) { |
1246 | 0 | return NS_ERROR_STORAGE_BUSY; |
1247 | 0 | } |
1248 | 0 | } |
1249 | 0 | } |
1250 | 0 |
|
1251 | 0 | if (QuotaManager::Get()) { |
1252 | 0 | nsresult rv = OpenDirectory(); |
1253 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1254 | 0 | return rv; |
1255 | 0 | } |
1256 | 0 | |
1257 | 0 | return NS_OK; |
1258 | 0 | } |
1259 | 0 | |
1260 | 0 | mState = State::QuotaManagerPending; |
1261 | 0 | QuotaManager::GetOrCreate(this); |
1262 | 0 |
|
1263 | 0 | return NS_OK; |
1264 | 0 | } |
1265 | | |
1266 | | nsresult |
1267 | | OpenOp::QuotaManagerOpen() |
1268 | 0 | { |
1269 | 0 | AssertIsOnOwningThread(); |
1270 | 0 | MOZ_ASSERT(mState == State::QuotaManagerPending); |
1271 | 0 |
|
1272 | 0 | if (NS_WARN_IF(!QuotaManager::Get())) { |
1273 | 0 | return NS_ERROR_FAILURE; |
1274 | 0 | } |
1275 | 0 | |
1276 | 0 | nsresult rv = OpenDirectory(); |
1277 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1278 | 0 | return rv; |
1279 | 0 | } |
1280 | 0 | |
1281 | 0 | return NS_OK; |
1282 | 0 | } |
1283 | | |
1284 | | nsresult |
1285 | | OpenOp::OpenDirectory() |
1286 | 0 | { |
1287 | 0 | AssertIsOnOwningThread(); |
1288 | 0 | MOZ_ASSERT(mState == State::FinishOpen || |
1289 | 0 | mState == State::QuotaManagerPending); |
1290 | 0 | MOZ_ASSERT(!mOrigin.IsEmpty()); |
1291 | 0 | MOZ_ASSERT(!mDirectoryLock); |
1292 | 0 | MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread()); |
1293 | 0 | MOZ_ASSERT(QuotaManager::Get()); |
1294 | 0 |
|
1295 | 0 | mState = State::DirectoryOpenPending; |
1296 | 0 | QuotaManager::Get()->OpenDirectory(PERSISTENCE_TYPE_DEFAULT, |
1297 | 0 | mGroup, |
1298 | 0 | mOrigin, |
1299 | 0 | mozilla::dom::quota::Client::SDB, |
1300 | 0 | /* aExclusive */ false, |
1301 | 0 | this); |
1302 | 0 |
|
1303 | 0 | return NS_OK; |
1304 | 0 | } |
1305 | | |
1306 | | nsresult |
1307 | | OpenOp::SendToIOThread() |
1308 | 0 | { |
1309 | 0 | AssertIsOnOwningThread(); |
1310 | 0 | MOZ_ASSERT(mState == State::DirectoryOpenPending); |
1311 | 0 |
|
1312 | 0 | if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) || |
1313 | 0 | IsActorDestroyed()) { |
1314 | 0 | return NS_ERROR_FAILURE; |
1315 | 0 | } |
1316 | 0 | |
1317 | 0 | mFileStream = new FileStream(PERSISTENCE_TYPE_DEFAULT, mGroup, mOrigin); |
1318 | 0 |
|
1319 | 0 | QuotaManager* quotaManager = QuotaManager::Get(); |
1320 | 0 | MOZ_ASSERT(quotaManager); |
1321 | 0 |
|
1322 | 0 | // Must set this before dispatching otherwise we will race with the IO thread. |
1323 | 0 | mState = State::DatabaseWorkOpen; |
1324 | 0 |
|
1325 | 0 | nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL); |
1326 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1327 | 0 | return rv; |
1328 | 0 | } |
1329 | 0 | |
1330 | 0 | return NS_OK; |
1331 | 0 | } |
1332 | | |
1333 | | nsresult |
1334 | | OpenOp::DatabaseWork() |
1335 | 0 | { |
1336 | 0 | AssertIsOnIOThread(); |
1337 | 0 | MOZ_ASSERT(mState == State::DatabaseWorkOpen); |
1338 | 0 | MOZ_ASSERT(mFileStream); |
1339 | 0 | MOZ_ASSERT(!mFileStreamOpen); |
1340 | 0 |
|
1341 | 0 | if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) || |
1342 | 0 | !OperationMayProceed()) { |
1343 | 0 | return NS_ERROR_FAILURE; |
1344 | 0 | } |
1345 | 0 | |
1346 | 0 | QuotaManager* quotaManager = QuotaManager::Get(); |
1347 | 0 | MOZ_ASSERT(quotaManager); |
1348 | 0 |
|
1349 | 0 | nsCOMPtr<nsIFile> dbDirectory; |
1350 | 0 | nsresult rv = |
1351 | 0 | quotaManager->EnsureOriginIsInitialized(PERSISTENCE_TYPE_DEFAULT, |
1352 | 0 | mSuffix, |
1353 | 0 | mGroup, |
1354 | 0 | mOrigin, |
1355 | 0 | getter_AddRefs(dbDirectory)); |
1356 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1357 | 0 | return rv; |
1358 | 0 | } |
1359 | 0 | |
1360 | 0 | rv = dbDirectory->Append(NS_LITERAL_STRING(SDB_DIRECTORY_NAME)); |
1361 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1362 | 0 | return rv; |
1363 | 0 | } |
1364 | 0 | |
1365 | 0 | bool exists; |
1366 | 0 | rv = dbDirectory->Exists(&exists); |
1367 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1368 | 0 | return rv; |
1369 | 0 | } |
1370 | 0 | |
1371 | 0 | if (!exists) { |
1372 | 0 | rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755); |
1373 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1374 | 0 | return rv; |
1375 | 0 | } |
1376 | 0 | } |
1377 | | #ifdef DEBUG |
1378 | | else { |
1379 | | bool isDirectory; |
1380 | | MOZ_ASSERT(NS_SUCCEEDED(dbDirectory->IsDirectory(&isDirectory))); |
1381 | | MOZ_ASSERT(isDirectory); |
1382 | | } |
1383 | | #endif |
1384 | | |
1385 | 0 | nsCOMPtr<nsIFile> dbFile; |
1386 | 0 | rv = dbDirectory->Clone(getter_AddRefs(dbFile)); |
1387 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1388 | 0 | return rv; |
1389 | 0 | } |
1390 | 0 | |
1391 | 0 | rv = dbFile->Append(mParams.name()); |
1392 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1393 | 0 | return rv; |
1394 | 0 | } |
1395 | 0 | |
1396 | 0 | nsString databaseFilePath; |
1397 | 0 | rv = dbFile->GetPath(databaseFilePath); |
1398 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1399 | 0 | return rv; |
1400 | 0 | } |
1401 | 0 | |
1402 | 0 | rv = mFileStream->Init(dbFile, PR_RDWR | PR_CREATE_FILE, 0644, 0); |
1403 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1404 | 0 | return rv; |
1405 | 0 | } |
1406 | 0 | |
1407 | 0 | mFileStreamOpen = true; |
1408 | 0 |
|
1409 | 0 | rv = DoDatabaseWork(mFileStream); |
1410 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1411 | 0 | return rv; |
1412 | 0 | } |
1413 | 0 | |
1414 | 0 | // Must set mState before dispatching otherwise we will race with the owning |
1415 | 0 | // thread. |
1416 | 0 | mState = State::SendingResults; |
1417 | 0 |
|
1418 | 0 | rv = OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL); |
1419 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1420 | 0 | return rv; |
1421 | 0 | } |
1422 | 0 | |
1423 | 0 | return NS_OK; |
1424 | 0 | } |
1425 | | |
1426 | | void |
1427 | | OpenOp::StreamClosedCallback() |
1428 | 0 | { |
1429 | 0 | AssertIsOnOwningThread(); |
1430 | 0 | MOZ_ASSERT(NS_FAILED(ResultCode())); |
1431 | 0 | MOZ_ASSERT(mDirectoryLock); |
1432 | 0 | MOZ_ASSERT(mFileStream); |
1433 | 0 | MOZ_ASSERT(mFileStreamOpen); |
1434 | 0 |
|
1435 | 0 | mDirectoryLock = nullptr; |
1436 | 0 | mFileStream = nullptr; |
1437 | 0 | mFileStreamOpen = false; |
1438 | 0 | } |
1439 | | |
1440 | | nsresult |
1441 | | OpenOp::DoDatabaseWork(nsIFileStream* aFileStream) |
1442 | 0 | { |
1443 | 0 | AssertIsOnIOThread(); |
1444 | 0 |
|
1445 | 0 | return NS_OK; |
1446 | 0 | } |
1447 | | |
1448 | | void |
1449 | | OpenOp::GetResponse(SDBRequestResponse& aResponse) |
1450 | 0 | { |
1451 | 0 | AssertIsOnOwningThread(); |
1452 | 0 |
|
1453 | 0 | aResponse = SDBRequestOpenResponse(); |
1454 | 0 | } |
1455 | | |
1456 | | void |
1457 | | OpenOp::OnSuccess() |
1458 | 0 | { |
1459 | 0 | AssertIsOnOwningThread(); |
1460 | 0 | MOZ_ASSERT(NS_SUCCEEDED(ResultCode())); |
1461 | 0 | MOZ_ASSERT(!mOrigin.IsEmpty()); |
1462 | 0 | MOZ_ASSERT(mDirectoryLock); |
1463 | 0 | MOZ_ASSERT(mFileStream); |
1464 | 0 | MOZ_ASSERT(mFileStreamOpen); |
1465 | 0 |
|
1466 | 0 | RefPtr<DirectoryLock> directoryLock; |
1467 | 0 | nsCOMPtr<nsIFileStream> fileStream; |
1468 | 0 |
|
1469 | 0 | mDirectoryLock.swap(directoryLock); |
1470 | 0 | mFileStream.swap(fileStream); |
1471 | 0 | mFileStreamOpen = false; |
1472 | 0 |
|
1473 | 0 | GetConnection()->OnOpen(mOrigin, |
1474 | 0 | mParams.name(), |
1475 | 0 | directoryLock.forget(), |
1476 | 0 | fileStream.forget()); |
1477 | 0 | } |
1478 | | |
1479 | | void |
1480 | | OpenOp::Cleanup() |
1481 | 0 | { |
1482 | 0 | AssertIsOnOwningThread(); |
1483 | 0 | MOZ_ASSERT_IF(mFileStreamOpen, mFileStream); |
1484 | 0 |
|
1485 | 0 | if (mFileStream && mFileStreamOpen) { |
1486 | 0 | // If we have an initialized file stream then the operation must have failed |
1487 | 0 | // and there must be a directory lock too. |
1488 | 0 | MOZ_ASSERT(NS_FAILED(ResultCode())); |
1489 | 0 | MOZ_ASSERT(mDirectoryLock); |
1490 | 0 |
|
1491 | 0 | // We must close the stream on the I/O thread before releasing it on this |
1492 | 0 | // thread. The directory lock can't be released either. |
1493 | 0 | nsCOMPtr<nsIRunnable> callback = |
1494 | 0 | NewRunnableMethod("dom::OpenOp::StreamClosedCallback", |
1495 | 0 | this, |
1496 | 0 | &OpenOp::StreamClosedCallback); |
1497 | 0 |
|
1498 | 0 | RefPtr<StreamHelper> helper = new StreamHelper(mFileStream, callback); |
1499 | 0 | helper->AsyncClose(); |
1500 | 0 | } else { |
1501 | 0 | MOZ_ASSERT(!mFileStreamOpen); |
1502 | 0 |
|
1503 | 0 | mDirectoryLock = nullptr; |
1504 | 0 | mFileStream = nullptr; |
1505 | 0 | } |
1506 | 0 |
|
1507 | 0 | ConnectionOperationBase::Cleanup(); |
1508 | 0 | } |
1509 | | |
1510 | | NS_IMPL_ISUPPORTS_INHERITED0(OpenOp, ConnectionOperationBase) |
1511 | | |
1512 | | NS_IMETHODIMP |
1513 | | OpenOp::Run() |
1514 | 0 | { |
1515 | 0 | nsresult rv; |
1516 | 0 |
|
1517 | 0 | switch (mState) { |
1518 | 0 | case State::Initial: |
1519 | 0 | rv = Open(); |
1520 | 0 | break; |
1521 | 0 |
|
1522 | 0 | case State::FinishOpen: |
1523 | 0 | rv = FinishOpen(); |
1524 | 0 | break; |
1525 | 0 |
|
1526 | 0 | case State::QuotaManagerPending: |
1527 | 0 | rv = QuotaManagerOpen(); |
1528 | 0 | break; |
1529 | 0 |
|
1530 | 0 | case State::DatabaseWorkOpen: |
1531 | 0 | rv = DatabaseWork(); |
1532 | 0 | break; |
1533 | 0 |
|
1534 | 0 | case State::SendingResults: |
1535 | 0 | SendResults(); |
1536 | 0 | return NS_OK; |
1537 | 0 |
|
1538 | 0 | default: |
1539 | 0 | MOZ_CRASH("Bad state!"); |
1540 | 0 | } |
1541 | 0 |
|
1542 | 0 | if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::SendingResults) { |
1543 | 0 | MaybeSetFailureCode(rv); |
1544 | 0 |
|
1545 | 0 | // Must set mState before dispatching otherwise we will race with the owning |
1546 | 0 | // thread. |
1547 | 0 | mState = State::SendingResults; |
1548 | 0 |
|
1549 | 0 | if (IsOnOwningThread()) { |
1550 | 0 | SendResults(); |
1551 | 0 | } else { |
1552 | 0 | MOZ_ALWAYS_SUCCEEDS( |
1553 | 0 | OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL)); |
1554 | 0 | } |
1555 | 0 | } |
1556 | 0 |
|
1557 | 0 | return NS_OK; |
1558 | 0 | } |
1559 | | |
1560 | | void |
1561 | | OpenOp::DirectoryLockAcquired(DirectoryLock* aLock) |
1562 | 0 | { |
1563 | 0 | AssertIsOnOwningThread(); |
1564 | 0 | MOZ_ASSERT(mState == State::DirectoryOpenPending); |
1565 | 0 | MOZ_ASSERT(!mDirectoryLock); |
1566 | 0 |
|
1567 | 0 | mDirectoryLock = aLock; |
1568 | 0 |
|
1569 | 0 | nsresult rv = SendToIOThread(); |
1570 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1571 | 0 | MaybeSetFailureCode(rv); |
1572 | 0 |
|
1573 | 0 | // The caller holds a strong reference to us, no need for a self reference |
1574 | 0 | // before calling Run(). |
1575 | 0 |
|
1576 | 0 | mState = State::SendingResults; |
1577 | 0 | MOZ_ALWAYS_SUCCEEDS(Run()); |
1578 | 0 |
|
1579 | 0 | return; |
1580 | 0 | } |
1581 | 0 | } |
1582 | | |
1583 | | void |
1584 | | OpenOp::DirectoryLockFailed() |
1585 | 0 | { |
1586 | 0 | AssertIsOnOwningThread(); |
1587 | 0 | MOZ_ASSERT(mState == State::DirectoryOpenPending); |
1588 | 0 | MOZ_ASSERT(!mDirectoryLock); |
1589 | 0 |
|
1590 | 0 | MaybeSetFailureCode(NS_ERROR_FAILURE); |
1591 | 0 |
|
1592 | 0 | // The caller holds a strong reference to us, no need for a self reference |
1593 | 0 | // before calling Run(). |
1594 | 0 |
|
1595 | 0 | mState = State::SendingResults; |
1596 | 0 | MOZ_ALWAYS_SUCCEEDS(Run()); |
1597 | 0 | } |
1598 | | |
1599 | | SeekOp::SeekOp(Connection* aConnection, |
1600 | | const SDBRequestParams& aParams) |
1601 | | : ConnectionOperationBase(aConnection) |
1602 | | , mParams(aParams.get_SDBRequestSeekParams()) |
1603 | 0 | { |
1604 | 0 | MOZ_ASSERT(aParams.type() == SDBRequestParams::TSDBRequestSeekParams); |
1605 | 0 | } |
1606 | | |
1607 | | nsresult |
1608 | | SeekOp::DoDatabaseWork(nsIFileStream* aFileStream) |
1609 | 0 | { |
1610 | 0 | AssertIsOnIOThread(); |
1611 | 0 | MOZ_ASSERT(aFileStream); |
1612 | 0 |
|
1613 | 0 | nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aFileStream); |
1614 | 0 | MOZ_ASSERT(seekableStream); |
1615 | 0 |
|
1616 | 0 | nsresult rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, |
1617 | 0 | mParams.offset()); |
1618 | 0 |
|
1619 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1620 | 0 | return rv; |
1621 | 0 | } |
1622 | 0 | |
1623 | 0 | return NS_OK; |
1624 | 0 | } |
1625 | | |
1626 | | void |
1627 | | SeekOp::GetResponse(SDBRequestResponse& aResponse) |
1628 | 0 | { |
1629 | 0 | aResponse = SDBRequestSeekResponse(); |
1630 | 0 | } |
1631 | | |
1632 | | ReadOp::ReadOp(Connection* aConnection, |
1633 | | const SDBRequestParams& aParams) |
1634 | | : ConnectionOperationBase(aConnection) |
1635 | | , mParams(aParams.get_SDBRequestReadParams()) |
1636 | 0 | { |
1637 | 0 | MOZ_ASSERT(aParams.type() == SDBRequestParams::TSDBRequestReadParams); |
1638 | 0 | } |
1639 | | |
1640 | | bool |
1641 | | ReadOp::Init() |
1642 | 0 | { |
1643 | 0 | AssertIsOnOwningThread(); |
1644 | 0 |
|
1645 | 0 | if (NS_WARN_IF(!ConnectionOperationBase::Init())) { |
1646 | 0 | return false; |
1647 | 0 | } |
1648 | 0 | |
1649 | 0 | mOutputStream = MemoryOutputStream::Create(mParams.size()); |
1650 | 0 | if (NS_WARN_IF(!mOutputStream)) { |
1651 | 0 | return false; |
1652 | 0 | } |
1653 | 0 | |
1654 | 0 | return true; |
1655 | 0 | } |
1656 | | |
1657 | | nsresult |
1658 | | ReadOp::DoDatabaseWork(nsIFileStream* aFileStream) |
1659 | 0 | { |
1660 | 0 | AssertIsOnIOThread(); |
1661 | 0 | MOZ_ASSERT(aFileStream); |
1662 | 0 |
|
1663 | 0 | nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(aFileStream); |
1664 | 0 | MOZ_ASSERT(inputStream); |
1665 | 0 |
|
1666 | 0 | nsresult rv; |
1667 | 0 |
|
1668 | 0 | uint64_t offset = 0; |
1669 | 0 |
|
1670 | 0 | do { |
1671 | 0 | char copyBuffer[kCopyBufferSize]; |
1672 | 0 |
|
1673 | 0 | uint64_t max = mParams.size() - offset; |
1674 | 0 | if (max == 0) { |
1675 | 0 | break; |
1676 | 0 | } |
1677 | 0 | |
1678 | 0 | uint32_t count = sizeof(copyBuffer); |
1679 | 0 | if (count > max) { |
1680 | 0 | count = max; |
1681 | 0 | } |
1682 | 0 |
|
1683 | 0 | uint32_t numRead; |
1684 | 0 | rv = inputStream->Read(copyBuffer, count, &numRead); |
1685 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1686 | 0 | return rv; |
1687 | 0 | } |
1688 | 0 | |
1689 | 0 | if (!numRead) { |
1690 | 0 | break; |
1691 | 0 | } |
1692 | 0 | |
1693 | 0 | uint32_t numWrite; |
1694 | 0 | rv = mOutputStream->Write(copyBuffer, numRead, &numWrite); |
1695 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1696 | 0 | return rv; |
1697 | 0 | } |
1698 | 0 | |
1699 | 0 | if (NS_WARN_IF(numWrite != numRead)) { |
1700 | 0 | return NS_ERROR_FAILURE; |
1701 | 0 | } |
1702 | 0 | |
1703 | 0 | offset += numWrite; |
1704 | 0 | } while (true); |
1705 | 0 |
|
1706 | 0 | MOZ_ASSERT(offset == mParams.size()); |
1707 | 0 |
|
1708 | 0 | MOZ_ALWAYS_SUCCEEDS(mOutputStream->Close()); |
1709 | 0 |
|
1710 | 0 | return NS_OK; |
1711 | 0 | } |
1712 | | |
1713 | | void |
1714 | | ReadOp::GetResponse(SDBRequestResponse& aResponse) |
1715 | 0 | { |
1716 | 0 | aResponse = SDBRequestReadResponse(mOutputStream->Data()); |
1717 | 0 | } |
1718 | | |
1719 | | WriteOp::WriteOp(Connection* aConnection, |
1720 | | const SDBRequestParams& aParams) |
1721 | | : ConnectionOperationBase(aConnection) |
1722 | | , mParams(aParams.get_SDBRequestWriteParams()) |
1723 | | , mSize(0) |
1724 | 0 | { |
1725 | 0 | MOZ_ASSERT(aParams.type() == SDBRequestParams::TSDBRequestWriteParams); |
1726 | 0 | } |
1727 | | |
1728 | | bool |
1729 | | WriteOp::Init() |
1730 | 0 | { |
1731 | 0 | AssertIsOnOwningThread(); |
1732 | 0 |
|
1733 | 0 | if (NS_WARN_IF(!ConnectionOperationBase::Init())) { |
1734 | 0 | return false; |
1735 | 0 | } |
1736 | 0 | |
1737 | 0 | const nsCString& string = mParams.data(); |
1738 | 0 |
|
1739 | 0 | nsCOMPtr<nsIInputStream> inputStream; |
1740 | 0 | nsresult rv = |
1741 | 0 | NS_NewCStringInputStream(getter_AddRefs(inputStream), string); |
1742 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1743 | 0 | return false; |
1744 | 0 | } |
1745 | 0 | |
1746 | 0 | mInputStream = std::move(inputStream); |
1747 | 0 | mSize = string.Length(); |
1748 | 0 |
|
1749 | 0 | return true; |
1750 | 0 | } |
1751 | | |
1752 | | nsresult |
1753 | | WriteOp::DoDatabaseWork(nsIFileStream* aFileStream) |
1754 | 0 | { |
1755 | 0 | AssertIsOnIOThread(); |
1756 | 0 | MOZ_ASSERT(aFileStream); |
1757 | 0 |
|
1758 | 0 | nsCOMPtr<nsIOutputStream> outputStream = do_QueryInterface(aFileStream); |
1759 | 0 | MOZ_ASSERT(outputStream); |
1760 | 0 |
|
1761 | 0 | nsresult rv; |
1762 | 0 |
|
1763 | 0 | do { |
1764 | 0 | char copyBuffer[kCopyBufferSize]; |
1765 | 0 |
|
1766 | 0 | uint32_t numRead; |
1767 | 0 | rv = mInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead); |
1768 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1769 | 0 | break; |
1770 | 0 | } |
1771 | 0 | |
1772 | 0 | if (!numRead) { |
1773 | 0 | break; |
1774 | 0 | } |
1775 | 0 | |
1776 | 0 | uint32_t numWrite; |
1777 | 0 | rv = outputStream->Write(copyBuffer, numRead, &numWrite); |
1778 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1779 | 0 | return rv; |
1780 | 0 | } |
1781 | 0 | |
1782 | 0 | if (NS_WARN_IF(numWrite != numRead)) { |
1783 | 0 | return NS_ERROR_FAILURE; |
1784 | 0 | } |
1785 | 0 | } while (true); |
1786 | 0 |
|
1787 | 0 | MOZ_ALWAYS_SUCCEEDS(mInputStream->Close()); |
1788 | 0 |
|
1789 | 0 | return NS_OK; |
1790 | 0 | } |
1791 | | |
1792 | | void |
1793 | | WriteOp::GetResponse(SDBRequestResponse& aResponse) |
1794 | 0 | { |
1795 | 0 | aResponse = SDBRequestWriteResponse(); |
1796 | 0 | } |
1797 | | |
1798 | | CloseOp::CloseOp(Connection* aConnection) |
1799 | | : ConnectionOperationBase(aConnection) |
1800 | 0 | { } |
1801 | | |
1802 | | nsresult |
1803 | | CloseOp::DoDatabaseWork(nsIFileStream* aFileStream) |
1804 | 0 | { |
1805 | 0 | AssertIsOnIOThread(); |
1806 | 0 | MOZ_ASSERT(aFileStream); |
1807 | 0 |
|
1808 | 0 | nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(aFileStream); |
1809 | 0 | MOZ_ASSERT(inputStream); |
1810 | 0 |
|
1811 | 0 | nsresult rv = inputStream->Close(); |
1812 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1813 | 0 | return rv; |
1814 | 0 | } |
1815 | 0 | |
1816 | 0 | return NS_OK; |
1817 | 0 | } |
1818 | | |
1819 | | void |
1820 | | CloseOp::GetResponse(SDBRequestResponse& aResponse) |
1821 | 0 | { |
1822 | 0 | aResponse = SDBRequestCloseResponse(); |
1823 | 0 | } |
1824 | | |
1825 | | void |
1826 | | CloseOp::OnSuccess() |
1827 | 0 | { |
1828 | 0 | AssertIsOnOwningThread(); |
1829 | 0 |
|
1830 | 0 | GetConnection()->OnClose(); |
1831 | 0 | } |
1832 | | |
1833 | | /******************************************************************************* |
1834 | | * QuotaClient |
1835 | | ******************************************************************************/ |
1836 | | |
1837 | | QuotaClient* QuotaClient::sInstance = nullptr; |
1838 | | |
1839 | | QuotaClient::QuotaClient() |
1840 | | : mShutdownRequested(false) |
1841 | 0 | { |
1842 | 0 | AssertIsOnBackgroundThread(); |
1843 | 0 | MOZ_ASSERT(!sInstance, "We expect this to be a singleton!"); |
1844 | 0 |
|
1845 | 0 | sInstance = this; |
1846 | 0 | } |
1847 | | |
1848 | | QuotaClient::~QuotaClient() |
1849 | 0 | { |
1850 | 0 | AssertIsOnBackgroundThread(); |
1851 | 0 | MOZ_ASSERT(sInstance == this, "We expect this to be a singleton!"); |
1852 | 0 |
|
1853 | 0 | sInstance = nullptr; |
1854 | 0 | } |
1855 | | |
1856 | | mozilla::dom::quota::Client::Type |
1857 | | QuotaClient::GetType() |
1858 | 0 | { |
1859 | 0 | return QuotaClient::SDB; |
1860 | 0 | } |
1861 | | |
1862 | | nsresult |
1863 | | QuotaClient::InitOrigin(PersistenceType aPersistenceType, |
1864 | | const nsACString& aGroup, |
1865 | | const nsACString& aOrigin, |
1866 | | const AtomicBool& aCanceled, |
1867 | | UsageInfo* aUsageInfo) |
1868 | 0 | { |
1869 | 0 | AssertIsOnIOThread(); |
1870 | 0 |
|
1871 | 0 | if (!aUsageInfo) { |
1872 | 0 | return NS_OK; |
1873 | 0 | } |
1874 | 0 | |
1875 | 0 | return GetUsageForOrigin(aPersistenceType, |
1876 | 0 | aGroup, |
1877 | 0 | aOrigin, |
1878 | 0 | aCanceled, |
1879 | 0 | aUsageInfo); |
1880 | 0 | } |
1881 | | |
1882 | | nsresult |
1883 | | QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType, |
1884 | | const nsACString& aGroup, |
1885 | | const nsACString& aOrigin, |
1886 | | const AtomicBool& aCanceled, |
1887 | | UsageInfo* aUsageInfo) |
1888 | 0 | { |
1889 | 0 | AssertIsOnIOThread(); |
1890 | 0 | MOZ_ASSERT(aUsageInfo); |
1891 | 0 |
|
1892 | 0 | QuotaManager* quotaManager = QuotaManager::Get(); |
1893 | 0 | MOZ_ASSERT(quotaManager); |
1894 | 0 |
|
1895 | 0 | nsCOMPtr<nsIFile> directory; |
1896 | 0 | nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin, |
1897 | 0 | getter_AddRefs(directory)); |
1898 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1899 | 0 | return rv; |
1900 | 0 | } |
1901 | 0 | |
1902 | 0 | MOZ_ASSERT(directory); |
1903 | 0 |
|
1904 | 0 | rv = directory->Append(NS_LITERAL_STRING(SDB_DIRECTORY_NAME)); |
1905 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1906 | 0 | return rv; |
1907 | 0 | } |
1908 | 0 | |
1909 | 0 | DebugOnly<bool> exists; |
1910 | 0 | MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists); |
1911 | 0 |
|
1912 | 0 | nsCOMPtr<nsIDirectoryEnumerator> entries; |
1913 | 0 | rv = directory->GetDirectoryEntries(getter_AddRefs(entries)); |
1914 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1915 | 0 | return rv; |
1916 | 0 | } |
1917 | 0 | |
1918 | 0 | bool hasMore; |
1919 | 0 | while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && |
1920 | 0 | hasMore && !aCanceled) { |
1921 | 0 | nsCOMPtr<nsISupports> entry; |
1922 | 0 | rv = entries->GetNext(getter_AddRefs(entry)); |
1923 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1924 | 0 | return rv; |
1925 | 0 | } |
1926 | 0 | |
1927 | 0 | nsCOMPtr<nsIFile> file = do_QueryInterface(entry); |
1928 | 0 | MOZ_ASSERT(file); |
1929 | 0 |
|
1930 | 0 | int64_t fileSize; |
1931 | 0 | rv = file->GetFileSize(&fileSize); |
1932 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1933 | 0 | return rv; |
1934 | 0 | } |
1935 | 0 | |
1936 | 0 | MOZ_ASSERT(fileSize >= 0); |
1937 | 0 |
|
1938 | 0 | aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize)); |
1939 | 0 | } |
1940 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
1941 | 0 | return rv; |
1942 | 0 | } |
1943 | 0 | |
1944 | 0 | return NS_OK; |
1945 | 0 | } |
1946 | | |
1947 | | void |
1948 | | QuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType, |
1949 | | const nsACString& aOrigin) |
1950 | 0 | { |
1951 | 0 | AssertIsOnIOThread(); |
1952 | 0 | } |
1953 | | |
1954 | | void |
1955 | | QuotaClient::ReleaseIOThreadObjects() |
1956 | 0 | { |
1957 | 0 | AssertIsOnIOThread(); |
1958 | 0 | } |
1959 | | |
1960 | | void |
1961 | | QuotaClient::AbortOperations(const nsACString& aOrigin) |
1962 | 0 | { |
1963 | 0 | AssertIsOnBackgroundThread(); |
1964 | 0 |
|
1965 | 0 | if (gOpenConnections) { |
1966 | 0 | for (Connection* connection : *gOpenConnections) { |
1967 | 0 | if (aOrigin.IsVoid() || connection->Origin() == aOrigin) { |
1968 | 0 | connection->AllowToClose(); |
1969 | 0 | } |
1970 | 0 | } |
1971 | 0 | } |
1972 | 0 | } |
1973 | | |
1974 | | void |
1975 | | QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId) |
1976 | 0 | { |
1977 | 0 | AssertIsOnBackgroundThread(); |
1978 | 0 | } |
1979 | | |
1980 | | void |
1981 | | QuotaClient::StartIdleMaintenance() |
1982 | 0 | { |
1983 | 0 | AssertIsOnBackgroundThread(); |
1984 | 0 | } |
1985 | | |
1986 | | void |
1987 | | QuotaClient::StopIdleMaintenance() |
1988 | 0 | { |
1989 | 0 | AssertIsOnBackgroundThread(); |
1990 | 0 | } |
1991 | | |
1992 | | void |
1993 | | QuotaClient::ShutdownWorkThreads() |
1994 | 0 | { |
1995 | 0 | AssertIsOnBackgroundThread(); |
1996 | 0 | MOZ_ASSERT(!mShutdownRequested); |
1997 | 0 |
|
1998 | 0 | mShutdownRequested = true; |
1999 | 0 |
|
2000 | 0 | if (gOpenConnections) { |
2001 | 0 | for (Connection* connection : *gOpenConnections) { |
2002 | 0 | connection->AllowToClose(); |
2003 | 0 | } |
2004 | 0 |
|
2005 | 0 | MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return !gOpenConnections; })); |
2006 | 0 | } |
2007 | 0 | } |
2008 | | |
2009 | | } // namespace dom |
2010 | | } // namespace mozilla |