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