| // Copyright (c) 2012 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. | 
 |  | 
 | #include "content/public/common/common_param_traits.h" | 
 |  | 
 | #include <stddef.h> | 
 | #include <string.h> | 
 |  | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | #include "base/macros.h" | 
 | #include "base/values.h" | 
 | #include "components/viz/common/surfaces/surface_info.h" | 
 | #include "content/common/resource_messages.h" | 
 | #include "content/public/common/content_constants.h" | 
 | #include "ipc/ipc_message.h" | 
 | #include "ipc/ipc_message_utils.h" | 
 | #include "net/base/host_port_pair.h" | 
 | #include "net/cert/ct_policy_status.h" | 
 | #include "net/ssl/ssl_info.h" | 
 | #include "net/test/cert_test_util.h" | 
 | #include "net/test/test_data_directory.h" | 
 | #include "printing/backend/print_backend.h" | 
 | #include "printing/page_range.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "third_party/skia/include/core/SkBitmap.h" | 
 | #include "ui/gfx/geometry/rect.h" | 
 | #include "ui/gfx/ipc/gfx_param_traits.h" | 
 | #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h" | 
 |  | 
 | // Tests std::pair serialization | 
 | TEST(IPCMessageTest, Pair) { | 
 |   typedef std::pair<std::string, std::string> TestPair; | 
 |  | 
 |   TestPair input("foo", "bar"); | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::ParamTraits<TestPair>::Write(&msg, input); | 
 |  | 
 |   TestPair output; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ParamTraits<TestPair>::Read(&msg, &iter, &output)); | 
 |   EXPECT_EQ(output.first, "foo"); | 
 |   EXPECT_EQ(output.second, "bar"); | 
 | } | 
 |  | 
 | // Tests bitmap serialization. | 
 | TEST(IPCMessageTest, Bitmap) { | 
 |   SkBitmap bitmap; | 
 |  | 
 |   bitmap.allocN32Pixels(10, 5); | 
 |   memset(bitmap.getPixels(), 'A', bitmap.computeByteSize()); | 
 |  | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::ParamTraits<SkBitmap>::Write(&msg, bitmap); | 
 |  | 
 |   SkBitmap output; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ParamTraits<SkBitmap>::Read(&msg, &iter, &output)); | 
 |  | 
 |   EXPECT_EQ(bitmap.colorType(), output.colorType()); | 
 |   EXPECT_EQ(bitmap.width(), output.width()); | 
 |   EXPECT_EQ(bitmap.height(), output.height()); | 
 |   EXPECT_EQ(bitmap.rowBytes(), output.rowBytes()); | 
 |   EXPECT_EQ(bitmap.computeByteSize(), output.computeByteSize()); | 
 |   EXPECT_EQ( | 
 |       memcmp(bitmap.getPixels(), output.getPixels(), bitmap.computeByteSize()), | 
 |       0); | 
 |  | 
 |   // Also test the corrupt case. | 
 |   IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   // Copy the first message block over to |bad_msg|. | 
 |   const char* fixed_data; | 
 |   int fixed_data_size; | 
 |   iter = base::PickleIterator(msg); | 
 |   EXPECT_TRUE(iter.ReadData(&fixed_data, &fixed_data_size)); | 
 |   bad_msg.WriteData(fixed_data, fixed_data_size); | 
 |   // Add some bogus pixel data. | 
 |   const size_t bogus_pixels_size = bitmap.computeByteSize() * 2; | 
 |   std::unique_ptr<char[]> bogus_pixels(new char[bogus_pixels_size]); | 
 |   memset(bogus_pixels.get(), 'B', bogus_pixels_size); | 
 |   bad_msg.WriteData(bogus_pixels.get(), bogus_pixels_size); | 
 |   // Make sure we don't read out the bitmap! | 
 |   SkBitmap bad_output; | 
 |   iter = base::PickleIterator(bad_msg); | 
 |   EXPECT_FALSE(IPC::ParamTraits<SkBitmap>::Read(&bad_msg, &iter, &bad_output)); | 
 | } | 
 |  | 
 | TEST(IPCMessageTest, ListValue) { | 
 |   base::ListValue input; | 
 |   input.AppendDouble(42.42); | 
 |   input.AppendString("forty"); | 
 |   input.Append(std::make_unique<base::Value>()); | 
 |  | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::WriteParam(&msg, input); | 
 |  | 
 |   base::ListValue output; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); | 
 |  | 
 |   EXPECT_TRUE(input.Equals(&output)); | 
 |  | 
 |   // Also test the corrupt case. | 
 |   IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   bad_msg.WriteInt(99); | 
 |   iter = base::PickleIterator(bad_msg); | 
 |   EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output)); | 
 | } | 
 |  | 
 | TEST(IPCMessageTest, DictionaryValue) { | 
 |   base::DictionaryValue input; | 
 |   input.Set("null", std::make_unique<base::Value>()); | 
 |   input.SetBoolean("bool", true); | 
 |   input.SetInteger("int", 42); | 
 |  | 
 |   auto subdict = std::make_unique<base::DictionaryValue>(); | 
 |   subdict->SetString("str", "forty two"); | 
 |   subdict->SetBoolean("bool", false); | 
 |  | 
 |   auto sublist = std::make_unique<base::ListValue>(); | 
 |   sublist->AppendDouble(42.42); | 
 |   sublist->AppendString("forty"); | 
 |   sublist->AppendString("two"); | 
 |   subdict->Set("list", std::move(sublist)); | 
 |  | 
 |   input.Set("dict", std::move(subdict)); | 
 |  | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::WriteParam(&msg, input); | 
 |  | 
 |   base::DictionaryValue output; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output)); | 
 |  | 
 |   EXPECT_TRUE(input.Equals(&output)); | 
 |  | 
 |   // Also test the corrupt case. | 
 |   IPC::Message bad_msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   bad_msg.WriteInt(99); | 
 |   iter = base::PickleIterator(bad_msg); | 
 |   EXPECT_FALSE(IPC::ReadParam(&bad_msg, &iter, &output)); | 
 | } | 
 |  | 
 | // Tests net::HostPortPair serialization | 
 | TEST(IPCMessageTest, HostPortPair) { | 
 |   net::HostPortPair input("host.com", 12345); | 
 |  | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::ParamTraits<net::HostPortPair>::Write(&msg, input); | 
 |  | 
 |   net::HostPortPair output; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ParamTraits<net::HostPortPair>::Read(&msg, &iter, &output)); | 
 |   EXPECT_EQ(input.host(), output.host()); | 
 |   EXPECT_EQ(input.port(), output.port()); | 
 | } | 
 |  | 
 | // Tests net::SSLInfo serialization | 
 | TEST(IPCMessageTest, SSLInfo) { | 
 |   // Build a SSLInfo. Avoid false for booleans as that's the default value. | 
 |   net::SSLInfo in; | 
 |   in.cert = | 
 |       net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); | 
 |   in.unverified_cert = net::ImportCertFromFile(net::GetTestCertsDirectory(), | 
 |                                                "ok_cert_by_intermediate.pem"); | 
 |   in.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID; | 
 |   in.security_bits = 0x100; | 
 |   in.key_exchange_group = 1024; | 
 |   in.connection_status = 0x300039;  // TLS_DHE_RSA_WITH_AES_256_CBC_SHA | 
 |   in.is_issued_by_known_root = true; | 
 |   in.pkp_bypassed = true; | 
 |   in.client_cert_sent = true; | 
 |   in.channel_id_sent = true; | 
 |   in.handshake_type = net::SSLInfo::HANDSHAKE_FULL; | 
 |   const net::SHA256HashValue kCertPublicKeyHashValue = {{0x01, 0x02}}; | 
 |   in.public_key_hashes.push_back(net::HashValue(kCertPublicKeyHashValue)); | 
 |   in.pinning_failure_log = "foo"; | 
 |  | 
 |   scoped_refptr<net::ct::SignedCertificateTimestamp> sct( | 
 |       new net::ct::SignedCertificateTimestamp()); | 
 |   sct->version = net::ct::SignedCertificateTimestamp::V1; | 
 |   sct->log_id = "unknown_log_id"; | 
 |   sct->extensions = "extensions"; | 
 |   sct->timestamp = base::Time::Now(); | 
 |   sct->signature.hash_algorithm = net::ct::DigitallySigned::HASH_ALGO_MD5; | 
 |   sct->signature.signature_algorithm = net::ct::DigitallySigned::SIG_ALGO_RSA; | 
 |   sct->signature.signature_data = "signature"; | 
 |   sct->origin = net::ct::SignedCertificateTimestamp::SCT_EMBEDDED; | 
 |   in.signed_certificate_timestamps.push_back( | 
 |       net::SignedCertificateTimestampAndStatus( | 
 |           sct, net::ct::SCT_STATUS_LOG_UNKNOWN)); | 
 |  | 
 |   in.ct_policy_compliance = | 
 |       net::ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS; | 
 |   in.ocsp_result.response_status = net::OCSPVerifyResult::PROVIDED; | 
 |   in.ocsp_result.revocation_status = net::OCSPRevocationStatus::REVOKED; | 
 |  | 
 |   // Now serialize and deserialize. | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::ParamTraits<net::SSLInfo>::Write(&msg, in); | 
 |  | 
 |   net::SSLInfo out; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ParamTraits<net::SSLInfo>::Read(&msg, &iter, &out)); | 
 |  | 
 |   // Now verify they're equal. | 
 |   ASSERT_TRUE(in.cert->EqualsIncludingChain(out.cert.get())); | 
 |   ASSERT_TRUE( | 
 |       in.unverified_cert->EqualsIncludingChain(out.unverified_cert.get())); | 
 |   ASSERT_EQ(in.security_bits, out.security_bits); | 
 |   ASSERT_EQ(in.key_exchange_group, out.key_exchange_group); | 
 |   ASSERT_EQ(in.connection_status, out.connection_status); | 
 |   ASSERT_EQ(in.is_issued_by_known_root, out.is_issued_by_known_root); | 
 |   ASSERT_EQ(in.pkp_bypassed, out.pkp_bypassed); | 
 |   ASSERT_EQ(in.client_cert_sent, out.client_cert_sent); | 
 |   ASSERT_EQ(in.channel_id_sent, out.channel_id_sent); | 
 |   ASSERT_EQ(in.handshake_type, out.handshake_type); | 
 |   ASSERT_EQ(in.public_key_hashes, out.public_key_hashes); | 
 |   ASSERT_EQ(in.pinning_failure_log, out.pinning_failure_log); | 
 |  | 
 |   ASSERT_EQ(in.signed_certificate_timestamps.size(), | 
 |             out.signed_certificate_timestamps.size()); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].status, | 
 |             out.signed_certificate_timestamps[0].status); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->version, | 
 |             out.signed_certificate_timestamps[0].sct->version); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->log_id, | 
 |             out.signed_certificate_timestamps[0].sct->log_id); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->timestamp, | 
 |             out.signed_certificate_timestamps[0].sct->timestamp); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->extensions, | 
 |             out.signed_certificate_timestamps[0].sct->extensions); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->signature.hash_algorithm, | 
 |             out.signed_certificate_timestamps[0].sct->signature.hash_algorithm); | 
 |   ASSERT_EQ( | 
 |       in.signed_certificate_timestamps[0].sct->signature.signature_algorithm, | 
 |       out.signed_certificate_timestamps[0].sct->signature.signature_algorithm); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->signature.signature_data, | 
 |             out.signed_certificate_timestamps[0].sct->signature.signature_data); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->origin, | 
 |             out.signed_certificate_timestamps[0].sct->origin); | 
 |   ASSERT_EQ(in.signed_certificate_timestamps[0].sct->log_description, | 
 |             out.signed_certificate_timestamps[0].sct->log_description); | 
 |  | 
 |   ASSERT_EQ(in.ct_policy_compliance, out.ct_policy_compliance); | 
 |   ASSERT_EQ(in.ocsp_result, out.ocsp_result); | 
 | } | 
 |  | 
 | TEST(IPCMessageTest, RenderWidgetSurfaceProperties) { | 
 |   content::RenderWidgetSurfaceProperties input; | 
 |   input.size = gfx::Size(23, 45); | 
 |   input.device_scale_factor = 0.8; | 
 |   input.top_controls_height = 16.5; | 
 |   input.top_controls_shown_ratio = 0.4; | 
 | #ifdef OS_ANDROID | 
 |   input.bottom_controls_height = 23.4; | 
 |   input.bottom_controls_shown_ratio = 0.8; | 
 |   input.selection.start.set_type(gfx::SelectionBound::Type::CENTER); | 
 |   input.has_transparent_background = true; | 
 | #endif | 
 |  | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   IPC::ParamTraits<content::RenderWidgetSurfaceProperties>::Write(&msg, input); | 
 |  | 
 |   content::RenderWidgetSurfaceProperties output; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE(IPC::ParamTraits<content::RenderWidgetSurfaceProperties>::Read( | 
 |       &msg, &iter, &output)); | 
 |  | 
 |   EXPECT_EQ(input.size, output.size); | 
 |   EXPECT_EQ(input.device_scale_factor, output.device_scale_factor); | 
 |   EXPECT_EQ(input.top_controls_height, output.top_controls_height); | 
 |   EXPECT_EQ(input.top_controls_shown_ratio, output.top_controls_shown_ratio); | 
 | #ifdef OS_ANDROID | 
 |   EXPECT_EQ(input.bottom_controls_height, output.bottom_controls_height); | 
 |   EXPECT_EQ(input.bottom_controls_shown_ratio, | 
 |             output.bottom_controls_shown_ratio); | 
 |   EXPECT_EQ(input.selection, output.selection); | 
 |   EXPECT_EQ(input.has_transparent_background, | 
 |             output.has_transparent_background); | 
 | #endif | 
 | } | 
 |  | 
 | static constexpr viz::FrameSinkId kArbitraryFrameSinkId(1, 1); | 
 |  | 
 | TEST(IPCMessageTest, SurfaceInfo) { | 
 |   IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); | 
 |   const viz::SurfaceId kArbitrarySurfaceId( | 
 |       kArbitraryFrameSinkId, | 
 |       viz::LocalSurfaceId(3, base::UnguessableToken::Create())); | 
 |   constexpr float kArbitraryDeviceScaleFactor = 0.9f; | 
 |   const gfx::Size kArbitrarySize(65, 321); | 
 |   const viz::SurfaceInfo surface_info_in( | 
 |       kArbitrarySurfaceId, kArbitraryDeviceScaleFactor, kArbitrarySize); | 
 |   IPC::ParamTraits<viz::SurfaceInfo>::Write(&msg, surface_info_in); | 
 |  | 
 |   viz::SurfaceInfo surface_info_out; | 
 |   base::PickleIterator iter(msg); | 
 |   EXPECT_TRUE( | 
 |       IPC::ParamTraits<viz::SurfaceInfo>::Read(&msg, &iter, &surface_info_out)); | 
 |  | 
 |   ASSERT_EQ(surface_info_in, surface_info_out); | 
 | } |