1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "modules/indexeddb/IDBOpenDBRequest.h" 28 29 #include "bindings/v8/Nullable.h" 30 #include "core/dom/ExceptionCode.h" 31 #include "core/dom/ExecutionContext.h" 32 #include "modules/indexeddb/IDBDatabase.h" 33 #include "modules/indexeddb/IDBDatabaseCallbacks.h" 34 #include "modules/indexeddb/IDBPendingTransactionMonitor.h" 35 #include "modules/indexeddb/IDBTracing.h" 36 #include "modules/indexeddb/IDBVersionChangeEvent.h" 37 38 using blink::WebIDBDatabase; 39 40 namespace WebCore { 41 42 IDBOpenDBRequest* IDBOpenDBRequest::create(ScriptState* scriptState, IDBDatabaseCallbacks* callbacks, int64_t transactionId, int64_t version) 43 { 44 IDBOpenDBRequest* request = adoptRefCountedGarbageCollectedWillBeNoop(new IDBOpenDBRequest(scriptState, callbacks, transactionId, version)); 45 request->suspendIfNeeded(); 46 return request; 47 } 48 49 IDBOpenDBRequest::IDBOpenDBRequest(ScriptState* scriptState, IDBDatabaseCallbacks* callbacks, int64_t transactionId, int64_t version) 50 : IDBRequest(scriptState, IDBAny::createNull(), 0) 51 , m_databaseCallbacks(callbacks) 52 , m_transactionId(transactionId) 53 , m_version(version) 54 { 55 ASSERT(!resultAsAny()); 56 ScriptWrappable::init(this); 57 } 58 59 IDBOpenDBRequest::~IDBOpenDBRequest() 60 { 61 } 62 63 void IDBOpenDBRequest::trace(Visitor* visitor) 64 { 65 visitor->trace(m_databaseCallbacks); 66 IDBRequest::trace(visitor); 67 } 68 69 const AtomicString& IDBOpenDBRequest::interfaceName() const 70 { 71 return EventTargetNames::IDBOpenDBRequest; 72 } 73 74 void IDBOpenDBRequest::onBlocked(int64_t oldVersion) 75 { 76 IDB_TRACE("IDBOpenDBRequest::onBlocked()"); 77 if (!shouldEnqueueEvent()) 78 return; 79 Nullable<unsigned long long> newVersionNullable = (m_version == IDBDatabaseMetadata::DefaultIntVersion) ? Nullable<unsigned long long>() : Nullable<unsigned long long>(m_version); 80 enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::blocked, oldVersion, newVersionNullable)); 81 } 82 83 void IDBOpenDBRequest::onUpgradeNeeded(int64_t oldVersion, PassOwnPtr<WebIDBDatabase> backend, const IDBDatabaseMetadata& metadata, blink::WebIDBDataLoss dataLoss, String dataLossMessage) 84 { 85 IDB_TRACE("IDBOpenDBRequest::onUpgradeNeeded()"); 86 if (m_contextStopped || !executionContext()) { 87 OwnPtr<WebIDBDatabase> db = backend; 88 db->abort(m_transactionId); 89 db->close(); 90 return; 91 } 92 if (!shouldEnqueueEvent()) 93 return; 94 95 ASSERT(m_databaseCallbacks); 96 97 IDBDatabase* idbDatabase = IDBDatabase::create(executionContext(), backend, m_databaseCallbacks.release()); 98 idbDatabase->setMetadata(metadata); 99 100 if (oldVersion == IDBDatabaseMetadata::NoIntVersion) { 101 // This database hasn't had an integer version before. 102 oldVersion = IDBDatabaseMetadata::DefaultIntVersion; 103 } 104 IDBDatabaseMetadata oldMetadata(metadata); 105 oldMetadata.intVersion = oldVersion; 106 107 m_transaction = IDBTransaction::create(executionContext(), m_transactionId, idbDatabase, this, oldMetadata); 108 setResult(IDBAny::create(idbDatabase)); 109 110 if (m_version == IDBDatabaseMetadata::NoIntVersion) 111 m_version = 1; 112 enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::upgradeneeded, oldVersion, m_version, dataLoss, dataLossMessage)); 113 } 114 115 void IDBOpenDBRequest::onSuccess(PassOwnPtr<WebIDBDatabase> backend, const IDBDatabaseMetadata& metadata) 116 { 117 IDB_TRACE("IDBOpenDBRequest::onSuccess()"); 118 if (m_contextStopped || !executionContext()) { 119 OwnPtr<WebIDBDatabase> db = backend; 120 if (db) 121 db->close(); 122 return; 123 } 124 if (!shouldEnqueueEvent()) 125 return; 126 127 IDBDatabase* idbDatabase = 0; 128 if (resultAsAny()) { 129 // Previous onUpgradeNeeded call delivered the backend. 130 ASSERT(!backend.get()); 131 idbDatabase = resultAsAny()->idbDatabase(); 132 ASSERT(idbDatabase); 133 ASSERT(!m_databaseCallbacks); 134 } else { 135 ASSERT(backend.get()); 136 ASSERT(m_databaseCallbacks); 137 idbDatabase = IDBDatabase::create(executionContext(), backend, m_databaseCallbacks.release()); 138 setResult(IDBAny::create(idbDatabase)); 139 } 140 idbDatabase->setMetadata(metadata); 141 enqueueEvent(Event::create(EventTypeNames::success)); 142 } 143 144 void IDBOpenDBRequest::onSuccess(int64_t oldVersion) 145 { 146 IDB_TRACE("IDBOpenDBRequest::onSuccess()"); 147 if (!shouldEnqueueEvent()) 148 return; 149 if (oldVersion == IDBDatabaseMetadata::NoIntVersion) { 150 // This database hasn't had an integer version before. 151 oldVersion = IDBDatabaseMetadata::DefaultIntVersion; 152 } 153 setResult(IDBAny::createUndefined()); 154 enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::success, oldVersion, Nullable<unsigned long long>())); 155 } 156 157 bool IDBOpenDBRequest::shouldEnqueueEvent() const 158 { 159 if (m_contextStopped || !executionContext()) 160 return false; 161 ASSERT(m_readyState == PENDING || m_readyState == DONE); 162 if (m_requestAborted) 163 return false; 164 return true; 165 } 166 167 bool IDBOpenDBRequest::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 168 { 169 // If the connection closed between onUpgradeNeeded and the delivery of the "success" event, 170 // an "error" event should be fired instead. 171 if (event->type() == EventTypeNames::success && resultAsAny()->type() == IDBAny::IDBDatabaseType && resultAsAny()->idbDatabase()->isClosePending()) { 172 dequeueEvent(event.get()); 173 setResult(0); 174 onError(DOMError::create(AbortError, "The connection was closed.")); 175 return false; 176 } 177 178 return IDBRequest::dispatchEvent(event); 179 } 180 181 } // namespace WebCore 182