blob: 145e9faa531a99c8a976ebdf2d925a5495347cca [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/modules/indexeddb/idb_open_db_request.h"
#include <memory>
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database_callbacks.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"
using blink::WebIDBDatabase;
namespace blink {
IDBOpenDBRequest* IDBOpenDBRequest::Create(
ScriptState* script_state,
IDBDatabaseCallbacks* callbacks,
int64_t transaction_id,
int64_t version,
IDBRequest::AsyncTraceState metrics) {
IDBOpenDBRequest* request = new IDBOpenDBRequest(
script_state, callbacks, transaction_id, version, std::move(metrics));
request->PauseIfNeeded();
return request;
}
IDBOpenDBRequest::IDBOpenDBRequest(ScriptState* script_state,
IDBDatabaseCallbacks* callbacks,
int64_t transaction_id,
int64_t version,
IDBRequest::AsyncTraceState metrics)
: IDBRequest(script_state,
IDBRequest::Source(),
nullptr,
std::move(metrics)),
database_callbacks_(callbacks),
transaction_id_(transaction_id),
version_(version) {
DCHECK(!ResultAsAny());
}
IDBOpenDBRequest::~IDBOpenDBRequest() = default;
void IDBOpenDBRequest::Trace(blink::Visitor* visitor) {
visitor->Trace(database_callbacks_);
IDBRequest::Trace(visitor);
}
void IDBOpenDBRequest::ContextDestroyed(ExecutionContext* destroyed_context) {
IDBRequest::ContextDestroyed(destroyed_context);
if (database_callbacks_)
database_callbacks_->DetachWebCallbacks();
}
const AtomicString& IDBOpenDBRequest::InterfaceName() const {
return event_target_names::kIDBOpenDBRequest;
}
void IDBOpenDBRequest::EnqueueBlocked(int64_t old_version) {
IDB_TRACE("IDBOpenDBRequest::onBlocked()");
if (!ShouldEnqueueEvent())
return;
base::Optional<unsigned long long> new_version_nullable;
if (version_ != IDBDatabaseMetadata::kDefaultVersion) {
new_version_nullable = version_;
}
EnqueueEvent(IDBVersionChangeEvent::Create(
event_type_names::kBlocked, old_version, new_version_nullable));
}
void IDBOpenDBRequest::EnqueueUpgradeNeeded(
int64_t old_version,
std::unique_ptr<WebIDBDatabase> backend,
const IDBDatabaseMetadata& metadata,
WebIDBDataLoss data_loss,
String data_loss_message) {
IDB_TRACE("IDBOpenDBRequest::onUpgradeNeeded()");
if (!ShouldEnqueueEvent()) {
metrics_.RecordAndReset();
return;
}
DCHECK(database_callbacks_);
IDBDatabase* idb_database =
IDBDatabase::Create(GetExecutionContext(), std::move(backend),
database_callbacks_.Release(), isolate_);
idb_database->SetMetadata(metadata);
if (old_version == IDBDatabaseMetadata::kNoVersion) {
// This database hasn't had a version before.
old_version = IDBDatabaseMetadata::kDefaultVersion;
}
IDBDatabaseMetadata old_database_metadata(
metadata.name, metadata.id, old_version, metadata.max_object_store_id);
transaction_ = IDBTransaction::CreateVersionChange(
GetExecutionContext(), transaction_id_, idb_database, this,
old_database_metadata);
SetResult(IDBAny::Create(idb_database));
if (version_ == IDBDatabaseMetadata::kNoVersion)
version_ = 1;
EnqueueEvent(IDBVersionChangeEvent::Create(event_type_names::kUpgradeneeded,
old_version, version_, data_loss,
data_loss_message));
}
void IDBOpenDBRequest::EnqueueResponse(std::unique_ptr<WebIDBDatabase> backend,
const IDBDatabaseMetadata& metadata) {
IDB_TRACE("IDBOpenDBRequest::onSuccess()");
if (!ShouldEnqueueEvent()) {
metrics_.RecordAndReset();
return;
}
IDBDatabase* idb_database = nullptr;
if (ResultAsAny()) {
// Previous OnUpgradeNeeded call delivered the backend.
DCHECK(!backend.get());
idb_database = ResultAsAny()->IdbDatabase();
DCHECK(idb_database);
DCHECK(!database_callbacks_);
} else {
DCHECK(backend.get());
DCHECK(database_callbacks_);
idb_database =
IDBDatabase::Create(GetExecutionContext(), std::move(backend),
database_callbacks_.Release(), isolate_);
SetResult(IDBAny::Create(idb_database));
}
idb_database->SetMetadata(metadata);
EnqueueEvent(Event::Create(event_type_names::kSuccess));
metrics_.RecordAndReset();
}
void IDBOpenDBRequest::EnqueueResponse(int64_t old_version) {
IDB_TRACE("IDBOpenDBRequest::onSuccess()");
if (!ShouldEnqueueEvent()) {
metrics_.RecordAndReset();
return;
}
if (old_version == IDBDatabaseMetadata::kNoVersion) {
// This database hasn't had an integer version before.
old_version = IDBDatabaseMetadata::kDefaultVersion;
}
SetResult(IDBAny::CreateUndefined());
EnqueueEvent(IDBVersionChangeEvent::Create(event_type_names::kSuccess,
old_version, base::nullopt));
metrics_.RecordAndReset();
}
bool IDBOpenDBRequest::ShouldEnqueueEvent() const {
if (!GetExecutionContext())
return false;
DCHECK(ready_state_ == PENDING || ready_state_ == DONE);
if (request_aborted_)
return false;
return true;
}
DispatchEventResult IDBOpenDBRequest::DispatchEventInternal(Event& event) {
// If the connection closed between onUpgradeNeeded and the delivery of the
// "success" event, an "error" event should be fired instead.
if (event.type() == event_type_names::kSuccess &&
ResultAsAny()->GetType() == IDBAny::kIDBDatabaseType &&
ResultAsAny()->IdbDatabase()->IsClosePending()) {
SetResult(nullptr);
HandleResponse(DOMException::Create(DOMExceptionCode::kAbortError,
"The connection was closed."));
return DispatchEventResult::kCanceledBeforeDispatch;
}
return IDBRequest::DispatchEventInternal(event);
}
} // namespace blink