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 <utility>
6
7 #include "base/test/task_environment.h"
8 #include "mojo/public/cpp/bindings/pending_receiver.h"
9 #include "mojo/public/cpp/bindings/receiver.h"
10 #include "mojo/public/cpp/bindings/remote.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "url/mojom/url_test.mojom.h"
13
14 namespace url {
15
16 class UrlTestImpl : public mojom::UrlTest {
17 public:
UrlTestImpl(mojo::PendingReceiver<mojom::UrlTest> receiver)18 explicit UrlTestImpl(mojo::PendingReceiver<mojom::UrlTest> receiver)
19 : receiver_(this, std::move(receiver)) {}
20
21 // UrlTest:
BounceUrl(const GURL & in,BounceUrlCallback callback)22 void BounceUrl(const GURL& in, BounceUrlCallback callback) override {
23 std::move(callback).Run(in);
24 }
25
BounceOrigin(const Origin & in,BounceOriginCallback callback)26 void BounceOrigin(const Origin& in, BounceOriginCallback callback) override {
27 std::move(callback).Run(in);
28 }
29
30 private:
31 mojo::Receiver<UrlTest> receiver_;
32 };
33
34 class MojoGURLStructTraitsTest : public ::testing::Test {
35 public:
MojoGURLStructTraitsTest()36 MojoGURLStructTraitsTest()
37 : url_test_impl_(url_test_remote_.BindNewPipeAndPassReceiver()) {}
38
BounceUrl(const GURL & input)39 GURL BounceUrl(const GURL& input) {
40 GURL output;
41 EXPECT_TRUE(url_test_remote_->BounceUrl(input, &output));
42 return output;
43 }
44
ExpectSerializationRoundtrips(const GURL & input)45 void ExpectSerializationRoundtrips(const GURL& input) {
46 SCOPED_TRACE(testing::Message()
47 << "Input GURL: " << input.possibly_invalid_spec());
48 GURL output = BounceUrl(input);
49
50 // We want to test each component individually to make sure its range was
51 // correctly serialized and deserialized, not just the spec.
52 EXPECT_EQ(input.possibly_invalid_spec(), output.possibly_invalid_spec());
53 EXPECT_EQ(input.is_valid(), output.is_valid());
54 EXPECT_EQ(input.scheme(), output.scheme());
55 EXPECT_EQ(input.username(), output.username());
56 EXPECT_EQ(input.password(), output.password());
57 EXPECT_EQ(input.host(), output.host());
58 EXPECT_EQ(input.port(), output.port());
59 EXPECT_EQ(input.path(), output.path());
60 EXPECT_EQ(input.query(), output.query());
61 EXPECT_EQ(input.ref(), output.ref());
62 }
63
BounceOrigin(const Origin & input)64 Origin BounceOrigin(const Origin& input) {
65 Origin output;
66 EXPECT_TRUE(url_test_remote_->BounceOrigin(input, &output));
67 return output;
68 }
69
70 private:
71 base::test::SingleThreadTaskEnvironment task_environment;
72 mojo::Remote<mojom::UrlTest> url_test_remote_;
73 UrlTestImpl url_test_impl_;
74 };
75
76 // Mojo version of chrome IPC test in url/ipc/url_param_traits_unittest.cc.
TEST_F(MojoGURLStructTraitsTest,Basic)77 TEST_F(MojoGURLStructTraitsTest, Basic) {
78 const char* serialize_cases[] = {
79 "http://www.google.com/",
80 "http://user:[email protected]:888/foo;bar?baz#nop",
81 };
82
83 for (const char* test_input : serialize_cases) {
84 SCOPED_TRACE(testing::Message() << "Test input: " << test_input);
85 GURL input(test_input);
86 ExpectSerializationRoundtrips(input);
87 }
88 }
89
90 // Test of an excessively long GURL.
TEST_F(MojoGURLStructTraitsTest,ExcessivelyLongUrl)91 TEST_F(MojoGURLStructTraitsTest, ExcessivelyLongUrl) {
92 const std::string url =
93 std::string("http://example.org/").append(kMaxURLChars + 1, 'a');
94 GURL input(url.c_str());
95 GURL output = BounceUrl(input);
96 EXPECT_TRUE(output.is_empty());
97 }
98
99 // Test for the GURL testcase based on https://crbug.com/1214098 (which in turn
100 // was based on ContentSecurityPolicyBrowserTest.FileURLs).
TEST_F(MojoGURLStructTraitsTest,WindowsDriveInPathReplacement)101 TEST_F(MojoGURLStructTraitsTest, WindowsDriveInPathReplacement) {
102 {
103 // #1: Try creating a file URL with a non-empty hostname.
104 GURL url_without_windows_drive_letter("file://hostname/");
105 EXPECT_EQ("/", url_without_windows_drive_letter.path());
106 EXPECT_EQ("hostname", url_without_windows_drive_letter.host());
107 ExpectSerializationRoundtrips(url_without_windows_drive_letter);
108 }
109
110 {
111 // #2: Use GURL::Replacement to create a GURL with 1) a path that starts
112 // with a Windows drive letter and 2) has a non-empty hostname (inherited
113 // from `url_without_windows_drive_letter` above). This used to not go
114 // through the DoParseUNC path that normally strips the hostname (for more
115 // details, see https://crbug.com/1214098#c4).
116 GURL::Replacements repl;
117 const std::string kNewPath = "/C:/dir/file.txt";
118 repl.SetPathStr(kNewPath);
119 GURL url_made_with_replace_components =
120 GURL("file://hostname/").ReplaceComponents(repl);
121
122 EXPECT_EQ(kNewPath, url_made_with_replace_components.path());
123 EXPECT_EQ("hostname", url_made_with_replace_components.host());
124 EXPECT_EQ("file://hostname/C:/dir/file.txt",
125 url_made_with_replace_components.spec());
126 // This is the MAIN VERIFICATION in this test. This used to fail on Windows,
127 // see https://crbug.com/1214098.
128 ExpectSerializationRoundtrips(url_made_with_replace_components);
129 }
130
131 {
132 // #3: Try to create a URL with a Windows drive letter and a non-empty
133 // hostname directly.
134 GURL url_created_directly("file://hostname/C:/dir/file.txt");
135 EXPECT_EQ("/C:/dir/file.txt", url_created_directly.path());
136 EXPECT_EQ("hostname", url_created_directly.host());
137 EXPECT_EQ("file://hostname/C:/dir/file.txt", url_created_directly.spec());
138 ExpectSerializationRoundtrips(url_created_directly);
139
140 // The URL created directly and the URL created through ReplaceComponents
141 // should be the same.
142 GURL::Replacements repl;
143 const std::string kNewPath = "/C:/dir/file.txt";
144 repl.SetPathStr(kNewPath);
145 GURL url_made_with_replace_components =
146 GURL("file://hostname/").ReplaceComponents(repl);
147 EXPECT_EQ(url_created_directly.spec(),
148 url_made_with_replace_components.spec());
149 }
150
151 {
152 // #4: Try to create a URL with a Windows drive letter and "localhost" as
153 // hostname directly.
154 GURL url_created_directly("file://localhost/C:/dir/file.txt");
155 EXPECT_EQ("/C:/dir/file.txt", url_created_directly.path());
156 EXPECT_EQ("", url_created_directly.host());
157 EXPECT_EQ("file:///C:/dir/file.txt", url_created_directly.spec());
158 ExpectSerializationRoundtrips(url_created_directly);
159
160 // The URL created directly and the URL created through ReplaceComponents
161 // should be the same.
162 GURL::Replacements repl;
163 const std::string kNewPath = "/C:/dir/file.txt";
164 repl.SetPathStr(kNewPath);
165 GURL url_made_with_replace_components =
166 GURL("file://localhost/").ReplaceComponents(repl);
167 EXPECT_EQ(url_created_directly.spec(),
168 url_made_with_replace_components.spec());
169 }
170 }
171
172 // Test of basic Origin serialization.
TEST_F(MojoGURLStructTraitsTest,OriginSerialization)173 TEST_F(MojoGURLStructTraitsTest, OriginSerialization) {
174 Origin non_unique = Origin::UnsafelyCreateTupleOriginWithoutNormalization(
175 "http", "www.google.com", 80)
176 .value();
177 Origin output = BounceOrigin(non_unique);
178 EXPECT_EQ(non_unique, output);
179 EXPECT_FALSE(output.opaque());
180
181 Origin unique1;
182 Origin unique2 = non_unique.DeriveNewOpaqueOrigin();
183 EXPECT_NE(unique1, unique2);
184 EXPECT_NE(unique2, unique1);
185 EXPECT_NE(unique2, non_unique);
186 output = BounceOrigin(unique1);
187 EXPECT_TRUE(output.opaque());
188 EXPECT_EQ(unique1, output);
189 Origin output2 = BounceOrigin(unique2);
190 EXPECT_EQ(unique2, output2);
191 EXPECT_NE(unique2, output);
192 EXPECT_NE(unique1, output2);
193
194 Origin normalized =
195 Origin::CreateFromNormalizedTuple("http", "www.google.com", 80);
196 EXPECT_EQ(normalized, non_unique);
197 output = BounceOrigin(normalized);
198 EXPECT_EQ(normalized, output);
199 EXPECT_EQ(non_unique, output);
200 EXPECT_FALSE(output.opaque());
201 }
202
203 // Test that the "kMaxURLChars" values are the same in url.mojom and
204 // url_constants.cc.
TEST_F(MojoGURLStructTraitsTest,TestMaxURLChars)205 TEST_F(MojoGURLStructTraitsTest, TestMaxURLChars) {
206 EXPECT_EQ(kMaxURLChars, mojom::kMaxURLChars);
207 }
208
209 } // namespace url
210