diff options
author | jsbell@chromium.org <jsbell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-21 03:08:54 +0000 |
---|---|---|
committer | jsbell@chromium.org <jsbell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-21 03:08:54 +0000 |
commit | 28f4165b9b0eb6266245b47edf913539cc4ebb0a (patch) | |
tree | 3b5410256363471cf9d54b62f33ea0b8120ca7de | |
parent | 0eea36cb9143d199db648e37a38278c6d91ec731 (diff) | |
download | chromium_src-28f4165b9b0eb6266245b47edf913539cc4ebb0a.zip chromium_src-28f4165b9b0eb6266245b47edf913539cc4ebb0a.tar.gz chromium_src-28f4165b9b0eb6266245b47edf913539cc4ebb0a.tar.bz2 |
IndexedDB: Support binary keys in Chromium back-end
Back-end support for binary values (Uint8Arrays) as IDB keys.
This requires Blink public API changes before landing.
(This is part 3 of a 4 part landing sequence.)
BUG=297304
Review URL: https://codereview.chromium.org/23439009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236380 0039d316-1c4b-4281-b951-d872f2087c98
7 files changed, 190 insertions, 1 deletions
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/content/browser/indexed_db/indexed_db_leveldb_coding.cc index 46e5121..dd3964a 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_coding.cc +++ b/content/browser/indexed_db/indexed_db_leveldb_coding.cc @@ -149,6 +149,7 @@ using base::StringPiece; using blink::WebIDBKeyType; using blink::WebIDBKeyTypeArray; +using blink::WebIDBKeyTypeBinary; using blink::WebIDBKeyTypeDate; using blink::WebIDBKeyTypeInvalid; using blink::WebIDBKeyTypeMin; @@ -173,6 +174,7 @@ static const unsigned char kIndexedDBKeyDateTypeByte = 2; static const unsigned char kIndexedDBKeyNumberTypeByte = 3; static const unsigned char kIndexedDBKeyArrayTypeByte = 4; static const unsigned char kIndexedDBKeyMinKeyTypeByte = 5; +static const unsigned char kIndexedDBKeyBinaryTypeByte = 6; static const unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0; static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0; @@ -269,6 +271,12 @@ void EncodeString(const string16& value, std::string* into) { *dst++ = htons(*src++); } +void EncodeBinary(const std::string& value, std::string* into) { + EncodeVarInt(value.length(), into); + into->append(value.begin(), value.end()); + DCHECK(into->size() >= value.size()); +} + void EncodeStringWithLength(const string16& value, std::string* into) { EncodeVarInt(value.length(), into); EncodeString(value, into); @@ -301,6 +309,12 @@ void EncodeIDBKey(const IndexedDBKey& value, std::string* into) { DCHECK_GT(into->size(), previous_size); return; } + case WebIDBKeyTypeBinary: { + EncodeByte(kIndexedDBKeyBinaryTypeByte, into); + EncodeBinary(value.binary(), into); + DCHECK_GT(into->size(), previous_size); + return; + } case WebIDBKeyTypeString: { EncodeByte(kIndexedDBKeyStringTypeByte, into); EncodeStringWithLength(value.string(), into); @@ -446,6 +460,22 @@ bool DecodeStringWithLength(StringPiece* slice, string16* value) { return true; } +bool DecodeBinary(StringPiece* slice, std::string* value) { + if (slice->empty()) + return false; + + int64 length = 0; + if (!DecodeVarInt(slice, &length) || length < 0) + return false; + size_t size = length; + if (slice->size() < size) + return false; + + value->assign(slice->begin(), size); + slice->remove_prefix(size); + return true; +} + bool DecodeIDBKey(StringPiece* slice, scoped_ptr<IndexedDBKey>* value) { if (slice->empty()) return false; @@ -472,6 +502,13 @@ bool DecodeIDBKey(StringPiece* slice, scoped_ptr<IndexedDBKey>* value) { *value = make_scoped_ptr(new IndexedDBKey(array)); return true; } + case kIndexedDBKeyBinaryTypeByte: { + std::string binary; + if (!DecodeBinary(slice, &binary)) + return false; + *value = make_scoped_ptr(new IndexedDBKey(binary)); + return true; + } case kIndexedDBKeyStringTypeByte: { string16 s; if (!DecodeStringWithLength(slice, &s)) @@ -578,6 +615,15 @@ bool ConsumeEncodedIDBKey(StringPiece* slice) { } return true; } + case kIndexedDBKeyBinaryTypeByte: { + int64 length = 0; + if (!DecodeVarInt(slice, &length) || length < 0) + return false; + if (slice->size() < static_cast<size_t>(length)) + return false; + slice->remove_prefix(length); + return true; + } case kIndexedDBKeyStringTypeByte: { int64 length = 0; if (!DecodeVarInt(slice, &length) || length < 0) @@ -614,6 +660,8 @@ static WebIDBKeyType KeyTypeByteToKeyType(unsigned char type) { return WebIDBKeyTypeInvalid; case kIndexedDBKeyArrayTypeByte: return WebIDBKeyTypeArray; + case kIndexedDBKeyBinaryTypeByte: + return WebIDBKeyTypeBinary; case kIndexedDBKeyStringTypeByte: return WebIDBKeyTypeString; case kIndexedDBKeyDateTypeByte: @@ -650,6 +698,7 @@ int CompareEncodedStringsWithLength(StringPiece* slice1, return 0; } + // Extract the string data, and advance the passed slices. StringPiece string1(slice1->begin(), len1 * sizeof(char16)); StringPiece string2(slice2->begin(), len2 * sizeof(char16)); slice1->remove_prefix(len1 * sizeof(char16)); @@ -660,6 +709,41 @@ int CompareEncodedStringsWithLength(StringPiece* slice1, return string1.compare(string2); } +int CompareEncodedBinary(StringPiece* slice1, + StringPiece* slice2, + bool* ok) { + int64 len1, len2; + if (!DecodeVarInt(slice1, &len1) || !DecodeVarInt(slice2, &len2)) { + *ok = false; + return 0; + } + DCHECK_GE(len1, 0); + DCHECK_GE(len2, 0); + if (len1 < 0 || len2 < 0) { + *ok = false; + return 0; + } + size_t size1 = len1; + size_t size2 = len2; + + DCHECK_GE(slice1->size(), size1); + DCHECK_GE(slice2->size(), size2); + if (slice1->size() < size1 || slice2->size() < size2) { + *ok = false; + return 0; + } + + // Extract the binary data, and advance the passed slices. + StringPiece binary1(slice1->begin(), size1); + StringPiece binary2(slice2->begin(), size2); + slice1->remove_prefix(size1); + slice2->remove_prefix(size2); + + *ok = true; + // This is the same as a memcmp() + return binary1.compare(binary2); +} + static int CompareInts(int64 a, int64 b) { #ifndef NDEBUG // Exercised by unit tests in debug only. @@ -718,6 +802,8 @@ int CompareEncodedIDBKeys(StringPiece* slice_a, } return length_a - length_b; } + case kIndexedDBKeyBinaryTypeByte: + return CompareEncodedBinary(slice_a, slice_b, ok); case kIndexedDBKeyStringTypeByte: return CompareEncodedStringsWithLength(slice_a, slice_b, ok); case kIndexedDBKeyDateTypeByte: diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.h b/content/browser/indexed_db/indexed_db_leveldb_coding.h index 4aca1b9..8d0c780 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_coding.h +++ b/content/browser/indexed_db/indexed_db_leveldb_coding.h @@ -30,6 +30,7 @@ CONTENT_EXPORT void EncodeVarInt(int64 value, std::string* into); CONTENT_EXPORT void EncodeString(const string16& value, std::string* into); CONTENT_EXPORT void EncodeStringWithLength(const string16& value, std::string* into); +CONTENT_EXPORT void EncodeBinary(const std::string& value, std::string* into); CONTENT_EXPORT void EncodeDouble(double value, std::string* into); CONTENT_EXPORT void EncodeIDBKey(const IndexedDBKey& value, std::string* into); CONTENT_EXPORT void EncodeIDBKeyPath(const IndexedDBKeyPath& value, @@ -48,6 +49,8 @@ CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeString(base::StringPiece* slice, CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeStringWithLength( base::StringPiece* slice, string16* value); +CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeBinary(base::StringPiece* slice, + std::string* value); CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeDouble(base::StringPiece* slice, double* value); CONTENT_EXPORT WARN_UNUSED_RESULT bool DecodeIDBKey( diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc b/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc index e5e4927..6d6ab0b 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc +++ b/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc @@ -123,6 +123,8 @@ TEST(IndexedDBLevelDBCodingTest, MaxIDBKey) { std::string min_key = MinIDBKey(); std::string array_key; EncodeIDBKey(IndexedDBKey(IndexedDBKey::KeyArray()), &array_key); + std::string binary_key; + EncodeIDBKey(IndexedDBKey(std::string("\x00\x01\x02")), &binary_key); std::string string_key; EncodeIDBKey(IndexedDBKey(ASCIIToUTF16("Hello world")), &string_key); std::string number_key; @@ -132,6 +134,7 @@ TEST(IndexedDBLevelDBCodingTest, MaxIDBKey) { EXPECT_GT(CompareKeys(max_key, min_key), 0); EXPECT_GT(CompareKeys(max_key, array_key), 0); + EXPECT_GT(CompareKeys(max_key, binary_key), 0); EXPECT_GT(CompareKeys(max_key, string_key), 0); EXPECT_GT(CompareKeys(max_key, number_key), 0); EXPECT_GT(CompareKeys(max_key, date_key), 0); @@ -143,6 +146,8 @@ TEST(IndexedDBLevelDBCodingTest, MinIDBKey) { std::string max_key = MaxIDBKey(); std::string array_key; EncodeIDBKey(IndexedDBKey(IndexedDBKey::KeyArray()), &array_key); + std::string binary_key; + EncodeIDBKey(IndexedDBKey(std::string("\x00\x01\x02")), &binary_key); std::string string_key; EncodeIDBKey(IndexedDBKey(ASCIIToUTF16("Hello world")), &string_key); std::string number_key; @@ -152,6 +157,7 @@ TEST(IndexedDBLevelDBCodingTest, MinIDBKey) { EXPECT_LT(CompareKeys(min_key, max_key), 0); EXPECT_LT(CompareKeys(min_key, array_key), 0); + EXPECT_LT(CompareKeys(min_key, binary_key), 0); EXPECT_LT(CompareKeys(min_key, string_key), 0); EXPECT_LT(CompareKeys(min_key, number_key), 0); EXPECT_LT(CompareKeys(min_key, date_key), 0); @@ -473,6 +479,58 @@ TEST(IndexedDBLevelDBCodingTest, CompareEncodedStringsWithLength) { } } +static std::string WrappedEncodeBinary(std::string value) { + std::string buffer; + EncodeBinary(value, &buffer); + return buffer; +} + +TEST(IndexedDBLevelDBCodingTest, EncodeBinary) { + const unsigned char binary_data[] = {0x00, 0x01, 0xfe, 0xff}; + EXPECT_EQ( + static_cast<size_t>(1), + WrappedEncodeBinary(std::string(binary_data, binary_data + 0)).size()); + EXPECT_EQ( + static_cast<size_t>(2), + WrappedEncodeBinary(std::string(binary_data, binary_data + 1)).size()); + EXPECT_EQ( + static_cast<size_t>(5), + WrappedEncodeBinary(std::string(binary_data, binary_data + 4)).size()); +} + +TEST(IndexedDBLevelDBCodingTest, DecodeBinary) { + const unsigned char binary_data[] = { 0x00, 0x01, 0xfe, 0xff }; + + std::vector<std::string> test_cases; + test_cases.push_back(std::string(binary_data, binary_data + 0)); + test_cases.push_back(std::string(binary_data, binary_data + 1)); + test_cases.push_back(std::string(binary_data, binary_data + 4)); + + for (size_t i = 0; i < test_cases.size(); ++i) { + std::string value = test_cases[i]; + std::string v = WrappedEncodeBinary(value); + ASSERT_GT(v.size(), static_cast<size_t>(0)); + StringPiece slice(v); + std::string result; + EXPECT_TRUE(DecodeBinary(&slice, &result)); + EXPECT_EQ(value, result); + EXPECT_TRUE(slice.empty()); + + slice = StringPiece(&*v.begin(), v.size() - 1); + EXPECT_FALSE(DecodeBinary(&slice, &result)); + + slice = StringPiece(&*v.begin(), static_cast<size_t>(0)); + EXPECT_FALSE(DecodeBinary(&slice, &result)); + + // Verify decoding at an offset, to detect unaligned memory access. + v.insert(v.begin(), static_cast<size_t>(1), static_cast<char>(0)); + slice = StringPiece(&*v.begin() + 1, v.size() - 1); + EXPECT_TRUE(DecodeBinary(&slice, &result)); + EXPECT_EQ(value, result); + EXPECT_TRUE(slice.empty()); + } +} + static std::string WrappedEncodeDouble(double value) { std::string buffer; EncodeDouble(value, &buffer); @@ -524,12 +582,14 @@ TEST(IndexedDBLevelDBCodingTest, EncodeDecodeIDBKey) { test_cases.push_back(IndexedDBKey(1234, WebIDBKeyTypeNumber)); test_cases.push_back(IndexedDBKey(7890, WebIDBKeyTypeDate)); test_cases.push_back(IndexedDBKey(ASCIIToUTF16("Hello World!"))); + test_cases.push_back(IndexedDBKey(std::string("\x01\x02"))); test_cases.push_back(IndexedDBKey(IndexedDBKey::KeyArray())); IndexedDBKey::KeyArray array; array.push_back(IndexedDBKey(1234, WebIDBKeyTypeNumber)); array.push_back(IndexedDBKey(7890, WebIDBKeyTypeDate)); array.push_back(IndexedDBKey(ASCIIToUTF16("Hello World!"))); + array.push_back(IndexedDBKey(std::string("\x01\x02"))); array.push_back(IndexedDBKey(IndexedDBKey::KeyArray())); test_cases.push_back(IndexedDBKey(array)); @@ -685,6 +745,15 @@ TEST(IndexedDBLevelDBCodingTest, ExtractAndCompareIDBKeys) { keys.push_back(IndexedDBKey(ASCIIToUTF16("baab"))); keys.push_back(IndexedDBKey(ASCIIToUTF16("c"))); + keys.push_back(IndexedDBKey(std::string())); + keys.push_back(IndexedDBKey(std::string("\x01"))); + keys.push_back(IndexedDBKey(std::string("\x01\x01"))); + keys.push_back(IndexedDBKey(std::string("\x01\x02"))); + keys.push_back(IndexedDBKey(std::string("\x02"))); + keys.push_back(IndexedDBKey(std::string("\x02\x01"))); + keys.push_back(IndexedDBKey(std::string("\x02\x02"))); + keys.push_back(IndexedDBKey(std::string("\xff"))); + keys.push_back(CreateArrayIDBKey()); keys.push_back(CreateArrayIDBKey(IndexedDBKey(0, WebIDBKeyTypeNumber))); keys.push_back(CreateArrayIDBKey(IndexedDBKey(0, WebIDBKeyTypeNumber), diff --git a/content/child/indexed_db/indexed_db_key_builders.cc b/content/child/indexed_db/indexed_db_key_builders.cc index 162546c..a17065f 100644 --- a/content/child/indexed_db/indexed_db_key_builders.cc +++ b/content/child/indexed_db/indexed_db_key_builders.cc @@ -10,6 +10,7 @@ using blink::WebIDBKey; using blink::WebIDBKeyRange; using blink::WebIDBKeyTypeArray; +using blink::WebIDBKeyTypeBinary; using blink::WebIDBKeyTypeDate; using blink::WebIDBKeyTypeInvalid; using blink::WebIDBKeyTypeMin; @@ -44,6 +45,9 @@ IndexedDBKey IndexedDBKeyBuilder::Build(const blink::WebIDBKey& key) { switch (key.keyType()) { case WebIDBKeyTypeArray: return IndexedDBKey(CopyKeyArray(key)); + case WebIDBKeyTypeBinary: + return IndexedDBKey( + std::string(key.binary().data(), key.binary().size())); case WebIDBKeyTypeString: return IndexedDBKey(key.string()); case WebIDBKeyTypeDate: @@ -72,6 +76,8 @@ WebIDBKey WebIDBKeyBuilder::Build(const IndexedDBKey& key) { } return WebIDBKey::createArray(web_array); } + case WebIDBKeyTypeBinary: + return WebIDBKey::createBinary(key.binary()); case WebIDBKeyTypeString: return WebIDBKey::createString(key.string()); case WebIDBKeyTypeDate: diff --git a/content/common/indexed_db/indexed_db_key.cc b/content/common/indexed_db/indexed_db_key.cc index 0ee2383..71ddd6a 100644 --- a/content/common/indexed_db/indexed_db_key.cc +++ b/content/common/indexed_db/indexed_db_key.cc @@ -12,6 +12,7 @@ namespace content { using blink::WebIDBKey; using blink::WebIDBKeyType; using blink::WebIDBKeyTypeArray; +using blink::WebIDBKeyTypeBinary; using blink::WebIDBKeyTypeDate; using blink::WebIDBKeyTypeInvalid; using blink::WebIDBKeyTypeMin; @@ -69,6 +70,12 @@ IndexedDBKey::IndexedDBKey(const KeyArray& keys) number_(0), size_estimate_(kOverheadSize + CalculateArraySize(keys)) {} +IndexedDBKey::IndexedDBKey(const std::string& key) + : type_(WebIDBKeyTypeBinary), + binary_(key), + size_estimate_(kOverheadSize + + (key.length() * sizeof(std::string::value_type))) {} + IndexedDBKey::IndexedDBKey(const string16& key) : type_(WebIDBKeyTypeString), string_(key), @@ -94,8 +101,10 @@ int IndexedDBKey::Compare(const IndexedDBKey& other) const { if (array_.size() > other.array_.size()) return 1; return 0; + case WebIDBKeyTypeBinary: + return binary_.compare(other.binary_); case WebIDBKeyTypeString: - return -other.string_.compare(string_); + return string_.compare(other.string_); case WebIDBKeyTypeDate: return (date_ < other.date_) ? -1 : (date_ > other.date_) ? 1 : 0; case WebIDBKeyTypeNumber: diff --git a/content/common/indexed_db/indexed_db_key.h b/content/common/indexed_db/indexed_db_key.h index 8cfc67f..b10eb1f 100644 --- a/content/common/indexed_db/indexed_db_key.h +++ b/content/common/indexed_db/indexed_db_key.h @@ -26,6 +26,7 @@ class CONTENT_EXPORT IndexedDBKey { IndexedDBKey(); // Defaults to blink::WebIDBKeyTypeInvalid. IndexedDBKey(blink::WebIDBKeyType); // must be Null or Invalid explicit IndexedDBKey(const KeyArray& array); + explicit IndexedDBKey(const std::string& binary); explicit IndexedDBKey(const string16& str); IndexedDBKey(double number, blink::WebIDBKeyType type); // must be date or number @@ -39,6 +40,7 @@ class CONTENT_EXPORT IndexedDBKey { blink::WebIDBKeyType type() const { return type_; } const std::vector<IndexedDBKey>& array() const { return array_; } + const std::string& binary() const { return binary_; } const string16& string() const { return string_; } double date() const { return date_; } double number() const { return number_; } @@ -48,6 +50,7 @@ class CONTENT_EXPORT IndexedDBKey { private: blink::WebIDBKeyType type_; std::vector<IndexedDBKey> array_; + std::string binary_; string16 string_; double date_; double number_; diff --git a/content/common/indexed_db/indexed_db_param_traits.cc b/content/common/indexed_db/indexed_db_param_traits.cc index 10c572f..94b2053 100644 --- a/content/common/indexed_db/indexed_db_param_traits.cc +++ b/content/common/indexed_db/indexed_db_param_traits.cc @@ -20,6 +20,7 @@ using blink::WebIDBKeyPathTypeNull; using blink::WebIDBKeyPathTypeString; using blink::WebIDBKeyType; using blink::WebIDBKeyTypeArray; +using blink::WebIDBKeyTypeBinary; using blink::WebIDBKeyTypeDate; using blink::WebIDBKeyTypeInvalid; using blink::WebIDBKeyTypeMin; @@ -35,6 +36,9 @@ void ParamTraits<IndexedDBKey>::Write(Message* m, const param_type& p) { case WebIDBKeyTypeArray: WriteParam(m, p.array()); return; + case WebIDBKeyTypeBinary: + WriteParam(m, p.binary()); + return; case WebIDBKeyTypeString: WriteParam(m, p.string()); return; @@ -70,6 +74,13 @@ bool ParamTraits<IndexedDBKey>::Read(const Message* m, *r = IndexedDBKey(array); return true; } + case WebIDBKeyTypeBinary: { + std::string binary; + if (!ReadParam(m, iter, &binary)) + return false; + *r = IndexedDBKey(binary); + return true; + } case WebIDBKeyTypeString: { string16 string; if (!ReadParam(m, iter, &string)) @@ -111,6 +122,8 @@ void ParamTraits<IndexedDBKey>::Log(const param_type& p, std::string* l) { l->append(", "); } l->append("], "); + LogParam(p.binary(), l); + l->append(", "); LogParam(p.string(), l); l->append(", "); LogParam(p.date(), l); |