| 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 "content/browser/service_worker/link_header_support.h" | 5 #include "components/link_header_util/link_header_util.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | |
| 8 #include "base/logging.h" | 7 #include "base/logging.h" |
| 9 #include "base/run_loop.h" | 8 #include "base/run_loop.h" |
| 10 #include "content/browser/service_worker/embedded_worker_test_helper.h" | |
| 11 #include "content/browser/service_worker/service_worker_context_wrapper.h" | |
| 12 #include "content/browser/service_worker/service_worker_registration.h" | |
| 13 #include "content/public/browser/resource_request_info.h" | |
| 14 #include "content/public/common/content_switches.h" | |
| 15 #include "content/public/test/mock_resource_context.h" | |
| 16 #include "content/public/test/test_browser_thread_bundle.h" | |
| 17 #include "net/http/http_response_headers.h" | |
| 18 #include "net/url_request/url_request_test_job.h" | |
| 19 #include "net/url_request/url_request_test_util.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
| 21 | 10 |
| 22 namespace content { | 11 namespace link_header_util { |
| 23 | 12 |
| 24 namespace { | 13 namespace { |
| 25 | 14 |
| 15 void SplitLinkHeaderForTesting(const std::string& header, |
| 16 std::vector<std::string>* values) { |
| 17 std::vector<StringIteratorPair> values_iterators = SplitLinkHeader(header); |
| 18 values->clear(); |
| 19 for (const auto& pair : values_iterators) |
| 20 values->push_back(std::string(pair.first, pair.second)); |
| 21 } |
| 22 |
| 23 bool ParseLinkHeaderValueForTesting( |
| 24 std::string value, |
| 25 std::string* url, |
| 26 std::unordered_map<std::string, base::Optional<std::string>>* params) { |
| 27 return ParseLinkHeaderValue(value.begin(), value.end(), url, params); |
| 28 } |
| 29 |
| 26 TEST(LinkHeaderTest, SplitEmpty) { | 30 TEST(LinkHeaderTest, SplitEmpty) { |
| 27 std::vector<std::string> values; | 31 std::vector<std::string> values; |
| 28 SplitLinkHeaderForTesting("", &values); | 32 SplitLinkHeaderForTesting("", &values); |
| 29 ASSERT_EQ(0u, values.size()); | 33 ASSERT_EQ(0u, values.size()); |
| 30 } | 34 } |
| 31 | 35 |
| 32 TEST(LinkHeaderTest, SplitSimple) { | 36 TEST(LinkHeaderTest, SplitSimple) { |
| 33 std::vector<std::string> values; | 37 std::vector<std::string> values; |
| 34 SplitLinkHeaderForTesting("hello", &values); | 38 SplitLinkHeaderForTesting("hello", &values); |
| 35 ASSERT_EQ(1u, values.size()); | 39 ASSERT_EQ(1u, values.size()); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 void PrintTo(const SimpleParseTestData& test, std::ostream* os) { | 90 void PrintTo(const SimpleParseTestData& test, std::ostream* os) { |
| 87 *os << ::testing::PrintToString(test.link); | 91 *os << ::testing::PrintToString(test.link); |
| 88 } | 92 } |
| 89 | 93 |
| 90 class SimpleParseTest : public ::testing::TestWithParam<SimpleParseTestData> {}; | 94 class SimpleParseTest : public ::testing::TestWithParam<SimpleParseTestData> {}; |
| 91 | 95 |
| 92 TEST_P(SimpleParseTest, Simple) { | 96 TEST_P(SimpleParseTest, Simple) { |
| 93 const SimpleParseTestData test = GetParam(); | 97 const SimpleParseTestData test = GetParam(); |
| 94 | 98 |
| 95 std::string url; | 99 std::string url; |
| 96 std::unordered_map<std::string, std::string> params; | 100 std::unordered_map<std::string, base::Optional<std::string>> params; |
| 97 EXPECT_EQ(test.valid, | 101 EXPECT_EQ(test.valid, |
| 98 ParseLinkHeaderValueForTesting(test.link, &url, ¶ms)); | 102 ParseLinkHeaderValueForTesting(test.link, &url, ¶ms)); |
| 99 if (test.valid) { | 103 if (test.valid) { |
| 100 EXPECT_EQ(test.url, url); | 104 EXPECT_EQ(test.url, url); |
| 101 EXPECT_EQ(test.rel, params["rel"]); | 105 EXPECT_EQ(test.rel, params["rel"].value_or("")); |
| 102 EXPECT_EQ(test.as, params["as"]); | 106 EXPECT_EQ(test.as, params["as"].value_or("")); |
| 103 } | 107 } |
| 104 } | 108 } |
| 105 | 109 |
| 106 // Test data mostly copied from blink::LinkHeaderTest. Expectations for some | 110 // Test data mostly copied from blink::LinkHeaderTest. Expectations for some |
| 107 // test cases are different though. Mostly because blink::LinkHeader is stricter | 111 // test cases are different though. Mostly because blink::LinkHeader is stricter |
| 108 // about validity while parsing (primarily things like mismatched quotes), and | 112 // about validity while parsing (primarily things like mismatched quotes), and |
| 109 // factors in knowledge about semantics of Link headers (parameters that are | 113 // factors in knowledge about semantics of Link headers (parameters that are |
| 110 // required to have a value if they occur, some parameters are auto-lower-cased, | 114 // required to have a value if they occur, some parameters are auto-lower-cased, |
| 111 // headers with an "anchor" parameter are rejected by base::LinkHeader). | 115 // headers with an "anchor" parameter are rejected by base::LinkHeader). |
| 112 // The code this tests purely parses without actually interpreting the data, as | 116 // The code this tests purely parses without actually interpreting the data, as |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 {"<simple.css>; rel=\"", true, "simple.css", "", ""}, | 215 {"<simple.css>; rel=\"", true, "simple.css", "", ""}, |
| 212 {"simple.css; rel=prefetch", false}, | 216 {"simple.css; rel=prefetch", false}, |
| 213 {"<simple.css>; rel=prefetch; rel=foobar", true, "simple.css", "prefetch", | 217 {"<simple.css>; rel=prefetch; rel=foobar", true, "simple.css", "prefetch", |
| 214 ""}, | 218 ""}, |
| 215 }; | 219 }; |
| 216 | 220 |
| 217 INSTANTIATE_TEST_CASE_P(LinkHeaderTest, | 221 INSTANTIATE_TEST_CASE_P(LinkHeaderTest, |
| 218 SimpleParseTest, | 222 SimpleParseTest, |
| 219 testing::ValuesIn(simple_parse_tests)); | 223 testing::ValuesIn(simple_parse_tests)); |
| 220 | 224 |
| 221 void SaveFoundRegistrationsCallback( | |
| 222 ServiceWorkerStatusCode expected_status, | |
| 223 bool* called, | |
| 224 std::vector<ServiceWorkerRegistrationInfo>* registrations, | |
| 225 ServiceWorkerStatusCode status, | |
| 226 const std::vector<ServiceWorkerRegistrationInfo>& result) { | |
| 227 EXPECT_EQ(expected_status, status); | |
| 228 *called = true; | |
| 229 *registrations = result; | |
| 230 } | |
| 231 | |
| 232 ServiceWorkerContextWrapper::GetRegistrationsInfosCallback | |
| 233 SaveFoundRegistrations( | |
| 234 ServiceWorkerStatusCode expected_status, | |
| 235 bool* called, | |
| 236 std::vector<ServiceWorkerRegistrationInfo>* registrations) { | |
| 237 *called = false; | |
| 238 return base::Bind(&SaveFoundRegistrationsCallback, expected_status, called, | |
| 239 registrations); | |
| 240 } | |
| 241 | |
| 242 class LinkHeaderServiceWorkerTest : public ::testing::Test { | |
| 243 public: | |
| 244 LinkHeaderServiceWorkerTest() | |
| 245 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), | |
| 246 resource_context_(&request_context_) { | |
| 247 base::CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 248 switches::kEnableExperimentalWebPlatformFeatures); | |
| 249 } | |
| 250 ~LinkHeaderServiceWorkerTest() override {} | |
| 251 | |
| 252 void SetUp() override { | |
| 253 helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); | |
| 254 } | |
| 255 | |
| 256 void TearDown() override { helper_.reset(); } | |
| 257 | |
| 258 ServiceWorkerContextWrapper* context_wrapper() { | |
| 259 return helper_->context_wrapper(); | |
| 260 } | |
| 261 | |
| 262 void ProcessLinkHeader(const GURL& request_url, | |
| 263 const std::string& link_header) { | |
| 264 scoped_ptr<net::URLRequest> request = request_context_.CreateRequest( | |
| 265 request_url, net::DEFAULT_PRIORITY, &request_delegate_); | |
| 266 ResourceRequestInfo::AllocateForTesting( | |
| 267 request.get(), RESOURCE_TYPE_SCRIPT, &resource_context_, | |
| 268 -1 /* render_process_id */, -1 /* render_view_id */, | |
| 269 -1 /* render_frame_id */, false /* is_main_frame */, | |
| 270 false /* parent_is_main_frame */, true /* allow_download */, | |
| 271 true /* is_async */, false /* is_using_lofi */); | |
| 272 | |
| 273 ProcessLinkHeaderForRequest(request.get(), link_header, context_wrapper()); | |
| 274 base::RunLoop().RunUntilIdle(); | |
| 275 } | |
| 276 | |
| 277 std::vector<ServiceWorkerRegistrationInfo> GetRegistrations() { | |
| 278 bool called; | |
| 279 std::vector<ServiceWorkerRegistrationInfo> registrations; | |
| 280 context_wrapper()->GetAllRegistrations( | |
| 281 SaveFoundRegistrations(SERVICE_WORKER_OK, &called, ®istrations)); | |
| 282 base::RunLoop().RunUntilIdle(); | |
| 283 EXPECT_TRUE(called); | |
| 284 return registrations; | |
| 285 } | |
| 286 | |
| 287 private: | |
| 288 TestBrowserThreadBundle thread_bundle_; | |
| 289 scoped_ptr<EmbeddedWorkerTestHelper> helper_; | |
| 290 net::TestURLRequestContext request_context_; | |
| 291 net::TestDelegate request_delegate_; | |
| 292 MockResourceContext resource_context_; | |
| 293 }; | |
| 294 | |
| 295 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_Basic) { | |
| 296 ProcessLinkHeader(GURL("https://example.com/foo/bar/"), | |
| 297 "<../foo.js>; rel=serviceworker"); | |
| 298 | |
| 299 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 300 ASSERT_EQ(1u, registrations.size()); | |
| 301 EXPECT_EQ(GURL("https://example.com/foo/"), registrations[0].pattern); | |
| 302 EXPECT_EQ(GURL("https://example.com/foo/foo.js"), | |
| 303 registrations[0].active_version.script_url); | |
| 304 } | |
| 305 | |
| 306 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeWithFragment) { | |
| 307 ProcessLinkHeader(GURL("https://example.com/foo/bar/"), | |
| 308 "<../bar.js>; rel=serviceworker; scope=\"scope#ref\""); | |
| 309 | |
| 310 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 311 ASSERT_EQ(1u, registrations.size()); | |
| 312 EXPECT_EQ(GURL("https://example.com/foo/bar/scope"), | |
| 313 registrations[0].pattern); | |
| 314 EXPECT_EQ(GURL("https://example.com/foo/bar.js"), | |
| 315 registrations[0].active_version.script_url); | |
| 316 } | |
| 317 | |
| 318 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeAbsoluteUrl) { | |
| 319 ProcessLinkHeader(GURL("https://example.com/foo/bar/"), | |
| 320 "<bar.js>; rel=serviceworker; " | |
| 321 "scope=\"https://example.com:443/foo/bar/scope\""); | |
| 322 | |
| 323 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 324 ASSERT_EQ(1u, registrations.size()); | |
| 325 EXPECT_EQ(GURL("https://example.com/foo/bar/scope"), | |
| 326 registrations[0].pattern); | |
| 327 EXPECT_EQ(GURL("https://example.com/foo/bar/bar.js"), | |
| 328 registrations[0].active_version.script_url); | |
| 329 } | |
| 330 | |
| 331 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeDifferentOrigin) { | |
| 332 ProcessLinkHeader( | |
| 333 GURL("https://example.com/foobar/"), | |
| 334 "<bar.js>; rel=serviceworker; scope=\"https://google.com/scope\""); | |
| 335 | |
| 336 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 337 ASSERT_EQ(0u, registrations.size()); | |
| 338 } | |
| 339 | |
| 340 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScopeUrlEncodedSlash) { | |
| 341 ProcessLinkHeader(GURL("https://example.com/foobar/"), | |
| 342 "<bar.js>; rel=serviceworker; scope=\"./foo%2Fbar\""); | |
| 343 | |
| 344 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 345 ASSERT_EQ(0u, registrations.size()); | |
| 346 } | |
| 347 | |
| 348 TEST_F(LinkHeaderServiceWorkerTest, | |
| 349 InstallServiceWorker_ScriptUrlEncodedSlash) { | |
| 350 ProcessLinkHeader(GURL("https://example.com/foobar/"), | |
| 351 "<foo%2Fbar.js>; rel=serviceworker"); | |
| 352 | |
| 353 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 354 ASSERT_EQ(0u, registrations.size()); | |
| 355 } | |
| 356 | |
| 357 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_ScriptAbsoluteUrl) { | |
| 358 ProcessLinkHeader( | |
| 359 GURL("https://example.com/foobar/"), | |
| 360 "<https://example.com/bar.js>; rel=serviceworker; scope=foo"); | |
| 361 | |
| 362 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 363 ASSERT_EQ(1u, registrations.size()); | |
| 364 EXPECT_EQ(GURL("https://example.com/foobar/foo"), registrations[0].pattern); | |
| 365 EXPECT_EQ(GURL("https://example.com/bar.js"), | |
| 366 registrations[0].active_version.script_url); | |
| 367 } | |
| 368 | |
| 369 TEST_F(LinkHeaderServiceWorkerTest, | |
| 370 InstallServiceWorker_ScriptDifferentOrigin) { | |
| 371 ProcessLinkHeader( | |
| 372 GURL("https://example.com/foobar/"), | |
| 373 "<https://google.com/bar.js>; rel=serviceworker; scope=foo"); | |
| 374 | |
| 375 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 376 ASSERT_EQ(0u, registrations.size()); | |
| 377 } | |
| 378 | |
| 379 TEST_F(LinkHeaderServiceWorkerTest, InstallServiceWorker_MultipleWorkers) { | |
| 380 ProcessLinkHeader(GURL("https://example.com/foobar/"), | |
| 381 "<bar.js>; rel=serviceworker; scope=foo, <baz.js>; " | |
| 382 "rel=serviceworker; scope=scope"); | |
| 383 | |
| 384 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 385 ASSERT_EQ(2u, registrations.size()); | |
| 386 EXPECT_EQ(GURL("https://example.com/foobar/foo"), registrations[0].pattern); | |
| 387 EXPECT_EQ(GURL("https://example.com/foobar/bar.js"), | |
| 388 registrations[0].active_version.script_url); | |
| 389 EXPECT_EQ(GURL("https://example.com/foobar/scope"), registrations[1].pattern); | |
| 390 EXPECT_EQ(GURL("https://example.com/foobar/baz.js"), | |
| 391 registrations[1].active_version.script_url); | |
| 392 } | |
| 393 | |
| 394 TEST_F(LinkHeaderServiceWorkerTest, | |
| 395 InstallServiceWorker_ValidAndInvalidValues) { | |
| 396 ProcessLinkHeader( | |
| 397 GURL("https://example.com/foobar/"), | |
| 398 "<https://google.com/bar.js>; rel=serviceworker; scope=foo, <baz.js>; " | |
| 399 "rel=serviceworker; scope=scope"); | |
| 400 | |
| 401 std::vector<ServiceWorkerRegistrationInfo> registrations = GetRegistrations(); | |
| 402 ASSERT_EQ(1u, registrations.size()); | |
| 403 EXPECT_EQ(GURL("https://example.com/foobar/scope"), registrations[0].pattern); | |
| 404 EXPECT_EQ(GURL("https://example.com/foobar/baz.js"), | |
| 405 registrations[0].active_version.script_url); | |
| 406 } | |
| 407 | |
| 408 } // namespace | 225 } // namespace |
| 409 | 226 |
| 410 } // namespace content | 227 } // namespace link_header_util |
| OLD | NEW |