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/core/frame/local_dom_window.h"
33 #include "third_party/blink/renderer/modules/webdatabase/database.h"
34 #include "third_party/blink/renderer/modules/webdatabase/database_manager.h"
35 #include "third_party/blink/renderer/modules/webdatabase/database_task.h"
36 #include "third_party/blink/renderer/modules/webdatabase/database_thread.h"
37 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
38 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
39 #include "third_party/blink/renderer/platform/wtf/assertions.h"
40 
41 namespace blink {
42 
43 // How the DatabaseContext Life-Cycle works?
44 // ========================================
45 // ... in other words, who's keeping the DatabaseContext alive and how long does
46 // it need to stay alive?
47 //
48 // The DatabaseContext is referenced from:
49 // 1. DatabaseManager
50 // 2. Database
51 //
52 // At Birth:
53 // ========
54 // We create a DatabaseContext only when there is a need i.e. the script tries
55 // to open a Database via DatabaseManager::openDatabase().
56 //
57 // The DatabaseContext constructor will register itself to DatabaseManager. This
58 // lets DatabaseContext keep itself alive until it is unregisterd in
59 // contextDestroyed().
60 //
61 // Once a DatabaseContext is associated with a ExecutionContext, it will
62 // live until after the ExecutionContext destructs. This is true even if
63 // we don't succeed in opening any Databases for that context. When we do
64 // succeed in opening Databases for this ExecutionContext, the Database
65 // will re-use the same DatabaseContext.
66 //
67 // At Shutdown:
68 // ===========
69 // During shutdown, the DatabaseContext needs to:
70 // 1. "outlive" the ExecutionContext.
71 //    - This is needed because the DatabaseContext needs to remove itself from
72 //    the
73 //      ExecutionContext's ExecutionContextLifecycleObserver list and
74 //      ExecutionContextLifecycleObserver
75 //      list. This removal needs to be executed on the script's thread. Hence,
76 //      we
77 //      rely on the ExecutionContext's shutdown process to call
78 //      stop() and contextDestroyed() to give us a chance to clean these up from
79 //      the script thread.
80 //
81 // 2. "outlive" the Databases.
82 //    - This is because they may make use of the DatabaseContext to execute a
83 //      close task and shutdown in an orderly manner. When the Databases are
84 //      destructed, they will release the DatabaseContext reference from the
85 //      DatabaseThread.
86 //
87 // During shutdown, the ExecutionContext is shutting down on the script thread
88 // while the Databases are shutting down on the DatabaseThread. Hence, there can
89 // be a race condition as to whether the ExecutionContext or the Databases
90 // destruct first.
91 //
92 // The Members in the Databases and DatabaseManager will ensure that the
93 // DatabaseContext will outlive Database and ExecutionContext regardless of
94 // which of the 2 destructs first.
95 
Create(ExecutionContext * context)96 DatabaseContext* DatabaseContext::Create(ExecutionContext* context) {
97   DatabaseContext* self = MakeGarbageCollected<DatabaseContext>(context);
98   DatabaseManager::Manager().RegisterDatabaseContext(self);
99   return self;
100 }
101 
DatabaseContext(ExecutionContext * context)102 DatabaseContext::DatabaseContext(ExecutionContext* context)
103     : ExecutionContextLifecycleObserver(context),
104       has_open_databases_(false),
105       has_requested_termination_(false) {
106   DCHECK(IsMainThread());
107 
108   // For debug accounting only. We must do this before we register the
109   // instance. The assertions assume this.
110   DatabaseManager::Manager().DidConstructDatabaseContext();
111 }
112 
~DatabaseContext()113 DatabaseContext::~DatabaseContext() {
114   // For debug accounting only. We must call this last. The assertions assume
115   // this.
116   DatabaseManager::Manager().DidDestructDatabaseContext();
117 }
118 
Trace(Visitor * visitor) const119 void DatabaseContext::Trace(Visitor* visitor) const {
120   visitor->Trace(database_thread_);
121   ExecutionContextLifecycleObserver::Trace(visitor);
122 }
123 
124 // This is called if the associated ExecutionContext is destructing while
125 // we're still associated with it. That's our cue to disassociate and shutdown.
126 // To do this, we stop the database and let everything shutdown naturally
127 // because the database closing process may still make use of this context.
128 // It is not safe to just delete the context here.
ContextDestroyed()129 void DatabaseContext::ContextDestroyed() {
130   StopDatabases();
131   DatabaseManager::Manager().UnregisterDatabaseContext(this);
132 }
133 
Backend()134 DatabaseContext* DatabaseContext::Backend() {
135   return this;
136 }
137 
GetDatabaseThread()138 DatabaseThread* DatabaseContext::GetDatabaseThread() {
139   if (!database_thread_ && !has_open_databases_) {
140     // It's OK to ask for the m_databaseThread after we've requested
141     // termination because we're still using it to execute the closing
142     // of the database. However, it is NOT OK to create a new thread
143     // after we've requested termination.
144     DCHECK(!has_requested_termination_);
145 
146     // Create the database thread on first request - but not if at least one
147     // database was already opened, because in that case we already had a
148     // database thread and terminated it and should not create another.
149     database_thread_ = MakeGarbageCollected<DatabaseThread>();
150     database_thread_->Start();
151   }
152 
153   return database_thread_.Get();
154 }
155 
DatabaseThreadAvailable()156 bool DatabaseContext::DatabaseThreadAvailable() {
157   return GetDatabaseThread() && !has_requested_termination_;
158 }
159 
StopDatabases()160 void DatabaseContext::StopDatabases() {
161   // Though we initiate termination of the DatabaseThread here in
162   // stopDatabases(), we can't clear the m_databaseThread ref till we get to
163   // the destructor. This is because the Databases that are managed by
164   // DatabaseThread still rely on this ref between the context and the thread
165   // to execute the task for closing the database. By the time we get to the
166   // destructor, we're guaranteed that the databases are destructed (which is
167   // why our ref count is 0 then and we're destructing). Then, the
168   // m_databaseThread RefPtr destructor will deref and delete the
169   // DatabaseThread.
170 
171   if (DatabaseThreadAvailable()) {
172     has_requested_termination_ = true;
173     // This blocks until the database thread finishes the cleanup task.
174     database_thread_->Terminate();
175   }
176 }
177 
AllowDatabaseAccess() const178 bool DatabaseContext::AllowDatabaseAccess() const {
179   return To<LocalDOMWindow>(GetExecutionContext())->document()->IsActive();
180 }
181 
GetSecurityOrigin() const182 const SecurityOrigin* DatabaseContext::GetSecurityOrigin() const {
183   return GetExecutionContext()->GetSecurityOrigin();
184 }
185 
IsContextThread() const186 bool DatabaseContext::IsContextThread() const {
187   return GetExecutionContext()->IsContextThread();
188 }
189 
190 }  // namespace blink
191