1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <string>
6
7 #include "ipc/ipc_message.h"
8 #include "ipc/ipc_message_utils.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "url/gurl.h"
11 #include "url/ipc/url_param_traits.h"
12
13 namespace {
14
BounceUrl(const GURL & input)15 GURL BounceUrl(const GURL& input) {
16 IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
17 IPC::ParamTraits<GURL>::Write(&msg, input);
18
19 GURL output;
20 base::PickleIterator iter(msg);
21 EXPECT_TRUE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output));
22
23 return output;
24 }
25
ExpectSerializationRoundtrips(const GURL & input)26 void ExpectSerializationRoundtrips(const GURL& input) {
27 SCOPED_TRACE(testing::Message()
28 << "Input GURL: " << input.possibly_invalid_spec());
29 GURL output = BounceUrl(input);
30
31 // We want to test each component individually to make sure its range was
32 // correctly serialized and deserialized, not just the spec.
33 EXPECT_EQ(input.possibly_invalid_spec(), output.possibly_invalid_spec());
34 EXPECT_EQ(input.is_valid(), output.is_valid());
35 EXPECT_EQ(input.scheme(), output.scheme());
36 EXPECT_EQ(input.username(), output.username());
37 EXPECT_EQ(input.password(), output.password());
38 EXPECT_EQ(input.host(), output.host());
39 EXPECT_EQ(input.port(), output.port());
40 EXPECT_EQ(input.path(), output.path());
41 EXPECT_EQ(input.query(), output.query());
42 EXPECT_EQ(input.ref(), output.ref());
43 }
44
45 } // namespace
46
47 // Tests that serialize/deserialize correctly understand each other.
TEST(IPCMessageTest,SerializeGurl_Basic)48 TEST(IPCMessageTest, SerializeGurl_Basic) {
49 const char* serialize_cases[] = {
50 "http://www.google.com/",
51 "http://user:[email protected]:888/foo;bar?baz#nop",
52 };
53
54 for (const char* test_input : serialize_cases) {
55 SCOPED_TRACE(testing::Message() << "Test input: " << test_input);
56 GURL input(test_input);
57 ExpectSerializationRoundtrips(input);
58 }
59 }
60
61 // Test of an excessively long GURL.
TEST(IPCMessageTest,SerializeGurl_ExcessivelyLong)62 TEST(IPCMessageTest, SerializeGurl_ExcessivelyLong) {
63 const std::string url =
64 std::string("http://example.org/").append(url::kMaxURLChars + 1, 'a');
65 GURL input(url.c_str());
66 GURL output = BounceUrl(input);
67 EXPECT_TRUE(output.is_empty());
68 }
69
70 // Test of an invalid GURL.
TEST(IPCMessageTest,SerializeGurl_InvalidUrl)71 TEST(IPCMessageTest, SerializeGurl_InvalidUrl) {
72 IPC::Message msg;
73 msg.WriteString("#inva://idurl/");
74 GURL output;
75 base::PickleIterator iter(msg);
76 EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output));
77 }
78
79 // Test of a corrupt deserialization input.
TEST(IPCMessageTest,SerializeGurl_CorruptPayload)80 TEST(IPCMessageTest, SerializeGurl_CorruptPayload) {
81 IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
82 msg.WriteInt(99);
83 GURL output;
84 base::PickleIterator iter(msg);
85 EXPECT_FALSE(IPC::ParamTraits<GURL>::Read(&msg, &iter, &output));
86 }
87
88 // Test for the GURL testcase based on https://crbug.com/1214098 (which in turn
89 // was based on ContentSecurityPolicyBrowserTest.FileURLs).
TEST(IPCMessageTest,SerializeGurl_WindowsDriveInPathReplacement)90 TEST(IPCMessageTest, SerializeGurl_WindowsDriveInPathReplacement) {
91 {
92 // #1: Try creating a file URL with a non-empty hostname.
93 GURL url_without_windows_drive_letter("file://hostname/");
94 EXPECT_EQ("/", url_without_windows_drive_letter.path());
95 EXPECT_EQ("hostname", url_without_windows_drive_letter.host());
96 ExpectSerializationRoundtrips(url_without_windows_drive_letter);
97 }
98
99 {
100 // #2: Use GURL::Replacement to create a GURL with 1) a path that starts
101 // with a Windows drive letter and 2) has a non-empty hostname (inherited
102 // from `url_without_windows_drive_letter` above). This used to not go
103 // through the DoParseUNC path that normally strips the hostname (for more
104 // details, see https://crbug.com/1214098#c4).
105 GURL::Replacements repl;
106 const std::string kNewPath = "/C:/dir/file.txt";
107 repl.SetPathStr(kNewPath);
108 GURL url_made_with_replace_components =
109 GURL("file://hostname/").ReplaceComponents(repl);
110
111 EXPECT_EQ(kNewPath, url_made_with_replace_components.path());
112 EXPECT_EQ("hostname", url_made_with_replace_components.host());
113 EXPECT_EQ("file://hostname/C:/dir/file.txt",
114 url_made_with_replace_components.spec());
115 // This is the MAIN VERIFICATION in this test. This used to fail on Windows,
116 // see https://crbug.com/1214098.
117 ExpectSerializationRoundtrips(url_made_with_replace_components);
118 }
119
120 {
121 // #3: Try to create a URL with a Windows drive letter and a non-empty
122 // hostname directly.
123 GURL url_created_directly("file://hostname/C:/dir/file.txt");
124 EXPECT_EQ("/C:/dir/file.txt", url_created_directly.path());
125 EXPECT_EQ("hostname", url_created_directly.host());
126 EXPECT_EQ("file://hostname/C:/dir/file.txt", url_created_directly.spec());
127 ExpectSerializationRoundtrips(url_created_directly);
128
129 // The URL created directly and the URL created through ReplaceComponents
130 // should be the same.
131 GURL::Replacements repl;
132 const std::string kNewPath = "/C:/dir/file.txt";
133 repl.SetPathStr(kNewPath);
134 GURL url_made_with_replace_components =
135 GURL("file://hostname/").ReplaceComponents(repl);
136 EXPECT_EQ(url_created_directly.spec(),
137 url_made_with_replace_components.spec());
138 }
139
140 {
141 // #4: Try to create a URL with a Windows drive letter and "localhost" as
142 // hostname directly.
143 GURL url_created_directly("file://localhost/C:/dir/file.txt");
144 EXPECT_EQ("/C:/dir/file.txt", url_created_directly.path());
145 EXPECT_EQ("", url_created_directly.host());
146 EXPECT_EQ("file:///C:/dir/file.txt", url_created_directly.spec());
147 ExpectSerializationRoundtrips(url_created_directly);
148
149 // The URL created directly and the URL created through ReplaceComponents
150 // should be the same.
151 GURL::Replacements repl;
152 const std::string kNewPath = "/C:/dir/file.txt";
153 repl.SetPathStr(kNewPath);
154 GURL url_made_with_replace_components =
155 GURL("file://localhost/").ReplaceComponents(repl);
156 EXPECT_EQ(url_created_directly.spec(),
157 url_made_with_replace_components.spec());
158 }
159 }
160