/* * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/351564777): Remove this and convert code to safer constructs. #pragma allow_unsafe_buffers #endif #include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h" #include "third_party/blink/public/common/indexeddb/indexeddb_key.h" #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h" #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_factory.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_blob.h" #include "third_party/blink/renderer/bindings/core/v8/v8_dom_string_list.h" #include "third_party/blink/renderer/bindings/core/v8/v8_file.h" #include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_cursor.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_cursor_with_value.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_database.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_index.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_key_range.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_object_store.h" #include "third_party/blink/renderer/core/fileapi/blob.h" #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h" #include "third_party/blink/renderer/modules/indexeddb/idb_any.h" #include "third_party/blink/renderer/modules/indexeddb/idb_cursor.h" #include "third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.h" #include "third_party/blink/renderer/modules/indexeddb/idb_database.h" #include "third_party/blink/renderer/modules/indexeddb/idb_key.h" #include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h" #include "third_party/blink/renderer/modules/indexeddb/idb_key_range.h" #include "third_party/blink/renderer/modules/indexeddb/idb_value.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { static v8::Local<v8::Value> DeserializeIDBValueData(v8::Isolate*, const IDBValue*); // Convert a simple (non-Array) script value to an Indexed DB key. If the // conversion fails due to a detached buffer, an exception is thrown. If // the value can't be converted into a key, an 'Invalid' key is returned. This // is used to implement part of the following spec algorithm: // https://w3c.github.io/IndexedDB/#convert-value-to-key // A V8 exception may be thrown on bad data or by script's getters; if so, // callers should not make further V8 calls. static std::unique_ptr<IDBKey> CreateIDBKeyFromSimpleValue( v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exception_state) { … } // Convert a script value to an Indexed DB key. If the result cannot be // converted, an 'Invalid' key is returned. If an array is being // converted, and a potential subkey does not exist, then the array is // returned but with an 'Invalid' entry; this is used for "multi-entry" // indexes where an array with invalid members is permitted will later be // sanitized. This is used to implement both of the following spec algorithms: // https://w3c.github.io/IndexedDB/#convert-value-to-key // https://w3c.github.io/IndexedDB/#convert-a-value-to-a-multientry-key // A V8 exception may be thrown on bad data or by script's getters; if so, // callers should not make further V8 calls. std::unique_ptr<IDBKey> CreateIDBKeyFromValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exception_state) { … } // Indexed DB key paths should apply to explicitly copied properties (that // will be "own" properties when deserialized) as well as the following. // http://www.w3.org/TR/IndexedDB/#key-path-construct static bool IsImplicitProperty(v8::Isolate* isolate, v8::Local<v8::Value> value, const String& name) { … } // Assumes a valid key path. static Vector<String> ParseKeyPath(const String& key_path) { … } // Evaluate a key path string against a value and return a key. It must be // called repeatedly for array-type key paths. Failure in the evaluation steps // (per spec) is represented by returning nullptr. Failure to convert the result // to a key is representing by returning an 'Invalid' key. (An array with // invalid members will be returned if needed.) // https://w3c.github.io/IndexedDB/#evaluate-a-key-path-on-a-value // A V8 exception may be thrown on bad data or by script's getters; if so, // callers should not make further V8 calls. std::unique_ptr<IDBKey> CreateIDBKeyFromValueAndKeyPath( v8::Isolate* isolate, v8::Local<v8::Value> v8_value, const String& key_path, ExceptionState& exception_state) { … } // Evaluate a key path against a value and return a key. For string-type // paths, nullptr is returned if evaluation of the path fails, and an // 'Invalid' key if evaluation succeeds but conversion fails. For array-type // paths, nullptr is returned if evaluation of any sub-path fails, otherwise // an array key is returned (with potentially 'Invalid' members). // https://w3c.github.io/IndexedDB/#evaluate-a-key-path-on-a-value // A V8 exception may be thrown on bad data or by script's getters; if so, // callers should not make further V8 calls. std::unique_ptr<IDBKey> CreateIDBKeyFromValueAndKeyPath( v8::Isolate* isolate, v8::Local<v8::Value> value, const IDBKeyPath& key_path, ExceptionState& exception_state) { … } // Evaluate an index's key path against a value and return a key. This // handles the special case for indexes where a compound key path // may result in "holes", depending on the store's properties. // Otherwise, nullptr is returned. // https://w3c.github.io/IndexedDB/#evaluate-a-key-path-on-a-value // A V8 exception may be thrown on bad data or by script's getters; if so, // callers should not make further V8 calls. std::unique_ptr<IDBKey> CreateIDBKeyFromValueAndKeyPaths( v8::Isolate* isolate, v8::Local<v8::Value> value, const IDBKeyPath& store_key_path, const IDBKeyPath& index_key_path, ExceptionState& exception_state) { … } // Deserialize just the value data & blobInfo from the given IDBValue. // // Primary key injection is performed in deserializeIDBValue() below. v8::Local<v8::Value> DeserializeIDBValueData(v8::Isolate* isolate, const IDBValue* value) { … } // Deserialize the entire IDBValue. // // On top of deserializeIDBValueData(), this handles the special case of having // to inject a key into the de-serialized value. See injectV8KeyIntoV8Value() // for details. v8::Local<v8::Value> DeserializeIDBValue(ScriptState* script_state, const IDBValue* value) { … } v8::Local<v8::Value> DeserializeIDBValueArray( ScriptState* script_state, const Vector<std::unique_ptr<IDBValue>>& values) { … } // Injects a primary key into a deserialized V8 value. // // In general, the value stored in IndexedDB is the serialized version of a // value passed to the API. However, the specification has a special case of // object stores that specify a key path and have a key generator. In this case, // the conceptual description in the spec states that the key produced by the // key generator is injected into the value before it is written to IndexedDB. // // We cannot implement the spec's conceptual description. We need to assign // primary keys in the browser process, to ensure that multiple renderer // processes talking to the same database receive sequential keys. At the same // time, we want the value serialization code to live in the renderer process, // because this type of code is a likely victim to security exploits. // // We handle this special case by serializing and writing values without the // corresponding keys. At read time, we obtain the keys and the values // separately, and we inject the keys into values. bool InjectV8KeyIntoV8Value(v8::Isolate* isolate, v8::Local<v8::Value> key, v8::Local<v8::Value> value, const IDBKeyPath& key_path) { … } // Verify that an value can have an generated key inserted at the location // specified by the key path (by injectV8KeyIntoV8Value) when the object is // later deserialized. bool CanInjectIDBKeyIntoScriptValue(v8::Isolate* isolate, const ScriptValue& script_value, const IDBKeyPath& key_path) { … } ScriptValue DeserializeScriptValue(ScriptState* script_state, SerializedScriptValue* serialized_value, const Vector<WebBlobInfo>* blob_info) { … } SQLValue NativeValueTraits<SQLValue>::NativeValue( v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exception_state) { … } #if DCHECK_IS_ON() // This assertion is used when a value has been retrieved from an object store // with implicit keys (i.e. a key path). It verifies that either the value // contains an implicit key matching the primary key (so it was correctly // extracted when stored) or that the key can be inserted as an own property. void AssertPrimaryKeyValidOrInjectable(ScriptState* script_state, const IDBValue* value) { … } #endif // DCHECK_IS_ON() } // namespace blink