1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2011 Google, Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include "third_party/blink/renderer/modules/webdatabase/database_context.h"
29 
30 #include "third_party/blink/renderer/core/dom/document.h"
31 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
32 #include "third_party/blink/renderer/modules/webdatabase/database.h"
33 #include "third_party/blink/renderer/modules/webdatabase/database_manager.h"
34 #include "third_party/blink/renderer/modules/webdatabase/database_task.h"
35 #include "third_party/blink/renderer/modules/webdatabase/database_thread.h"
36 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
37 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
38 #include "third_party/blink/renderer/platform/wtf/assertions.h"
39 
40 namespace blink {
41 
42 // How the DatabaseContext Life-Cycle works?
43 // ========================================
44 // ... in other words, who's keeping the DatabaseContext alive and how long does
45 // it need to stay alive?
46 //
47 // The DatabaseContext is referenced from:
48 // 1. DatabaseManager
49 // 2. Database
50 //
51 // At Birth:
52 // ========
53 // We create a DatabaseContext only when there is a need i.e. the script tries
54 // to open a Database via DatabaseManager::openDatabase().
55 //
56 // The DatabaseContext constructor will register itself to DatabaseManager. This
57 // lets DatabaseContext keep itself alive until it is unregisterd in
58 // contextDestroyed().
59 //
60 // Once a DatabaseContext is associated with a ExecutionContext, it will
61 // live until after the ExecutionContext destructs. This is true even if
62 // we don't succeed in opening any Databases for that context. When we do
63 // succeed in opening Databases for this ExecutionContext, the Database
64 // will re-use the same DatabaseContext.
65 //
66 // At Shutdown:
67 // ===========
68 // During shutdown, the DatabaseContext needs to:
69 // 1. "outlive" the ExecutionContext.
70 //    - This is needed because the DatabaseContext needs to remove itself from
71 //    the
72 //      ExecutionContext's ExecutionContextLifecycleObserver list and
73 //      ExecutionContextLifecycleObserver
74 //      list. This removal needs to be executed on the script's thread. Hence,
75 //      we
76 //      rely on the ExecutionContext's shutdown process to call
77 //      stop() and contextDestroyed() to give us a chance to clean these up from
78 //      the script thread.
79 //
80 // 2. "outlive" the Databases.
81 //    - This is because they may make use of the DatabaseContext to execute a
82 //      close task and shutdown in an orderly manner. When the Databases are
83 //      destructed, they will release the DatabaseContext reference from the
84 //      DatabaseThread.
85 //
86 // During shutdown, the ExecutionContext is shutting down on the script thread
87 // while the Databases are shutting down on the DatabaseThread. Hence, there can
88 // be a race condition as to whether the ExecutionContext or the Databases
89 // destruct first.
90 //
91 // The Members in the Databases and DatabaseManager will ensure that the
92 // DatabaseContext will outlive Database and ExecutionContext regardless of
93 // which of the 2 destructs first.
94 
Create(ExecutionContext * context)95 DatabaseContext* DatabaseContext::Create(ExecutionContext* context) {
96   DatabaseContext* self = MakeGarbageCollected<DatabaseContext>(context);
97   DatabaseManager::Manager().RegisterDatabaseContext(self);
98   return self;
99 }
100 
DatabaseContext(ExecutionContext * context)101 DatabaseContext::DatabaseContext(ExecutionContext* context)
102     : ExecutionContextLifecycleObserver(context),
103       has_open_databases_(false),
104       has_requested_termination_(false) {
105   DCHECK(IsMainThread());
106 
107   // For debug accounting only. We must do this before we register the
108   // instance. The assertions assume this.
109   DatabaseManager::Manager().DidConstructDatabaseContext();
110 }
111 
~DatabaseContext()112 DatabaseContext::~DatabaseContext() {
113   // For debug accounting only. We must call this last. The assertions assume
114   // this.
115   DatabaseManager::Manager().DidDestructDatabaseContext();
116 }
117 
Trace(Visitor * visitor)118 void DatabaseContext::Trace(Visitor* visitor) {
119   visitor->Trace(database_thread_);
120   ExecutionContextLifecycleObserver::Trace(visitor);
121 }
122 
123 // This is called if the associated ExecutionContext is destructing while
124 // we're still associated with it. That's our cue to disassociate and shutdown.
125 // To do this, we stop the database and let everything shutdown naturally
126 // because the database closing process may still make use of this context.
127 // It is not safe to just delete the context here.
ContextDestroyed()128 void DatabaseContext::ContextDestroyed() {
129   StopDatabases();
130   DatabaseManager::Manager().UnregisterDatabaseContext(this);
131 }
132 
Backend()133 DatabaseContext* DatabaseContext::Backend() {
134   return this;
135 }
136 
GetDatabaseThread()137 DatabaseThread* DatabaseContext::GetDatabaseThread() {
138   if (!database_thread_ && !has_open_databases_) {
139     // It's OK to ask for the m_databaseThread after we've requested
140     // termination because we're still using it to execute the closing
141     // of the database. However, it is NOT OK to create a new thread
142     // after we've requested termination.
143     DCHECK(!has_requested_termination_);
144 
145     // Create the database thread on first request - but not if at least one
146     // database was already opened, because in that case we already had a
147     // database thread and terminated it and should not create another.
148     database_thread_ = MakeGarbageCollected<DatabaseThread>();
149     database_thread_->Start();
150   }
151 
152   return database_thread_.Get();
153 }
154 
DatabaseThreadAvailable()155 bool DatabaseContext::DatabaseThreadAvailable() {
156   return GetDatabaseThread() && !has_requested_termination_;
157 }
158 
StopDatabases()159 void DatabaseContext::StopDatabases() {
160   // Though we initiate termination of the DatabaseThread here in
161   // stopDatabases(), we can't clear the m_databaseThread ref till we get to
162   // the destructor. This is because the Databases that are managed by
163   // DatabaseThread still rely on this ref between the context and the thread
164   // to execute the task for closing the database. By the time we get to the
165   // destructor, we're guaranteed that the databases are destructed (which is
166   // why our ref count is 0 then and we're destructing). Then, the
167   // m_databaseThread RefPtr destructor will deref and delete the
168   // DatabaseThread.
169 
170   if (DatabaseThreadAvailable()) {
171     has_requested_termination_ = true;
172     // This blocks until the database thread finishes the cleanup task.
173     database_thread_->Terminate();
174   }
175 }
176 
AllowDatabaseAccess() const177 bool DatabaseContext::AllowDatabaseAccess() const {
178   return Document::From(GetExecutionContext())->IsActive();
179 }
180 
GetSecurityOrigin() const181 const SecurityOrigin* DatabaseContext::GetSecurityOrigin() const {
182   return GetExecutionContext()->GetSecurityOrigin();
183 }
184 
IsContextThread() const185 bool DatabaseContext::IsContextThread() const {
186   return GetExecutionContext()->IsContextThread();
187 }
188 
189 }  // namespace blink
190