blob: 175c2411c36a37f5b17faa41ae834d1bb60c0f26 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/indexeddb/IDBRequestLoader.h"
#include "core/dom/DOMException.h"
#include "core/fileapi/FileReaderLoader.h"
#include "modules/indexeddb/IDBRequest.h"
#include "modules/indexeddb/IDBRequestQueueItem.h"
#include "modules/indexeddb/IDBValue.h"
#include "modules/indexeddb/IDBValueWrapping.h"
#include "public/platform/modules/indexeddb/WebIDBDatabaseException.h"
namespace blink {
IDBRequestLoader::IDBRequestLoader(
IDBRequestQueueItem* queue_item,
Vector<scoped_refptr<IDBValue>>* result_values)
: queue_item_(queue_item), values_(result_values) {
DCHECK(IDBValueUnwrapper::IsWrapped(*values_));
}
IDBRequestLoader::~IDBRequestLoader() {
// TODO(pwnall): Do we need to call loader_->Cancel() here?
}
void IDBRequestLoader::Start() {
#if DCHECK_IS_ON()
DCHECK(!started_) << "Start() was already called";
started_ = true;
#endif // DCHECK_IS_ON()
// TODO(pwnall): Start() / StartNextValue() unwrap large values sequentially.
// Consider parallelizing. The main issue is that the Blob reads
// will have to be throttled somewhere, and the extra complexity
// only benefits applications that use getAll().
current_value_ = values_->begin();
StartNextValue();
}
void IDBRequestLoader::Cancel() {
#if DCHECK_IS_ON()
DCHECK(started_) << "Cancel() called on a loader that hasn't been Start()ed";
DCHECK(!canceled_) << "Cancel() was already called";
canceled_ = true;
DCHECK(file_reader_loading_);
file_reader_loading_ = false;
#endif // DCHECK_IS_ON()
if (loader_)
loader_->Cancel();
}
void IDBRequestLoader::StartNextValue() {
IDBValueUnwrapper unwrapper;
while (true) {
if (current_value_ == values_->end()) {
ReportSuccess();
return;
}
if (unwrapper.Parse(current_value_->get()))
break;
++current_value_;
}
DCHECK(current_value_ != values_->end());
ExecutionContext* context = queue_item_->Request()->GetExecutionContext();
if (!context) {
ReportError();
return;
}
wrapped_data_.ReserveCapacity(unwrapper.WrapperBlobSize());
#if DCHECK_IS_ON()
DCHECK(!file_reader_loading_);
file_reader_loading_ = true;
#endif // DCHECK_IS_ON()
loader_ = FileReaderLoader::Create(FileReaderLoader::kReadByClient, this);
loader_->Start(context, unwrapper.WrapperBlobHandle());
}
void IDBRequestLoader::DidStartLoading() {}
void IDBRequestLoader::DidReceiveDataForClient(const char* data,
unsigned data_length) {
DCHECK_LE(wrapped_data_.size() + data_length, wrapped_data_.capacity())
<< "The reader returned more data than we were prepared for";
wrapped_data_.Append(data, data_length);
}
void IDBRequestLoader::DidFinishLoading() {
#if DCHECK_IS_ON()
DCHECK(started_)
<< "FileReaderLoader called DidFinishLoading() before it was Start()ed";
DCHECK(!canceled_)
<< "FileReaderLoader called DidFinishLoading() after it was Cancel()ed";
DCHECK(file_reader_loading_);
file_reader_loading_ = false;
#endif // DCHECK_IS_ON()
*current_value_ = IDBValueUnwrapper::Unwrap(
current_value_->get(), SharedBuffer::AdoptVector(wrapped_data_));
++current_value_;
StartNextValue();
}
void IDBRequestLoader::DidFail(FileError::ErrorCode) {
#if DCHECK_IS_ON()
DCHECK(started_)
<< "FileReaderLoader called DidFail() before it was Start()ed";
DCHECK(!canceled_)
<< "FileReaderLoader called DidFail() after it was Cancel()ed";
DCHECK(file_reader_loading_);
file_reader_loading_ = false;
#endif // DCHECK_IS_ON()
ReportError();
}
void IDBRequestLoader::ReportSuccess() {
#if DCHECK_IS_ON()
DCHECK(started_);
DCHECK(!canceled_);
#endif // DCHECK_IS_ON()
queue_item_->OnResultLoadComplete();
}
void IDBRequestLoader::ReportError() {
#if DCHECK_IS_ON()
DCHECK(started_);
DCHECK(!canceled_);
#endif // DCHECK_IS_ON()
queue_item_->OnResultLoadComplete(
DOMException::Create(kDataError, "Failed to read large IndexedDB value"));
}
} // namespace blink