| Index: third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
 | 
| diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..a1e806e24593860611a6906341e6d740963b856d
 | 
| --- /dev/null
 | 
| +++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
 | 
| @@ -0,0 +1,214 @@
 | 
| +// Copyright 2017 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#ifndef IDBValueWrapping_h
 | 
| +#define IDBValueWrapping_h
 | 
| +
 | 
| +#include "bindings/core/v8/ExceptionState.h"
 | 
| +#include "bindings/core/v8/serialization/SerializedScriptValue.h"
 | 
| +#include "modules/ModulesExport.h"
 | 
| +#include "platform/SharedBuffer.h"
 | 
| +#include "platform/wtf/Allocator.h"
 | 
| +#include "platform/wtf/RefPtr.h"
 | 
| +#include "platform/wtf/Vector.h"
 | 
| +#include "public/platform/WebBlobInfo.h"
 | 
| +#include "v8/include/v8.h"
 | 
| +
 | 
| +namespace blink {
 | 
| +
 | 
| +class Blob;
 | 
| +class BlobDataHandle;
 | 
| +class ExceptionState;
 | 
| +class IDBValue;
 | 
| +class ScriptState;
 | 
| +class ScriptValue;
 | 
| +class SerializedScriptValue;
 | 
| +class SharedBuffer;
 | 
| +
 | 
| +// Logic for serializing V8 values for storage in IndexedDB.
 | 
| +//
 | 
| +// V8 values are stored on disk using the format implemented in
 | 
| +// SerializedScriptValue (SSV), which is essentialy a byte array plus an array
 | 
| +// of attached Blobs. For "normal" (not too large) V8 values, the SSV output's
 | 
| +// byte array is stored directly in IndexedDB's backing store, together with
 | 
| +// references to the attached Blobs.
 | 
| +//
 | 
| +// "Large" V8 values are wrapped in Blobs, in order to avoid operating the
 | 
| +// backing store in a sub-optimal region. Specifically, the byte array in the
 | 
| +// SSV output is replaced with a "wrapped value" marker, and stored inside a
 | 
| +// Blob that is tacked to the end of the SSV's Blob array. IndexedDB's backing
 | 
| +// store receives the "wrapped value" marker and the references to the Blobs,
 | 
| +// while the large byte array in the SSV output is handled by the Blob storage
 | 
| +// system.
 | 
| +//
 | 
| +// In summary:
 | 
| +// "normal" v8::Value -> SSV -> IDBValue (stores SSV output) -> LevelDB
 | 
| +// "large" v8::Value -> SSV -> IDBValue (stores SSV output) ->
 | 
| +//     Blob (stores SSV output) + IDBValue (stores Blob reference) -> LevelDB
 | 
| +//
 | 
| +// Full picture that accounts for Blob attachments:
 | 
| +// "normal" v8::Value -> SSV (byte array, Blob attachments) ->
 | 
| +//     IDBValue (bytes: SSV byte array, blobs: SSV Blob attachments) -> LevelDB
 | 
| +// "large" v8::Value -> SSV (byte array, Blob attachments) ->
 | 
| +//     IDBValue (bytes: "wrapped value" marker,
 | 
| +//               blobs: SSV Blob attachments + [wrapper Blob(SSV byte array)] ->
 | 
| +//     LevelDB
 | 
| +class MODULES_EXPORT IDBValueWrapper {
 | 
| +  STACK_ALLOCATED();
 | 
| +
 | 
| + public:
 | 
| +  // Wrapper for an IndexedDB value.
 | 
| +  //
 | 
| +  // The serialization process can throw an exception. The caller is responsible
 | 
| +  // for checking exception_state.
 | 
| +  IDBValueWrapper(
 | 
| +      v8::Isolate*,
 | 
| +      v8::Local<v8::Value>,
 | 
| +      SerializedScriptValue::SerializeOptions::WasmSerializationPolicy,
 | 
| +      ExceptionState&);
 | 
| +
 | 
| +  // Creates a clone of the serialized value.
 | 
| +  //
 | 
| +  // This method is used to fulfill the IndexedDB specification requirement that
 | 
| +  // a value's key and index keys are extracted from a structured clone of the
 | 
| +  // value, which avoids the issue of side-effects in custom getters.
 | 
| +  //
 | 
| +  // This method cannot be called after WrapIfBiggerThan().
 | 
| +  void Clone(ScriptState*, ScriptValue* clone);
 | 
| +
 | 
| +  // Conditionally wraps the serialized value's byte array into a Blob.
 | 
| +  //
 | 
| +  // The byte array is wrapped if its size exceeds max_bytes. In production, the
 | 
| +  // max_bytes threshold is currently always kWrapThreshold.
 | 
| +  //
 | 
| +  // This method must be called before ExtractWireBytes() and cannot be called
 | 
| +  // after ExtractWireBytes().
 | 
| +  bool WrapIfBiggerThan(unsigned max_bytes);
 | 
| +
 | 
| +  // Obtains the BlobDataHandles from the serialized value's Blob array.
 | 
| +  //
 | 
| +  // This method must be called at most once, and must be called after
 | 
| +  // WrapIfBiggerThan().
 | 
| +  void ExtractBlobDataHandles(
 | 
| +      Vector<RefPtr<BlobDataHandle>>* blob_data_handles);
 | 
| +
 | 
| +  // Obtains the byte array for the serialized value.
 | 
| +  //
 | 
| +  // This method must be called at most once, and must be called after
 | 
| +  // WrapIfBiggerThan().
 | 
| +  RefPtr<SharedBuffer> ExtractWireBytes();
 | 
| +
 | 
| +  // Obtains WebBlobInfos for the serialized value's Blob array.
 | 
| +  //
 | 
| +  // This method must be called at most once, and must be called after
 | 
| +  // WrapIfBiggerThan().
 | 
| +  inline Vector<WebBlobInfo>& WrappedBlobInfo() {
 | 
| +#if DCHECK_IS_ON()
 | 
| +    DCHECK(!had_exception_)
 | 
| +        << "WrapBlobInfo() called on wrapper with serialization exception";
 | 
| +#endif  // DCHECK_IS_ON()
 | 
| +    return blob_info_;
 | 
| +  }
 | 
| +
 | 
| +  // Default threshold for WrapIfBiggerThan().
 | 
| +  //
 | 
| +  // This should be tuned to achieve a compromise between short-term IndexedDB
 | 
| +  // throughput and long-term I/O load and memory usage. LevelDB, the underlying
 | 
| +  // storage for IndexedDB, was not designed with large values in mind. At the
 | 
| +  // very least, large values will slow down compaction, causing occasional I/O
 | 
| +  // spikes.
 | 
| +  static constexpr unsigned kWrapThreshold = 64 * 1024;
 | 
| +
 | 
| +  // MIME type used for Blobs that wrap IDBValues.
 | 
| +  static constexpr const char* kWrapMimeType =
 | 
| +      "application/vnd.blink-idb-value-wrapper";
 | 
| +
 | 
| + private:
 | 
| +  // Used to serialize the wrapped value.
 | 
| +  static void WriteVarint(unsigned value, Vector<char>& output);
 | 
| +
 | 
| +  RefPtr<SerializedScriptValue> serialized_value_;
 | 
| +  RefPtr<BlobDataHandle> wrapper_handle_;
 | 
| +  Vector<WebBlobInfo> blob_info_;
 | 
| +  Vector<char> wire_bytes_;
 | 
| +#if DCHECK_IS_ON()
 | 
| +  bool had_exception_ = false;
 | 
| +  bool wrap_called_ = false;
 | 
| +#endif  // DCHECK_IS_ON()
 | 
| +};
 | 
| +
 | 
| +// State and logic for unwrapping large IndexedDB values from Blobs.
 | 
| +//
 | 
| +// See IDBValueWrapper for an explanation of the wrapping concept.
 | 
| +//
 | 
| +// Once created, an IDBValueUnwrapper instance can be used to unwrap multiple
 | 
| +// Blobs. For each Blob to be unwrapped, the caller should first call Parse().
 | 
| +// If the method succeeds, the IDBValueUnwrapper will store the parse state,
 | 
| +// which can be obtained using WrapperBlobSize() and WrapperBlobHandle().
 | 
| +class MODULES_EXPORT IDBValueUnwrapper {
 | 
| +  STACK_ALLOCATED();
 | 
| +
 | 
| + public:
 | 
| +  IDBValueUnwrapper();
 | 
| +
 | 
| +  // True if the IDBValue's data was wrapped in a Blob.
 | 
| +  static bool IsWrapped(IDBValue*);
 | 
| +
 | 
| +  // True if at least one of the IDBValues' data was wrapped in a Blob.
 | 
| +  static bool IsWrapped(const Vector<RefPtr<IDBValue>>&);
 | 
| +
 | 
| +  // Pieces together an unwrapped IDBValue from a wrapped value and Blob data.
 | 
| +  static RefPtr<IDBValue> Unwrap(IDBValue* wrapped_value,
 | 
| +                                 RefPtr<SharedBuffer>&& wrapper_blob_content);
 | 
| +
 | 
| +  // Parses the wrapper Blob information from a wrapped IDBValue.
 | 
| +  //
 | 
| +  // Returns true for success, and false for failure. Failure can mean that the
 | 
| +  // given value was not a wrapped IDBValue, or that the value bytes were
 | 
| +  // corrupted.
 | 
| +  bool Parse(IDBValue*);
 | 
| +
 | 
| +  // Returns the size of the Blob obtained by the last Unwrap() call.
 | 
| +  //
 | 
| +  // Should only be called after a successful result from Unwrap().
 | 
| +  inline unsigned WrapperBlobSize() const {
 | 
| +    DCHECK(end_);
 | 
| +    return blob_size_;
 | 
| +  }
 | 
| +
 | 
| +  // Returns a handle to the Blob obtained by the last Unwrap() call.
 | 
| +  //
 | 
| +  // Should only be called exactly once after a successful result from Unwrap().
 | 
| +  RefPtr<BlobDataHandle> WrapperBlobHandle();
 | 
| +
 | 
| + private:
 | 
| +  // Used to deserialize the wrapped value.
 | 
| +  bool ReadVarint(unsigned& value);
 | 
| +
 | 
| +  // Resets the parsing state.
 | 
| +  inline bool Reset() {
 | 
| +#if DCHECK_IS_ON()
 | 
| +    blob_handle_.Clear();
 | 
| +    current_ = nullptr;
 | 
| +    end_ = nullptr;
 | 
| +#endif  // DCHECK_IS_ON()
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  // Deserialization cursor in the SharedBuffer of the IDBValue being unwrapped.
 | 
| +  const uint8_t* current_;
 | 
| +
 | 
| +  // Smallest invalid position_ value.
 | 
| +  const uint8_t* end_;
 | 
| +
 | 
| +  // The size of the Blob holding the data for the last unwrapped IDBValue.
 | 
| +  unsigned blob_size_;
 | 
| +
 | 
| +  // Handle to the Blob holding the data for the last unwrapped IDBValue.
 | 
| +  RefPtr<BlobDataHandle> blob_handle_;
 | 
| +};
 | 
| +
 | 
| +}  // namespace blink
 | 
| +
 | 
| +#endif  // IDBValueWrapping_h
 | 
| 
 |