Chromium Code Reviews| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef IDBValueWrapping_h | |
| 6 #define IDBValueWrapping_h | |
| 7 | |
| 8 #include "bindings/core/v8/ExceptionState.h" | |
| 9 #include "bindings/core/v8/serialization/SerializedScriptValue.h" | |
| 10 #include "platform/SharedBuffer.h" | |
| 11 #include "platform/wtf/Allocator.h" | |
| 12 #include "platform/wtf/RefPtr.h" | |
| 13 #include "platform/wtf/Vector.h" | |
| 14 #include "public/platform/WebBlobInfo.h" | |
| 15 #include "v8/include/v8.h" | |
| 16 | |
| 17 namespace blink { | |
| 18 | |
| 19 class Blob; | |
| 20 class BlobDataHandle; | |
| 21 class ExceptionState; | |
| 22 class IDBValue; | |
| 23 class ScriptState; | |
| 24 class ScriptValue; | |
| 25 class SerializedScriptValue; | |
| 26 class SharedBuffer; | |
| 27 | |
| 28 // Logic for serializing V8 values for storage in IndexedDB. | |
| 29 // | |
| 30 // V8 values are stored on disk using the format implemented in | |
| 31 // SerializedScriptValue (SSV). For "normal" (not too large) V8 values, the SSV | |
| 32 // output is stored directly in IndexedDB's backing store. "Large" V8 values are | |
| 33 // wrapped in Blobs, in order to avoid operating the backing store in a | |
| 34 // sub-optimal region. In this case, the SSV output is stored using the Blob | |
| 35 // storage system, and IndexedDB's backing store only holds references to the | |
| 36 // Blobs. | |
| 37 // | |
| 38 // In summary: | |
| 39 // "normal" v8::Value -> SSV -> IDBValue (stores SSV output) -> LevelDB | |
| 40 // "large" v8::Value -> SSV -> IDBValue (stores SSV output) -> | |
| 41 // Blob (stores SSV output) + IDBValue (stores Blob reference) -> LevelDB | |
| 42 class IDBValueWrapper { | |
| 43 STACK_ALLOCATED(); | |
| 44 | |
| 45 public: | |
| 46 // Wrapper for an IndexedDB value. | |
| 47 // | |
| 48 // The serialization process can throw an exception. The caller is responsible | |
| 49 // for checking exception_state. | |
| 50 IDBValueWrapper( | |
| 51 v8::Isolate*, | |
| 52 v8::Local<v8::Value>, | |
| 53 SerializedScriptValue::SerializeOptions::WasmSerializationPolicy, | |
| 54 ExceptionState&); | |
| 55 | |
| 56 // Creates a clone of the serialized value. | |
| 57 // | |
| 58 // This method is used to fulfill the IndexedDB specification requirement that | |
| 59 // a value's key and index keys are extracted from a structured clone of the | |
| 60 // value, which avoids the issue of side-effects in custom getters. | |
| 61 // | |
| 62 // This method cannot be called after WrapIfBiggerThan(). | |
| 63 void Clone(ScriptState*, ScriptValue* clone); | |
| 64 | |
| 65 // Wraps the serialized value into a Blob if it exceeds the given size. | |
| 66 // | |
| 67 // In production, the threshold is currently always kWrapThreshold. | |
| 68 // | |
| 69 // This method must be called before ExtractWireBytes() and cannot be called | |
| 70 // after ExtractWireBytes(). | |
| 71 bool WrapIfBiggerThan(unsigned max_bytes); | |
| 72 | |
| 73 void ExtractBlobDataHandles( | |
| 74 Vector<RefPtr<BlobDataHandle>>* blob_data_handles); | |
| 75 | |
| 76 RefPtr<SharedBuffer> ExtractWireBytes(); | |
| 77 | |
| 78 inline Vector<WebBlobInfo>& WrappedBlobInfo() { | |
| 79 #if DCHECK_IS_ON() | |
| 80 DCHECK(!had_exception_) | |
| 81 << "WrapBlobInfo() called on wrapper with serialization exception"; | |
| 82 #endif // DCHECK_IS_ON() | |
| 83 return blob_info_; | |
| 84 } | |
| 85 | |
| 86 // Default threshold for WrapIfBiggerThan(). | |
| 87 // | |
| 88 // This should be tuned to achieve a compromise between short-term IndexedDB | |
| 89 // throughput and long-term I/O load and memory usage. LevelDB, the underlying | |
| 90 // storage for IndexedDB, was not designed with large values in mind. At the | |
| 91 // very least, large values will slow down compaction, causing occasional I/O | |
| 92 // spikes. | |
| 93 static constexpr unsigned kWrapThreshold = 64 * 1024; | |
| 94 | |
| 95 // MIME type used for Blobs that wrap IDBValues. | |
| 96 static constexpr const char* kWrapMimeType = | |
| 97 "application/x-blink-idb-value-wrapper"; | |
| 
 
jbroman
2017/05/23 20:13:11
IIUC, IANA no longer recommends deploying unregist
 
pwnall
2017/05/25 13:27:12
I submitted an application for "application/vnd.bl
 
 | |
| 98 | |
| 99 private: | |
| 100 // Used to serialize the wrapped value. | |
| 101 static void WriteVarint(unsigned value, Vector<char>& output); | |
| 102 | |
| 103 RefPtr<SerializedScriptValue> serialized_value_; | |
| 104 RefPtr<BlobDataHandle> wrapper_handle_; | |
| 105 Vector<WebBlobInfo> blob_info_; | |
| 106 Vector<BlobDataHandle> blob_handles_; | |
| 107 Vector<char> wire_bytes_; | |
| 108 #if DCHECK_IS_ON() | |
| 109 bool had_exception_ = false; | |
| 110 bool wrap_called_ = false; | |
| 111 #endif // DCHECK_IS_ON() | |
| 112 }; | |
| 113 | |
| 114 // State and logic for unwrapping large IndexedDB values from Blobs. | |
| 115 // | |
| 116 // See IDBValueWrapper for an explanation of the wrapping concept. | |
| 117 // | |
| 118 // Once created, an IDBValueUnwrapper instance can be used to unwrap multiple | |
| 119 // Blobs. For each Blob to be unwrapped, the caller should first call Parse(). | |
| 120 // If the method succeeds, the IDBValueUnwrapper will store the parse state, | |
| 121 // which can be obtained using WrapperBlobSize() and WrapperBlobHandle(). | |
| 122 class IDBValueUnwrapper { | |
| 123 STACK_ALLOCATED(); | |
| 124 | |
| 125 public: | |
| 126 IDBValueUnwrapper(); | |
| 127 | |
| 128 // True if the IDBValue's data was wrapped in a Blob. | |
| 129 static bool IsWrapped(IDBValue*); | |
| 130 | |
| 131 // True if at least one of the IDBValues' data was wrapped in a Blob. | |
| 132 static bool IsWrapped(const Vector<RefPtr<IDBValue>>&); | |
| 133 | |
| 134 // Pieces together an unwrapped IDBValue from a wrapped value and Blob data. | |
| 135 static RefPtr<IDBValue> CreateUnwrapped( | |
| 136 IDBValue* wrapped_value, | |
| 137 RefPtr<SharedBuffer>&& wrapper_blob_content); | |
| 138 | |
| 139 // Parses the wrapper Blob information from a wrapped IDBValue. | |
| 140 // | |
| 141 // Returns true for success, and false for failure. Failure can mean that the | |
| 142 // given value was not a wrapped IDBValue, or that the value bytes were | |
| 143 // corrupted. | |
| 144 bool Parse(IDBValue*); | |
| 145 | |
| 146 // Returns the size of the Blob obtained by the last Unwrap() call. | |
| 147 // | |
| 148 // Should only be called after a successful result from Unwrap(). | |
| 149 inline unsigned WrapperBlobSize() const { | |
| 150 DCHECK(end_); | |
| 151 return blob_size_; | |
| 152 } | |
| 153 | |
| 154 // Returns a handle to the Blob obtained by the last Unwrap() call. | |
| 155 // | |
| 156 // Should only be called exactly once after a successful result from Unwrap(). | |
| 157 RefPtr<BlobDataHandle> WrapperBlobHandle(); | |
| 158 | |
| 159 private: | |
| 160 // Used to deserialize the wrapped value. | |
| 161 bool ReadVarint(unsigned& value); | |
| 162 | |
| 163 // Resets the parsing state. | |
| 164 inline bool Reset() { | |
| 165 #if DCHECK_IS_ON() | |
| 166 blob_handle_.Clear(); | |
| 167 current_ = nullptr; | |
| 168 end_ = nullptr; | |
| 169 #endif // DCHECK_IS_ON() | |
| 170 return false; | |
| 171 } | |
| 172 | |
| 173 // Deserialization cursor in the SharedBuffer of the IDBValue being unwrapped. | |
| 174 const uint8_t* current_; | |
| 175 | |
| 176 // Smallest invalid position_ value. | |
| 177 const uint8_t* end_; | |
| 178 | |
| 179 // The size of the Blob holding the data for the last unwrapped IDBValue. | |
| 180 unsigned blob_size_; | |
| 181 | |
| 182 // Handle to the Blob holding the data for the last unwrapped IDBValue. | |
| 183 RefPtr<BlobDataHandle> blob_handle_; | |
| 184 }; | |
| 185 | |
| 186 } // namespace blink | |
| 187 | |
| 188 #endif // IDBValueWrapping_h | |
| OLD | NEW |