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 |