| Index: content/browser/indexed_db/indexed_db_backing_store.cc
|
| diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
|
| index 162d451582494989dbaef89fe998b8ef3cb0e067..c92f75a1f4ca7e45510b398b3662390d3c20af5f 100644
|
| --- a/content/browser/indexed_db/indexed_db_backing_store.cc
|
| +++ b/content/browser/indexed_db/indexed_db_backing_store.cc
|
| @@ -12,6 +12,8 @@
|
| #include "base/metrics/histogram.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "content/browser/child_process_security_policy_impl.h"
|
| +#include "content/browser/indexed_db/indexed_db_blob_info.h"
|
| #include "content/browser/indexed_db/indexed_db_database_error.h"
|
| #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
|
| #include "content/browser/indexed_db/indexed_db_metadata.h"
|
| @@ -27,6 +29,7 @@
|
| #include "third_party/WebKit/public/platform/WebIDBTypes.h"
|
| #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
|
| #include "third_party/leveldatabase/env_chromium.h"
|
| +#include "webkit/browser/blob/blob_data_handle.h"
|
| #include "webkit/common/database/database_identifier.h"
|
|
|
| using base::StringPiece;
|
| @@ -45,6 +48,12 @@ static base::FilePath ComputeFileName(const GURL& origin_url) {
|
| .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
|
| }
|
|
|
| +static base::FilePath ComputeBlobPath(const GURL& origin_url) {
|
| + return base::FilePath()
|
| + .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
|
| + .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob"));
|
| +}
|
| +
|
| static base::FilePath ComputeCorruptionFileName(const GURL& origin_url) {
|
| return ComputeFileName(origin_url)
|
| .Append(FILE_PATH_LITERAL("corruption_info.json"));
|
| @@ -431,11 +440,13 @@ class DefaultLevelDBFactory : public LevelDBFactory {
|
| IndexedDBBackingStore::IndexedDBBackingStore(
|
| IndexedDBFactory* indexed_db_factory,
|
| const GURL& origin_url,
|
| + const base::FilePath& blob_path,
|
| scoped_ptr<LevelDBDatabase> db,
|
| scoped_ptr<LevelDBComparator> comparator,
|
| base::TaskRunner* task_runner)
|
| : indexed_db_factory_(indexed_db_factory),
|
| origin_url_(origin_url),
|
| + blob_path_(blob_path),
|
| origin_identifier_(ComputeOriginIdentifier(origin_url)),
|
| task_runner_(task_runner),
|
| db_(db.Pass()),
|
| @@ -443,6 +454,16 @@ IndexedDBBackingStore::IndexedDBBackingStore(
|
| active_blob_registry_(this) {}
|
|
|
| IndexedDBBackingStore::~IndexedDBBackingStore() {
|
| + if (!blob_path_.empty() && !child_process_ids_granted_.empty()) {
|
| + ChildProcessSecurityPolicyImpl* policy =
|
| + ChildProcessSecurityPolicyImpl::GetInstance();
|
| + std::set<int>::const_iterator iter;
|
| + for (iter = child_process_ids_granted_.begin();
|
| + iter != child_process_ids_granted_.end();
|
| + ++iter) {
|
| + policy->RevokeAllPermissionsForFile(*iter, blob_path_);
|
| + }
|
| + }
|
| // db_'s destructor uses comparator_. The order of destruction is important.
|
| db_.reset();
|
| comparator_.reset();
|
| @@ -661,6 +682,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
|
|
|
| const base::FilePath file_path =
|
| path_base.Append(ComputeFileName(origin_url));
|
| + const base::FilePath blob_path =
|
| + path_base.Append(ComputeBlobPath(origin_url));
|
|
|
| if (IsPathTooLong(file_path)) {
|
| HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG,
|
| @@ -756,6 +779,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
|
|
|
| return Create(indexed_db_factory,
|
| origin_url,
|
| + blob_path,
|
| db.Pass(),
|
| comparator.Pass(),
|
| task_runner);
|
| @@ -790,6 +814,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
|
|
|
| return Create(NULL /* indexed_db_factory */,
|
| origin_url,
|
| + base::FilePath(),
|
| db.Pass(),
|
| comparator.Pass(),
|
| task_runner);
|
| @@ -799,6 +824,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
|
| scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
|
| IndexedDBFactory* indexed_db_factory,
|
| const GURL& origin_url,
|
| + const base::FilePath& blob_path,
|
| scoped_ptr<LevelDBDatabase> db,
|
| scoped_ptr<LevelDBComparator> comparator,
|
| base::TaskRunner* task_runner) {
|
| @@ -807,6 +833,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
|
| scoped_refptr<IndexedDBBackingStore> backing_store(
|
| new IndexedDBBackingStore(indexed_db_factory,
|
| origin_url,
|
| + blob_path,
|
| db.Pass(),
|
| comparator.Pass(),
|
| task_runner));
|
| @@ -817,6 +844,14 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
|
| return backing_store;
|
| }
|
|
|
| +void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) {
|
| + if (!child_process_ids_granted_.count(child_process_id)) {
|
| + child_process_ids_granted_.insert(child_process_id);
|
| + ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
|
| + child_process_id, blob_path_);
|
| + }
|
| +}
|
| +
|
| std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
|
| leveldb::Status* s) {
|
| *s = leveldb::Status::OK();
|
| @@ -1119,7 +1154,7 @@ leveldb::Status IndexedDBBackingStore::GetObjectStores(
|
| INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
|
| }
|
|
|
| - s = it->Next(); // Is evicatble.
|
| + s = it->Next(); // Is evictable.
|
| if (!s.ok())
|
| break;
|
| if (!CheckObjectStoreAndMetaDataType(it.get(),
|
| @@ -1435,7 +1470,8 @@ leveldb::Status IndexedDBBackingStore::PutRecord(
|
| int64 database_id,
|
| int64 object_store_id,
|
| const IndexedDBKey& key,
|
| - const IndexedDBValue& value,
|
| + IndexedDBValue& value,
|
| + ScopedVector<webkit_blob::BlobDataHandle>* handles,
|
| RecordIdentifier* record_identifier) {
|
| IDB_TRACE("IndexedDBBackingStore::PutRecord");
|
| if (!KeyPrefix::ValidIds(database_id, object_store_id))
|
| @@ -1457,6 +1493,12 @@ leveldb::Status IndexedDBBackingStore::PutRecord(
|
| v.append(value.bits);
|
|
|
| leveldb_transaction->Put(object_store_data_key, &v);
|
| + transaction->PutBlobInfo(database_id,
|
| + object_store_id,
|
| + object_store_data_key,
|
| + &value.blob_info,
|
| + handles);
|
| + DCHECK(!handles->size());
|
|
|
| const std::string exists_entry_key =
|
| ExistsEntryKey::Encode(database_id, object_store_id, key);
|
| @@ -1502,6 +1544,8 @@ leveldb::Status IndexedDBBackingStore::DeleteRecord(
|
| const std::string object_store_data_key = ObjectStoreDataKey::Encode(
|
| database_id, object_store_id, record_identifier.primary_key());
|
| leveldb_transaction->Remove(object_store_data_key);
|
| + transaction->PutBlobInfo(
|
| + database_id, object_store_id, object_store_data_key, NULL, NULL);
|
|
|
| const std::string exists_entry_key = ExistsEntryKey::Encode(
|
| database_id, object_store_id, record_identifier.primary_key());
|
| @@ -2879,9 +2923,12 @@ IndexedDBBackingStore::OpenIndexCursor(
|
|
|
| IndexedDBBackingStore::Transaction::Transaction(
|
| IndexedDBBackingStore* backing_store)
|
| - : backing_store_(backing_store) {}
|
| + : backing_store_(backing_store), database_id_(-1) {}
|
|
|
| -IndexedDBBackingStore::Transaction::~Transaction() {}
|
| +IndexedDBBackingStore::Transaction::~Transaction() {
|
| + STLDeleteContainerPairSecondPointers(
|
| + blob_change_map_.begin(), blob_change_map_.end());
|
| +}
|
|
|
| void IndexedDBBackingStore::Transaction::Begin() {
|
| IDB_TRACE("IndexedDBBackingStore::Transaction::Begin");
|
| @@ -2906,4 +2953,55 @@ void IndexedDBBackingStore::Transaction::Rollback() {
|
| transaction_ = NULL;
|
| }
|
|
|
| +IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord(
|
| + const std::string& key, int64 object_store_id)
|
| + : key_(key), object_store_id_(object_store_id) {
|
| +}
|
| +
|
| +IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() {
|
| +}
|
| +
|
| +void IndexedDBBackingStore::Transaction::BlobChangeRecord::SetBlobInfo(
|
| + std::vector<IndexedDBBlobInfo>* blob_info) {
|
| + blob_info_.clear();
|
| + if (blob_info)
|
| + blob_info_.swap(*blob_info);
|
| +}
|
| +
|
| +void IndexedDBBackingStore::Transaction::BlobChangeRecord::SetHandles(
|
| + ScopedVector<webkit_blob::BlobDataHandle>* handles) {
|
| + handles_.clear();
|
| + if (handles)
|
| + handles_.swap(*handles);
|
| +}
|
| +
|
| +// This is storing an info, even if empty, even if the previous key had no blob
|
| +// info that we know of. It duplicates a bunch of information stored in the
|
| +// leveldb transaction, but only w.r.t. the user keys altered--we don't keep the
|
| +// changes to exists or index keys here.
|
| +void IndexedDBBackingStore::Transaction::PutBlobInfo(
|
| + int64 database_id,
|
| + int64 object_store_id,
|
| + const std::string& key,
|
| + std::vector<IndexedDBBlobInfo>* blob_info,
|
| + ScopedVector<webkit_blob::BlobDataHandle>* handles) {
|
| + DCHECK_GT(key.size(), 0UL);
|
| + if (database_id_ < 0)
|
| + database_id_ = database_id;
|
| + DCHECK_EQ(database_id_, database_id);
|
| +
|
| + BlobChangeMap::iterator it = blob_change_map_.find(key);
|
| + BlobChangeRecord* record = NULL;
|
| + if (it == blob_change_map_.end()) {
|
| + record = new BlobChangeRecord(key, object_store_id);
|
| + blob_change_map_[key] = record;
|
| + } else {
|
| + record = it->second;
|
| + }
|
| + DCHECK_EQ(record->object_store_id(), object_store_id);
|
| + record->SetBlobInfo(blob_info);
|
| + record->SetHandles(handles);
|
| + DCHECK(!handles || !handles->size());
|
| +}
|
| +
|
| } // namespace content
|
|
|