| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "bindings/modules/v8/serialization/V8ScriptValueSerializerForModules.h" | 5 #include "bindings/modules/v8/serialization/V8ScriptValueSerializerForModules.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 7 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| 8 #include "bindings/core/v8/ToV8.h" | 8 #include "bindings/core/v8/ToV8.h" |
| 9 #include "bindings/core/v8/V8ArrayBuffer.h" | 9 #include "bindings/core/v8/V8ArrayBuffer.h" |
| 10 #include "bindings/core/v8/V8BindingForTesting.h" | 10 #include "bindings/core/v8/V8BindingForTesting.h" |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 Platform::current()->createRTCCertificateGenerator()); | 172 Platform::current()->createRTCCertificateGenerator()); |
| 173 std::unique_ptr<WebRTCCertificate> webCertificate = | 173 std::unique_ptr<WebRTCCertificate> webCertificate = |
| 174 certificateGenerator->fromPEM( | 174 certificateGenerator->fromPEM( |
| 175 WebString::fromUTF8(kEcdsaPrivateKey, sizeof(kEcdsaPrivateKey)), | 175 WebString::fromUTF8(kEcdsaPrivateKey, sizeof(kEcdsaPrivateKey)), |
| 176 WebString::fromUTF8(kEcdsaCertificate, sizeof(kEcdsaCertificate))); | 176 WebString::fromUTF8(kEcdsaCertificate, sizeof(kEcdsaCertificate))); |
| 177 ASSERT_TRUE(webCertificate); | 177 ASSERT_TRUE(webCertificate); |
| 178 RTCCertificate* certificate = new RTCCertificate(std::move(webCertificate)); | 178 RTCCertificate* certificate = new RTCCertificate(std::move(webCertificate)); |
| 179 | 179 |
| 180 // Round trip test. | 180 // Round trip test. |
| 181 v8::Local<v8::Value> wrapper = | 181 v8::Local<v8::Value> wrapper = |
| 182 toV8(certificate, scope.context()->Global(), scope.isolate()); | 182 ToV8(certificate, scope.context()->Global(), scope.isolate()); |
| 183 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 183 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 184 ASSERT_TRUE(V8RTCCertificate::hasInstance(result, scope.isolate())); | 184 ASSERT_TRUE(V8RTCCertificate::hasInstance(result, scope.isolate())); |
| 185 RTCCertificate* newCertificate = | 185 RTCCertificate* newCertificate = |
| 186 V8RTCCertificate::toImpl(result.As<v8::Object>()); | 186 V8RTCCertificate::toImpl(result.As<v8::Object>()); |
| 187 WebRTCCertificatePEM pem = newCertificate->certificate().toPEM(); | 187 WebRTCCertificatePEM pem = newCertificate->certificate().toPEM(); |
| 188 EXPECT_EQ(kEcdsaPrivateKey, pem.privateKey()); | 188 EXPECT_EQ(kEcdsaPrivateKey, pem.privateKey()); |
| 189 EXPECT_EQ(kEcdsaCertificate, pem.certificate()); | 189 EXPECT_EQ(kEcdsaCertificate, pem.certificate()); |
| 190 } | 190 } |
| 191 | 191 |
| 192 TEST(V8ScriptValueSerializerForModulesTest, DecodeRTCCertificate) { | 192 TEST(V8ScriptValueSerializerForModulesTest, DecodeRTCCertificate) { |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 | 404 |
| 405 // Generate a 128-bit AES key. | 405 // Generate a 128-bit AES key. |
| 406 std::unique_ptr<WebCryptoAlgorithmParams> params( | 406 std::unique_ptr<WebCryptoAlgorithmParams> params( |
| 407 new WebCryptoAesKeyGenParams(128)); | 407 new WebCryptoAesKeyGenParams(128)); |
| 408 WebCryptoAlgorithm algorithm(WebCryptoAlgorithmIdAesCbc, std::move(params)); | 408 WebCryptoAlgorithm algorithm(WebCryptoAlgorithmIdAesCbc, std::move(params)); |
| 409 CryptoKey* key = | 409 CryptoKey* key = |
| 410 syncGenerateKey(scriptState, algorithm, true, | 410 syncGenerateKey(scriptState, algorithm, true, |
| 411 WebCryptoKeyUsageEncrypt | WebCryptoKeyUsageDecrypt); | 411 WebCryptoKeyUsageEncrypt | WebCryptoKeyUsageDecrypt); |
| 412 | 412 |
| 413 // Round trip it and check the visible attributes. | 413 // Round trip it and check the visible attributes. |
| 414 v8::Local<v8::Value> wrapper = toV8(key, scope.getScriptState()); | 414 v8::Local<v8::Value> wrapper = ToV8(key, scope.getScriptState()); |
| 415 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 415 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 416 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); | 416 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); |
| 417 CryptoKey* newKey = V8CryptoKey::toImpl(result.As<v8::Object>()); | 417 CryptoKey* newKey = V8CryptoKey::toImpl(result.As<v8::Object>()); |
| 418 EXPECT_EQ("secret", newKey->type()); | 418 EXPECT_EQ("secret", newKey->type()); |
| 419 EXPECT_TRUE(newKey->extractable()); | 419 EXPECT_TRUE(newKey->extractable()); |
| 420 EXPECT_THAT(newKey->usages(), UnorderedElementsAre("encrypt", "decrypt")); | 420 EXPECT_THAT(newKey->usages(), UnorderedElementsAre("encrypt", "decrypt")); |
| 421 | 421 |
| 422 // Check that the keys have the same raw representation. | 422 // Check that the keys have the same raw representation. |
| 423 WebVector<uint8_t> keyRaw = | 423 WebVector<uint8_t> keyRaw = |
| 424 syncExportKey(scriptState, WebCryptoKeyFormatRaw, key->key()); | 424 syncExportKey(scriptState, WebCryptoKeyFormatRaw, key->key()); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 WebCryptoAlgorithm hash(WebCryptoAlgorithmIdSha256, nullptr); | 477 WebCryptoAlgorithm hash(WebCryptoAlgorithmIdSha256, nullptr); |
| 478 std::unique_ptr<WebCryptoAlgorithmParams> generateKeyParams( | 478 std::unique_ptr<WebCryptoAlgorithmParams> generateKeyParams( |
| 479 new WebCryptoHmacKeyGenParams(hash, false, 0)); | 479 new WebCryptoHmacKeyGenParams(hash, false, 0)); |
| 480 WebCryptoAlgorithm generateKeyAlgorithm(WebCryptoAlgorithmIdHmac, | 480 WebCryptoAlgorithm generateKeyAlgorithm(WebCryptoAlgorithmIdHmac, |
| 481 std::move(generateKeyParams)); | 481 std::move(generateKeyParams)); |
| 482 CryptoKey* key = | 482 CryptoKey* key = |
| 483 syncGenerateKey(scriptState, generateKeyAlgorithm, true, | 483 syncGenerateKey(scriptState, generateKeyAlgorithm, true, |
| 484 WebCryptoKeyUsageSign | WebCryptoKeyUsageVerify); | 484 WebCryptoKeyUsageSign | WebCryptoKeyUsageVerify); |
| 485 | 485 |
| 486 // Round trip it and check the visible attributes. | 486 // Round trip it and check the visible attributes. |
| 487 v8::Local<v8::Value> wrapper = toV8(key, scope.getScriptState()); | 487 v8::Local<v8::Value> wrapper = ToV8(key, scope.getScriptState()); |
| 488 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 488 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 489 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); | 489 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); |
| 490 CryptoKey* newKey = V8CryptoKey::toImpl(result.As<v8::Object>()); | 490 CryptoKey* newKey = V8CryptoKey::toImpl(result.As<v8::Object>()); |
| 491 EXPECT_EQ("secret", newKey->type()); | 491 EXPECT_EQ("secret", newKey->type()); |
| 492 EXPECT_TRUE(newKey->extractable()); | 492 EXPECT_TRUE(newKey->extractable()); |
| 493 EXPECT_THAT(newKey->usages(), UnorderedElementsAre("sign", "verify")); | 493 EXPECT_THAT(newKey->usages(), UnorderedElementsAre("sign", "verify")); |
| 494 | 494 |
| 495 // Check that the keys have the same raw representation. | 495 // Check that the keys have the same raw representation. |
| 496 WebVector<uint8_t> keyRaw = | 496 WebVector<uint8_t> keyRaw = |
| 497 syncExportKey(scriptState, WebCryptoKeyFormatRaw, key->key()); | 497 syncExportKey(scriptState, WebCryptoKeyFormatRaw, key->key()); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 new WebCryptoRsaHashedKeyGenParams(hash, 1024, Vector<uint8_t>{1, 0, 1})); | 553 new WebCryptoRsaHashedKeyGenParams(hash, 1024, Vector<uint8_t>{1, 0, 1})); |
| 554 WebCryptoAlgorithm generateKeyAlgorithm(WebCryptoAlgorithmIdRsaPss, | 554 WebCryptoAlgorithm generateKeyAlgorithm(WebCryptoAlgorithmIdRsaPss, |
| 555 std::move(generateKeyParams)); | 555 std::move(generateKeyParams)); |
| 556 CryptoKey* publicKey; | 556 CryptoKey* publicKey; |
| 557 CryptoKey* privateKey; | 557 CryptoKey* privateKey; |
| 558 std::tie(publicKey, privateKey) = | 558 std::tie(publicKey, privateKey) = |
| 559 syncGenerateKeyPair(scriptState, generateKeyAlgorithm, true, | 559 syncGenerateKeyPair(scriptState, generateKeyAlgorithm, true, |
| 560 WebCryptoKeyUsageSign | WebCryptoKeyUsageVerify); | 560 WebCryptoKeyUsageSign | WebCryptoKeyUsageVerify); |
| 561 | 561 |
| 562 // Round trip the private key and check the visible attributes. | 562 // Round trip the private key and check the visible attributes. |
| 563 v8::Local<v8::Value> wrapper = toV8(privateKey, scope.getScriptState()); | 563 v8::Local<v8::Value> wrapper = ToV8(privateKey, scope.getScriptState()); |
| 564 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 564 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 565 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); | 565 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); |
| 566 CryptoKey* newPrivateKey = V8CryptoKey::toImpl(result.As<v8::Object>()); | 566 CryptoKey* newPrivateKey = V8CryptoKey::toImpl(result.As<v8::Object>()); |
| 567 EXPECT_EQ("private", newPrivateKey->type()); | 567 EXPECT_EQ("private", newPrivateKey->type()); |
| 568 EXPECT_TRUE(newPrivateKey->extractable()); | 568 EXPECT_TRUE(newPrivateKey->extractable()); |
| 569 EXPECT_THAT(newPrivateKey->usages(), UnorderedElementsAre("sign")); | 569 EXPECT_THAT(newPrivateKey->usages(), UnorderedElementsAre("sign")); |
| 570 | 570 |
| 571 // Check that the keys have the same PKCS8 representation. | 571 // Check that the keys have the same PKCS8 representation. |
| 572 WebVector<uint8_t> keyRaw = | 572 WebVector<uint8_t> keyRaw = |
| 573 syncExportKey(scriptState, WebCryptoKeyFormatPkcs8, privateKey->key()); | 573 syncExportKey(scriptState, WebCryptoKeyFormatPkcs8, privateKey->key()); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 new WebCryptoEcKeyGenParams(WebCryptoNamedCurveP256)); | 646 new WebCryptoEcKeyGenParams(WebCryptoNamedCurveP256)); |
| 647 WebCryptoAlgorithm generateKeyAlgorithm(WebCryptoAlgorithmIdEcdsa, | 647 WebCryptoAlgorithm generateKeyAlgorithm(WebCryptoAlgorithmIdEcdsa, |
| 648 std::move(generateKeyParams)); | 648 std::move(generateKeyParams)); |
| 649 CryptoKey* publicKey; | 649 CryptoKey* publicKey; |
| 650 CryptoKey* privateKey; | 650 CryptoKey* privateKey; |
| 651 std::tie(publicKey, privateKey) = | 651 std::tie(publicKey, privateKey) = |
| 652 syncGenerateKeyPair(scriptState, generateKeyAlgorithm, true, | 652 syncGenerateKeyPair(scriptState, generateKeyAlgorithm, true, |
| 653 WebCryptoKeyUsageSign | WebCryptoKeyUsageVerify); | 653 WebCryptoKeyUsageSign | WebCryptoKeyUsageVerify); |
| 654 | 654 |
| 655 // Round trip the private key and check the visible attributes. | 655 // Round trip the private key and check the visible attributes. |
| 656 v8::Local<v8::Value> wrapper = toV8(privateKey, scope.getScriptState()); | 656 v8::Local<v8::Value> wrapper = ToV8(privateKey, scope.getScriptState()); |
| 657 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 657 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 658 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); | 658 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); |
| 659 CryptoKey* newPrivateKey = V8CryptoKey::toImpl(result.As<v8::Object>()); | 659 CryptoKey* newPrivateKey = V8CryptoKey::toImpl(result.As<v8::Object>()); |
| 660 EXPECT_EQ("private", newPrivateKey->type()); | 660 EXPECT_EQ("private", newPrivateKey->type()); |
| 661 EXPECT_TRUE(newPrivateKey->extractable()); | 661 EXPECT_TRUE(newPrivateKey->extractable()); |
| 662 EXPECT_THAT(newPrivateKey->usages(), UnorderedElementsAre("sign")); | 662 EXPECT_THAT(newPrivateKey->usages(), UnorderedElementsAre("sign")); |
| 663 | 663 |
| 664 // Check that the keys have the same PKCS8 representation. | 664 // Check that the keys have the same PKCS8 representation. |
| 665 WebVector<uint8_t> keyRaw = | 665 WebVector<uint8_t> keyRaw = |
| 666 syncExportKey(scriptState, WebCryptoKeyFormatPkcs8, privateKey->key()); | 666 syncExportKey(scriptState, WebCryptoKeyFormatPkcs8, privateKey->key()); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 V8TestingScope scope; | 724 V8TestingScope scope; |
| 725 ScriptState* scriptState = scope.getScriptState(); | 725 ScriptState* scriptState = scope.getScriptState(); |
| 726 | 726 |
| 727 // Import some data into a PBKDF2 state. | 727 // Import some data into a PBKDF2 state. |
| 728 WebCryptoAlgorithm importKeyAlgorithm(WebCryptoAlgorithmIdPbkdf2, nullptr); | 728 WebCryptoAlgorithm importKeyAlgorithm(WebCryptoAlgorithmIdPbkdf2, nullptr); |
| 729 CryptoKey* key = syncImportKey(scriptState, WebCryptoKeyFormatRaw, | 729 CryptoKey* key = syncImportKey(scriptState, WebCryptoKeyFormatRaw, |
| 730 Vector<uint8_t>{1, 2, 3}, importKeyAlgorithm, | 730 Vector<uint8_t>{1, 2, 3}, importKeyAlgorithm, |
| 731 false, WebCryptoKeyUsageDeriveBits); | 731 false, WebCryptoKeyUsageDeriveBits); |
| 732 | 732 |
| 733 // Round trip the key and check the visible attributes. | 733 // Round trip the key and check the visible attributes. |
| 734 v8::Local<v8::Value> wrapper = toV8(key, scope.getScriptState()); | 734 v8::Local<v8::Value> wrapper = ToV8(key, scope.getScriptState()); |
| 735 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 735 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 736 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); | 736 ASSERT_TRUE(V8CryptoKey::hasInstance(result, scope.isolate())); |
| 737 CryptoKey* newKey = V8CryptoKey::toImpl(result.As<v8::Object>()); | 737 CryptoKey* newKey = V8CryptoKey::toImpl(result.As<v8::Object>()); |
| 738 EXPECT_EQ("secret", newKey->type()); | 738 EXPECT_EQ("secret", newKey->type()); |
| 739 EXPECT_FALSE(newKey->extractable()); | 739 EXPECT_FALSE(newKey->extractable()); |
| 740 EXPECT_THAT(newKey->usages(), UnorderedElementsAre("deriveBits")); | 740 EXPECT_THAT(newKey->usages(), UnorderedElementsAre("deriveBits")); |
| 741 | 741 |
| 742 // Check that the keys derive the same bits. | 742 // Check that the keys derive the same bits. |
| 743 WebCryptoAlgorithm hash(WebCryptoAlgorithmIdSha256, nullptr); | 743 WebCryptoAlgorithm hash(WebCryptoAlgorithmIdSha256, nullptr); |
| 744 WebVector<uint8_t> salt(static_cast<size_t>(16)); | 744 WebVector<uint8_t> salt(static_cast<size_t>(16)); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 TEST(V8ScriptValueSerializerForModulesTest, RoundTripDOMFileSystem) { | 889 TEST(V8ScriptValueSerializerForModulesTest, RoundTripDOMFileSystem) { |
| 890 ScopedEnableV8BasedStructuredClone enable; | 890 ScopedEnableV8BasedStructuredClone enable; |
| 891 V8TestingScope scope; | 891 V8TestingScope scope; |
| 892 | 892 |
| 893 DOMFileSystem* fs = DOMFileSystem::create( | 893 DOMFileSystem* fs = DOMFileSystem::create( |
| 894 scope.getExecutionContext(), "http_example.com_0:Persistent", | 894 scope.getExecutionContext(), "http_example.com_0:Persistent", |
| 895 FileSystemTypePersistent, | 895 FileSystemTypePersistent, |
| 896 KURL(ParsedURLString, "filesystem:http://example.com/persistent/")); | 896 KURL(ParsedURLString, "filesystem:http://example.com/persistent/")); |
| 897 // At time of writing, this can only happen for filesystems from PPAPI. | 897 // At time of writing, this can only happen for filesystems from PPAPI. |
| 898 fs->makeClonable(); | 898 fs->makeClonable(); |
| 899 v8::Local<v8::Value> wrapper = toV8(fs, scope.getScriptState()); | 899 v8::Local<v8::Value> wrapper = ToV8(fs, scope.getScriptState()); |
| 900 v8::Local<v8::Value> result = roundTrip(wrapper, scope); | 900 v8::Local<v8::Value> result = roundTrip(wrapper, scope); |
| 901 ASSERT_FALSE(result.IsEmpty()); | 901 ASSERT_FALSE(result.IsEmpty()); |
| 902 ASSERT_TRUE(V8DOMFileSystem::hasInstance(result, scope.isolate())); | 902 ASSERT_TRUE(V8DOMFileSystem::hasInstance(result, scope.isolate())); |
| 903 DOMFileSystem* newFS = V8DOMFileSystem::toImpl(result.As<v8::Object>()); | 903 DOMFileSystem* newFS = V8DOMFileSystem::toImpl(result.As<v8::Object>()); |
| 904 EXPECT_EQ("http_example.com_0:Persistent", newFS->name()); | 904 EXPECT_EQ("http_example.com_0:Persistent", newFS->name()); |
| 905 EXPECT_EQ(FileSystemTypePersistent, newFS->type()); | 905 EXPECT_EQ(FileSystemTypePersistent, newFS->type()); |
| 906 EXPECT_EQ("filesystem:http://example.com/persistent/", | 906 EXPECT_EQ("filesystem:http://example.com/persistent/", |
| 907 newFS->rootURL().getString()); | 907 newFS->rootURL().getString()); |
| 908 } | 908 } |
| 909 | 909 |
| 910 TEST(V8ScriptValueSerializerForModulesTest, RoundTripDOMFileSystemNotClonable) { | 910 TEST(V8ScriptValueSerializerForModulesTest, RoundTripDOMFileSystemNotClonable) { |
| 911 ScopedEnableV8BasedStructuredClone enable; | 911 ScopedEnableV8BasedStructuredClone enable; |
| 912 V8TestingScope scope; | 912 V8TestingScope scope; |
| 913 ExceptionState exceptionState(scope.isolate(), | 913 ExceptionState exceptionState(scope.isolate(), |
| 914 ExceptionState::ExecutionContext, "Window", | 914 ExceptionState::ExecutionContext, "Window", |
| 915 "postMessage"); | 915 "postMessage"); |
| 916 | 916 |
| 917 DOMFileSystem* fs = DOMFileSystem::create( | 917 DOMFileSystem* fs = DOMFileSystem::create( |
| 918 scope.getExecutionContext(), "http_example.com_0:Persistent", | 918 scope.getExecutionContext(), "http_example.com_0:Persistent", |
| 919 FileSystemTypePersistent, | 919 FileSystemTypePersistent, |
| 920 KURL(ParsedURLString, "filesystem:http://example.com/persistent/0/")); | 920 KURL(ParsedURLString, "filesystem:http://example.com/persistent/0/")); |
| 921 ASSERT_FALSE(fs->clonable()); | 921 ASSERT_FALSE(fs->clonable()); |
| 922 v8::Local<v8::Value> wrapper = toV8(fs, scope.getScriptState()); | 922 v8::Local<v8::Value> wrapper = ToV8(fs, scope.getScriptState()); |
| 923 EXPECT_FALSE(V8ScriptValueSerializer(scope.getScriptState()) | 923 EXPECT_FALSE(V8ScriptValueSerializer(scope.getScriptState()) |
| 924 .serialize(wrapper, nullptr, exceptionState)); | 924 .serialize(wrapper, nullptr, exceptionState)); |
| 925 EXPECT_TRUE(hadDOMException("DataCloneError", scope.getScriptState(), | 925 EXPECT_TRUE(hadDOMException("DataCloneError", scope.getScriptState(), |
| 926 exceptionState)); | 926 exceptionState)); |
| 927 } | 927 } |
| 928 | 928 |
| 929 TEST(V8ScriptValueSerializerForModulesTest, DecodeDOMFileSystem) { | 929 TEST(V8ScriptValueSerializerForModulesTest, DecodeDOMFileSystem) { |
| 930 ScopedEnableV8BasedStructuredClone enable; | 930 ScopedEnableV8BasedStructuredClone enable; |
| 931 V8TestingScope scope; | 931 V8TestingScope scope; |
| 932 | 932 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x73, 0x69, | 971 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x73, 0x69, |
| 972 0x73, 0x74, 0x65, 0x6e, 0x74, 0x2f | 972 0x73, 0x74, 0x65, 0x6e, 0x74, 0x2f |
| 973 | 973 |
| 974 })) | 974 })) |
| 975 .deserialize() | 975 .deserialize() |
| 976 ->IsNull()); | 976 ->IsNull()); |
| 977 } | 977 } |
| 978 | 978 |
| 979 } // namespace | 979 } // namespace |
| 980 } // namespace blink | 980 } // namespace blink |
| OLD | NEW |