1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 <stack> 6 #include <string> 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/callback.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/synchronization/waitable_event.h" 14 #include "base/threading/thread.h" 15 #include "content/browser/appcache/appcache.h" 16 #include "content/browser/appcache/appcache_backend_impl.h" 17 #include "content/browser/appcache/appcache_request_handler.h" 18 #include "content/browser/appcache/appcache_url_request_job.h" 19 #include "content/browser/appcache/mock_appcache_policy.h" 20 #include "content/browser/appcache/mock_appcache_service.h" 21 #include "net/base/net_errors.h" 22 #include "net/base/request_priority.h" 23 #include "net/http/http_response_headers.h" 24 #include "net/url_request/url_request.h" 25 #include "net/url_request/url_request_context.h" 26 #include "net/url_request/url_request_error_job.h" 27 #include "net/url_request/url_request_job_factory.h" 28 #include "testing/gtest/include/gtest/gtest.h" 29 30 namespace content { 31 32 static const int kMockProcessId = 1; 33 34 class AppCacheRequestHandlerTest : public testing::Test { 35 public: 36 class MockFrontend : public AppCacheFrontend { 37 public: 38 virtual void OnCacheSelected( 39 int host_id, const AppCacheInfo& info) OVERRIDE {} 40 41 virtual void OnStatusChanged(const std::vector<int>& host_ids, 42 AppCacheStatus status) OVERRIDE {} 43 44 virtual void OnEventRaised(const std::vector<int>& host_ids, 45 AppCacheEventID event_id) OVERRIDE {} 46 47 virtual void OnErrorEventRaised( 48 const std::vector<int>& host_ids, 49 const AppCacheErrorDetails& details) OVERRIDE {} 50 51 virtual void OnProgressEventRaised(const std::vector<int>& host_ids, 52 const GURL& url, 53 int num_total, 54 int num_complete) OVERRIDE { 55 } 56 57 virtual void OnLogMessage(int host_id, 58 AppCacheLogLevel log_level, 59 const std::string& message) OVERRIDE { 60 } 61 62 virtual void OnContentBlocked(int host_id, 63 const GURL& manifest_url) OVERRIDE {} 64 }; 65 66 // Helper callback to run a test on our io_thread. The io_thread is spun up 67 // once and reused for all tests. 68 template <class Method> 69 void MethodWrapper(Method method) { 70 SetUpTest(); 71 (this->*method)(); 72 } 73 74 // Subclasses to simulate particular responses so test cases can 75 // exercise fallback code paths. 76 77 class MockURLRequestDelegate : public net::URLRequest::Delegate { 78 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {} 79 virtual void OnReadCompleted(net::URLRequest* request, 80 int bytes_read) OVERRIDE { 81 } 82 }; 83 84 class MockURLRequestJob : public net::URLRequestJob { 85 public: 86 MockURLRequestJob(net::URLRequest* request, 87 net::NetworkDelegate* network_delegate, 88 int response_code) 89 : net::URLRequestJob(request, network_delegate), 90 response_code_(response_code), 91 has_response_info_(false) {} 92 MockURLRequestJob(net::URLRequest* request, 93 net::NetworkDelegate* network_delegate, 94 const net::HttpResponseInfo& info) 95 : net::URLRequestJob(request, network_delegate), 96 response_code_(info.headers->response_code()), 97 has_response_info_(true), 98 response_info_(info) {} 99 100 protected: 101 virtual ~MockURLRequestJob() {} 102 virtual void Start() OVERRIDE { 103 NotifyHeadersComplete(); 104 } 105 virtual int GetResponseCode() const OVERRIDE { 106 return response_code_; 107 } 108 virtual void GetResponseInfo( 109 net::HttpResponseInfo* info) OVERRIDE { 110 if (!has_response_info_) 111 return; 112 *info = response_info_; 113 } 114 115 private: 116 int response_code_; 117 bool has_response_info_; 118 net::HttpResponseInfo response_info_; 119 }; 120 121 class MockURLRequestJobFactory : public net::URLRequestJobFactory { 122 public: 123 MockURLRequestJobFactory() : job_(NULL) { 124 } 125 126 virtual ~MockURLRequestJobFactory() { 127 DCHECK(!job_); 128 } 129 130 void SetJob(net::URLRequestJob* job) { 131 job_ = job; 132 } 133 134 virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler( 135 const std::string& scheme, 136 net::URLRequest* request, 137 net::NetworkDelegate* network_delegate) const OVERRIDE { 138 if (job_) { 139 net::URLRequestJob* temp = job_; 140 job_ = NULL; 141 return temp; 142 } else { 143 // Some of these tests trigger UpdateJobs which start URLRequests. 144 // We short circuit those be returning error jobs. 145 return new net::URLRequestErrorJob(request, 146 network_delegate, 147 net::ERR_INTERNET_DISCONNECTED); 148 } 149 } 150 151 virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE { 152 return scheme == "http"; 153 }; 154 155 virtual bool IsHandledURL(const GURL& url) const OVERRIDE { 156 return url.SchemeIs("http"); 157 } 158 159 virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE { 160 return false; 161 } 162 163 private: 164 mutable net::URLRequestJob* job_; 165 }; 166 167 static void SetUpTestCase() { 168 io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread")); 169 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); 170 io_thread_->StartWithOptions(options); 171 } 172 173 static void TearDownTestCase() { 174 io_thread_.reset(NULL); 175 } 176 177 // Test harness -------------------------------------------------- 178 179 AppCacheRequestHandlerTest() : host_(NULL) {} 180 181 template <class Method> 182 void RunTestOnIOThread(Method method) { 183 test_finished_event_ .reset(new base::WaitableEvent(false, false)); 184 io_thread_->message_loop()->PostTask( 185 FROM_HERE, 186 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>, 187 base::Unretained(this), method)); 188 test_finished_event_->Wait(); 189 } 190 191 void SetUpTest() { 192 DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 193 mock_service_.reset(new MockAppCacheService); 194 mock_service_->set_request_context(&empty_context_); 195 mock_policy_.reset(new MockAppCachePolicy); 196 mock_service_->set_appcache_policy(mock_policy_.get()); 197 mock_frontend_.reset(new MockFrontend); 198 backend_impl_.reset(new AppCacheBackendImpl); 199 backend_impl_->Initialize(mock_service_.get(), mock_frontend_.get(), 200 kMockProcessId); 201 const int kHostId = 1; 202 backend_impl_->RegisterHost(kHostId); 203 host_ = backend_impl_->GetHost(kHostId); 204 job_factory_.reset(new MockURLRequestJobFactory()); 205 empty_context_.set_job_factory(job_factory_.get()); 206 } 207 208 void TearDownTest() { 209 DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 210 job_ = NULL; 211 handler_.reset(); 212 request_.reset(); 213 backend_impl_.reset(); 214 mock_frontend_.reset(); 215 mock_service_.reset(); 216 mock_policy_.reset(); 217 job_factory_.reset(); 218 host_ = NULL; 219 } 220 221 void TestFinished() { 222 // We unwind the stack prior to finishing up to let stack 223 // based objects get deleted. 224 DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 225 base::MessageLoop::current()->PostTask( 226 FROM_HERE, 227 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound, 228 base::Unretained(this))); 229 } 230 231 void TestFinishedUnwound() { 232 TearDownTest(); 233 test_finished_event_->Signal(); 234 } 235 236 void PushNextTask(const base::Closure& task) { 237 task_stack_.push(task); 238 } 239 240 void ScheduleNextTask() { 241 DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 242 if (task_stack_.empty()) { 243 TestFinished(); 244 return; 245 } 246 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top()); 247 task_stack_.pop(); 248 } 249 250 // MainResource_Miss -------------------------------------------------- 251 252 void MainResource_Miss() { 253 PushNextTask( 254 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss, 255 base::Unretained(this))); 256 257 request_ = empty_context_.CreateRequest( 258 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 259 handler_.reset(host_->CreateRequestHandler(request_.get(), 260 RESOURCE_TYPE_MAIN_FRAME)); 261 EXPECT_TRUE(handler_.get()); 262 263 job_ = handler_->MaybeLoadResource(request_.get(), 264 request_->context()->network_delegate()); 265 EXPECT_TRUE(job_.get()); 266 EXPECT_TRUE(job_->is_waiting()); 267 268 // We have to wait for completion of storage->FindResponseForMainRequest. 269 ScheduleNextTask(); 270 } 271 272 void Verify_MainResource_Miss() { 273 EXPECT_FALSE(job_->is_waiting()); 274 EXPECT_TRUE(job_->is_delivering_network_response()); 275 276 int64 cache_id = kAppCacheNoCacheId; 277 GURL manifest_url; 278 handler_->GetExtraResponseInfo(&cache_id, &manifest_url); 279 EXPECT_EQ(kAppCacheNoCacheId, cache_id); 280 EXPECT_EQ(GURL(), manifest_url); 281 EXPECT_EQ(0, handler_->found_group_id_); 282 283 AppCacheURLRequestJob* fallback_job; 284 fallback_job = handler_->MaybeLoadFallbackForRedirect( 285 request_.get(), 286 request_->context()->network_delegate(), 287 GURL("http://blah/redirect")); 288 EXPECT_FALSE(fallback_job); 289 fallback_job = handler_->MaybeLoadFallbackForResponse( 290 request_.get(), request_->context()->network_delegate()); 291 EXPECT_FALSE(fallback_job); 292 293 EXPECT_TRUE(host_->preferred_manifest_url().is_empty()); 294 295 TestFinished(); 296 } 297 298 // MainResource_Hit -------------------------------------------------- 299 300 void MainResource_Hit() { 301 PushNextTask( 302 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit, 303 base::Unretained(this))); 304 305 request_ = empty_context_.CreateRequest( 306 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 307 handler_.reset(host_->CreateRequestHandler(request_.get(), 308 RESOURCE_TYPE_MAIN_FRAME)); 309 EXPECT_TRUE(handler_.get()); 310 311 mock_storage()->SimulateFindMainResource( 312 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), 313 GURL(), AppCacheEntry(), 314 1, 2, GURL("http://blah/manifest/")); 315 316 job_ = handler_->MaybeLoadResource(request_.get(), 317 request_->context()->network_delegate()); 318 EXPECT_TRUE(job_.get()); 319 EXPECT_TRUE(job_->is_waiting()); 320 321 // We have to wait for completion of storage->FindResponseForMainRequest. 322 ScheduleNextTask(); 323 } 324 325 void Verify_MainResource_Hit() { 326 EXPECT_FALSE(job_->is_waiting()); 327 EXPECT_TRUE(job_->is_delivering_appcache_response()); 328 329 int64 cache_id = kAppCacheNoCacheId; 330 GURL manifest_url; 331 handler_->GetExtraResponseInfo(&cache_id, &manifest_url); 332 EXPECT_EQ(1, cache_id); 333 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url); 334 EXPECT_EQ(2, handler_->found_group_id_); 335 336 AppCacheURLRequestJob* fallback_job; 337 fallback_job = handler_->MaybeLoadFallbackForResponse( 338 request_.get(), request_->context()->network_delegate()); 339 EXPECT_FALSE(fallback_job); 340 341 EXPECT_EQ(GURL("http://blah/manifest/"), 342 host_->preferred_manifest_url()); 343 344 TestFinished(); 345 } 346 347 // MainResource_Fallback -------------------------------------------------- 348 349 void MainResource_Fallback() { 350 PushNextTask( 351 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback, 352 base::Unretained(this))); 353 354 request_ = empty_context_.CreateRequest( 355 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 356 handler_.reset(host_->CreateRequestHandler(request_.get(), 357 RESOURCE_TYPE_MAIN_FRAME)); 358 EXPECT_TRUE(handler_.get()); 359 360 mock_storage()->SimulateFindMainResource( 361 AppCacheEntry(), 362 GURL("http://blah/fallbackurl"), 363 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), 364 1, 2, GURL("http://blah/manifest/")); 365 366 job_ = handler_->MaybeLoadResource(request_.get(), 367 request_->context()->network_delegate()); 368 EXPECT_TRUE(job_.get()); 369 EXPECT_TRUE(job_->is_waiting()); 370 371 // We have to wait for completion of storage->FindResponseForMainRequest. 372 ScheduleNextTask(); 373 } 374 375 void SimulateResponseCode(int response_code) { 376 job_factory_->SetJob( 377 new MockURLRequestJob( 378 request_.get(), 379 request_->context()->network_delegate(), 380 response_code)); 381 request_->Start(); 382 // All our simulation needs to satisfy are the following two DCHECKs 383 DCHECK(request_->status().is_success()); 384 DCHECK_EQ(response_code, request_->GetResponseCode()); 385 } 386 387 void SimulateResponseInfo(const net::HttpResponseInfo& info) { 388 job_factory_->SetJob( 389 new MockURLRequestJob( 390 request_.get(), 391 request_->context()->network_delegate(), info)); 392 request_->Start(); 393 } 394 395 void Verify_MainResource_Fallback() { 396 EXPECT_FALSE(job_->is_waiting()); 397 EXPECT_TRUE(job_->is_delivering_network_response()); 398 399 // When the request is restarted, the existing job is dropped so a 400 // real network job gets created. We expect NULL here which will cause 401 // the net library to create a real job. 402 job_ = handler_->MaybeLoadResource(request_.get(), 403 request_->context()->network_delegate()); 404 EXPECT_FALSE(job_.get()); 405 406 // Simulate an http error of the real network job. 407 SimulateResponseCode(500); 408 409 job_ = handler_->MaybeLoadFallbackForResponse( 410 request_.get(), request_->context()->network_delegate()); 411 EXPECT_TRUE(job_.get()); 412 EXPECT_TRUE(job_->is_delivering_appcache_response()); 413 414 int64 cache_id = kAppCacheNoCacheId; 415 GURL manifest_url; 416 handler_->GetExtraResponseInfo(&cache_id, &manifest_url); 417 EXPECT_EQ(1, cache_id); 418 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url); 419 EXPECT_TRUE(host_->main_resource_was_namespace_entry_); 420 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->namespace_entry_url_); 421 422 EXPECT_EQ(GURL("http://blah/manifest/"), 423 host_->preferred_manifest_url()); 424 425 TestFinished(); 426 } 427 428 // MainResource_FallbackOverride -------------------------------------------- 429 430 void MainResource_FallbackOverride() { 431 PushNextTask(base::Bind( 432 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride, 433 base::Unretained(this))); 434 435 request_ = empty_context_.CreateRequest( 436 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY, 437 &delegate_, NULL); 438 handler_.reset(host_->CreateRequestHandler(request_.get(), 439 RESOURCE_TYPE_MAIN_FRAME)); 440 EXPECT_TRUE(handler_.get()); 441 442 mock_storage()->SimulateFindMainResource( 443 AppCacheEntry(), 444 GURL("http://blah/fallbackurl"), 445 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), 446 1, 2, GURL("http://blah/manifest/")); 447 448 job_ = handler_->MaybeLoadResource(request_.get(), 449 request_->context()->network_delegate()); 450 EXPECT_TRUE(job_.get()); 451 EXPECT_TRUE(job_->is_waiting()); 452 453 // We have to wait for completion of storage->FindResponseForMainRequest. 454 ScheduleNextTask(); 455 } 456 457 void Verify_MainResource_FallbackOverride() { 458 EXPECT_FALSE(job_->is_waiting()); 459 EXPECT_TRUE(job_->is_delivering_network_response()); 460 461 // When the request is restarted, the existing job is dropped so a 462 // real network job gets created. We expect NULL here which will cause 463 // the net library to create a real job. 464 job_ = handler_->MaybeLoadResource(request_.get(), 465 request_->context()->network_delegate()); 466 EXPECT_FALSE(job_.get()); 467 468 // Simulate an http error of the real network job, but with custom 469 // headers that override the fallback behavior. 470 const char kOverrideHeaders[] = 471 "HTTP/1.1 404 BOO HOO\0" 472 "x-chromium-appcache-fallback-override: disallow-fallback\0" 473 "\0"; 474 net::HttpResponseInfo info; 475 info.headers = new net::HttpResponseHeaders( 476 std::string(kOverrideHeaders, arraysize(kOverrideHeaders))); 477 SimulateResponseInfo(info); 478 479 job_ = handler_->MaybeLoadFallbackForResponse( 480 request_.get(), request_->context()->network_delegate()); 481 EXPECT_FALSE(job_.get()); 482 483 TestFinished(); 484 } 485 486 // SubResource_Miss_WithNoCacheSelected ---------------------------------- 487 488 void SubResource_Miss_WithNoCacheSelected() { 489 request_ = empty_context_.CreateRequest( 490 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 491 handler_.reset(host_->CreateRequestHandler(request_.get(), 492 RESOURCE_TYPE_SUB_RESOURCE)); 493 494 // We avoid creating handler when possible, sub-resource requests are not 495 // subject to retrieval from an appcache when there's no associated cache. 496 EXPECT_FALSE(handler_.get()); 497 498 TestFinished(); 499 } 500 501 // SubResource_Miss_WithCacheSelected ---------------------------------- 502 503 void SubResource_Miss_WithCacheSelected() { 504 // A sub-resource load where the resource is not in an appcache, or 505 // in a network or fallback namespace, should result in a failed request. 506 host_->AssociateCompleteCache(MakeNewCache()); 507 508 request_ = empty_context_.CreateRequest( 509 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 510 handler_.reset(host_->CreateRequestHandler(request_.get(), 511 RESOURCE_TYPE_SUB_RESOURCE)); 512 EXPECT_TRUE(handler_.get()); 513 514 job_ = handler_->MaybeLoadResource(request_.get(), 515 request_->context()->network_delegate()); 516 EXPECT_TRUE(job_.get()); 517 EXPECT_TRUE(job_->is_delivering_error_response()); 518 519 AppCacheURLRequestJob* fallback_job; 520 fallback_job = handler_->MaybeLoadFallbackForRedirect( 521 request_.get(), 522 request_->context()->network_delegate(), 523 GURL("http://blah/redirect")); 524 EXPECT_FALSE(fallback_job); 525 fallback_job = handler_->MaybeLoadFallbackForResponse( 526 request_.get(), request_->context()->network_delegate()); 527 EXPECT_FALSE(fallback_job); 528 529 TestFinished(); 530 } 531 532 // SubResource_Miss_WithWaitForCacheSelection ----------------------------- 533 534 void SubResource_Miss_WithWaitForCacheSelection() { 535 // Precondition, the host is waiting on cache selection. 536 scoped_refptr<AppCache> cache(MakeNewCache()); 537 host_->pending_selected_cache_id_ = cache->cache_id(); 538 host_->set_preferred_manifest_url(cache->owning_group()->manifest_url()); 539 540 request_ = empty_context_.CreateRequest( 541 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 542 handler_.reset(host_->CreateRequestHandler(request_.get(), 543 RESOURCE_TYPE_SUB_RESOURCE)); 544 EXPECT_TRUE(handler_.get()); 545 job_ = handler_->MaybeLoadResource(request_.get(), 546 request_->context()->network_delegate()); 547 EXPECT_TRUE(job_.get()); 548 EXPECT_TRUE(job_->is_waiting()); 549 550 host_->FinishCacheSelection(cache.get(), NULL); 551 EXPECT_FALSE(job_->is_waiting()); 552 EXPECT_TRUE(job_->is_delivering_error_response()); 553 554 AppCacheURLRequestJob* fallback_job; 555 fallback_job = handler_->MaybeLoadFallbackForRedirect( 556 request_.get(), 557 request_->context()->network_delegate(), 558 GURL("http://blah/redirect")); 559 EXPECT_FALSE(fallback_job); 560 fallback_job = handler_->MaybeLoadFallbackForResponse( 561 request_.get(), request_->context()->network_delegate()); 562 EXPECT_FALSE(fallback_job); 563 564 TestFinished(); 565 } 566 567 // SubResource_Hit ----------------------------- 568 569 void SubResource_Hit() { 570 host_->AssociateCompleteCache(MakeNewCache()); 571 572 mock_storage()->SimulateFindSubResource( 573 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false); 574 575 request_ = empty_context_.CreateRequest( 576 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 577 handler_.reset(host_->CreateRequestHandler(request_.get(), 578 RESOURCE_TYPE_SUB_RESOURCE)); 579 EXPECT_TRUE(handler_.get()); 580 job_ = handler_->MaybeLoadResource(request_.get(), 581 request_->context()->network_delegate()); 582 EXPECT_TRUE(job_.get()); 583 EXPECT_TRUE(job_->is_delivering_appcache_response()); 584 585 AppCacheURLRequestJob* fallback_job; 586 fallback_job = handler_->MaybeLoadFallbackForRedirect( 587 request_.get(), 588 request_->context()->network_delegate(), 589 GURL("http://blah/redirect")); 590 EXPECT_FALSE(fallback_job); 591 fallback_job = handler_->MaybeLoadFallbackForResponse( 592 request_.get(), request_->context()->network_delegate()); 593 EXPECT_FALSE(fallback_job); 594 595 TestFinished(); 596 } 597 598 // SubResource_RedirectFallback ----------------------------- 599 600 void SubResource_RedirectFallback() { 601 // Redirects to resources in the a different origin are subject to 602 // fallback namespaces. 603 host_->AssociateCompleteCache(MakeNewCache()); 604 605 mock_storage()->SimulateFindSubResource( 606 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false); 607 608 request_ = empty_context_.CreateRequest( 609 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 610 handler_.reset(host_->CreateRequestHandler(request_.get(), 611 RESOURCE_TYPE_SUB_RESOURCE)); 612 EXPECT_TRUE(handler_.get()); 613 job_ = handler_->MaybeLoadResource(request_.get(), 614 request_->context()->network_delegate()); 615 EXPECT_FALSE(job_.get()); 616 617 job_ = handler_->MaybeLoadFallbackForRedirect( 618 request_.get(), 619 request_->context()->network_delegate(), 620 GURL("http://not_blah/redirect")); 621 EXPECT_TRUE(job_.get()); 622 EXPECT_TRUE(job_->is_delivering_appcache_response()); 623 624 AppCacheURLRequestJob* fallback_job; 625 fallback_job = handler_->MaybeLoadFallbackForResponse( 626 request_.get(), request_->context()->network_delegate()); 627 EXPECT_FALSE(fallback_job); 628 629 TestFinished(); 630 } 631 632 // SubResource_NoRedirectFallback ----------------------------- 633 634 void SubResource_NoRedirectFallback() { 635 // Redirects to resources in the same-origin are not subject to 636 // fallback namespaces. 637 host_->AssociateCompleteCache(MakeNewCache()); 638 639 mock_storage()->SimulateFindSubResource( 640 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false); 641 642 request_ = empty_context_.CreateRequest( 643 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 644 handler_.reset(host_->CreateRequestHandler(request_.get(), 645 RESOURCE_TYPE_SUB_RESOURCE)); 646 EXPECT_TRUE(handler_.get()); 647 job_ = handler_->MaybeLoadResource(request_.get(), 648 request_->context()->network_delegate()); 649 EXPECT_FALSE(job_.get()); 650 651 AppCacheURLRequestJob* fallback_job; 652 fallback_job = handler_->MaybeLoadFallbackForRedirect( 653 request_.get(), 654 request_->context()->network_delegate(), 655 GURL("http://blah/redirect")); 656 EXPECT_FALSE(fallback_job); 657 658 SimulateResponseCode(200); 659 fallback_job = handler_->MaybeLoadFallbackForResponse( 660 request_.get(), request_->context()->network_delegate()); 661 EXPECT_FALSE(fallback_job); 662 663 TestFinished(); 664 } 665 666 // SubResource_Network ----------------------------- 667 668 void SubResource_Network() { 669 // A sub-resource load where the resource is in a network namespace, 670 // should result in the system using a 'real' job to do the network 671 // retrieval. 672 host_->AssociateCompleteCache(MakeNewCache()); 673 674 mock_storage()->SimulateFindSubResource( 675 AppCacheEntry(), AppCacheEntry(), true); 676 677 request_ = empty_context_.CreateRequest( 678 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 679 handler_.reset(host_->CreateRequestHandler(request_.get(), 680 RESOURCE_TYPE_SUB_RESOURCE)); 681 EXPECT_TRUE(handler_.get()); 682 job_ = handler_->MaybeLoadResource(request_.get(), 683 request_->context()->network_delegate()); 684 EXPECT_FALSE(job_.get()); 685 686 AppCacheURLRequestJob* fallback_job; 687 fallback_job = handler_->MaybeLoadFallbackForRedirect( 688 request_.get(), 689 request_->context()->network_delegate(), 690 GURL("http://blah/redirect")); 691 EXPECT_FALSE(fallback_job); 692 fallback_job = handler_->MaybeLoadFallbackForResponse( 693 request_.get(), request_->context()->network_delegate()); 694 EXPECT_FALSE(fallback_job); 695 696 TestFinished(); 697 } 698 699 // DestroyedHost ----------------------------- 700 701 void DestroyedHost() { 702 host_->AssociateCompleteCache(MakeNewCache()); 703 704 mock_storage()->SimulateFindSubResource( 705 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false); 706 707 request_ = empty_context_.CreateRequest( 708 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 709 handler_.reset(host_->CreateRequestHandler(request_.get(), 710 RESOURCE_TYPE_SUB_RESOURCE)); 711 EXPECT_TRUE(handler_.get()); 712 713 backend_impl_->UnregisterHost(1); 714 host_ = NULL; 715 716 EXPECT_FALSE(handler_->MaybeLoadResource( 717 request_.get(), request_->context()->network_delegate())); 718 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect( 719 request_.get(), 720 request_->context()->network_delegate(), 721 GURL("http://blah/redirect"))); 722 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse( 723 request_.get(), request_->context()->network_delegate())); 724 725 TestFinished(); 726 } 727 728 // DestroyedHostWithWaitingJob ----------------------------- 729 730 void DestroyedHostWithWaitingJob() { 731 // Precondition, the host is waiting on cache selection. 732 host_->pending_selected_cache_id_ = 1; 733 734 request_ = empty_context_.CreateRequest( 735 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 736 handler_.reset(host_->CreateRequestHandler(request_.get(), 737 RESOURCE_TYPE_SUB_RESOURCE)); 738 EXPECT_TRUE(handler_.get()); 739 740 job_ = handler_->MaybeLoadResource(request_.get(), 741 request_->context()->network_delegate()); 742 EXPECT_TRUE(job_.get()); 743 EXPECT_TRUE(job_->is_waiting()); 744 745 backend_impl_->UnregisterHost(1); 746 host_ = NULL; 747 EXPECT_TRUE(job_->has_been_killed()); 748 749 EXPECT_FALSE(handler_->MaybeLoadResource( 750 request_.get(), request_->context()->network_delegate())); 751 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect( 752 request_.get(), 753 request_->context()->network_delegate(), 754 GURL("http://blah/redirect"))); 755 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse( 756 request_.get(), request_->context()->network_delegate())); 757 758 TestFinished(); 759 } 760 761 // UnsupportedScheme ----------------------------- 762 763 void UnsupportedScheme() { 764 // Precondition, the host is waiting on cache selection. 765 host_->pending_selected_cache_id_ = 1; 766 767 request_ = empty_context_.CreateRequest( 768 GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 769 handler_.reset(host_->CreateRequestHandler(request_.get(), 770 RESOURCE_TYPE_SUB_RESOURCE)); 771 EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably) 772 773 EXPECT_FALSE(handler_->MaybeLoadResource( 774 request_.get(), request_->context()->network_delegate())); 775 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect( 776 request_.get(), 777 request_->context()->network_delegate(), 778 GURL("ftp://blah/redirect"))); 779 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse( 780 request_.get(), request_->context()->network_delegate())); 781 782 TestFinished(); 783 } 784 785 // CanceledRequest ----------------------------- 786 787 void CanceledRequest() { 788 request_ = empty_context_.CreateRequest( 789 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 790 handler_.reset(host_->CreateRequestHandler(request_.get(), 791 RESOURCE_TYPE_MAIN_FRAME)); 792 EXPECT_TRUE(handler_.get()); 793 794 job_ = handler_->MaybeLoadResource(request_.get(), 795 request_->context()->network_delegate()); 796 EXPECT_TRUE(job_.get()); 797 EXPECT_TRUE(job_->is_waiting()); 798 EXPECT_FALSE(job_->has_been_started()); 799 800 job_factory_->SetJob(job_.get()); 801 request_->Start(); 802 EXPECT_TRUE(job_->has_been_started()); 803 804 request_->Cancel(); 805 EXPECT_TRUE(job_->has_been_killed()); 806 807 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse( 808 request_.get(), request_->context()->network_delegate())); 809 810 TestFinished(); 811 } 812 813 // WorkerRequest ----------------------------- 814 815 void WorkerRequest() { 816 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType( 817 RESOURCE_TYPE_MAIN_FRAME)); 818 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType( 819 RESOURCE_TYPE_SUB_FRAME)); 820 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType( 821 RESOURCE_TYPE_SHARED_WORKER)); 822 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType( 823 RESOURCE_TYPE_WORKER)); 824 825 request_ = empty_context_.CreateRequest( 826 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 827 828 const int kParentHostId = host_->host_id(); 829 const int kWorkerHostId = 2; 830 const int kAbandonedWorkerHostId = 3; 831 const int kNonExsitingHostId = 700; 832 833 backend_impl_->RegisterHost(kWorkerHostId); 834 AppCacheHost* worker_host = backend_impl_->GetHost(kWorkerHostId); 835 worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId); 836 handler_.reset(worker_host->CreateRequestHandler( 837 request_.get(), RESOURCE_TYPE_SHARED_WORKER)); 838 EXPECT_TRUE(handler_.get()); 839 // Verify that the handler is associated with the parent host. 840 EXPECT_EQ(host_, handler_->host_); 841 842 // Create a new worker host, but associate it with a parent host that 843 // does not exists to simulate the host having been torn down. 844 backend_impl_->UnregisterHost(kWorkerHostId); 845 backend_impl_->RegisterHost(kAbandonedWorkerHostId); 846 worker_host = backend_impl_->GetHost(kAbandonedWorkerHostId); 847 EXPECT_EQ(NULL, backend_impl_->GetHost(kNonExsitingHostId)); 848 worker_host->SelectCacheForWorker(kNonExsitingHostId, kMockProcessId); 849 handler_.reset(worker_host->CreateRequestHandler( 850 request_.get(), RESOURCE_TYPE_SHARED_WORKER)); 851 EXPECT_FALSE(handler_.get()); 852 853 TestFinished(); 854 } 855 856 // MainResource_Blocked -------------------------------------------------- 857 858 void MainResource_Blocked() { 859 PushNextTask( 860 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked, 861 base::Unretained(this))); 862 863 request_ = empty_context_.CreateRequest( 864 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL); 865 handler_.reset(host_->CreateRequestHandler(request_.get(), 866 RESOURCE_TYPE_MAIN_FRAME)); 867 EXPECT_TRUE(handler_.get()); 868 869 mock_policy_->can_load_return_value_ = false; 870 mock_storage()->SimulateFindMainResource( 871 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), 872 GURL(), AppCacheEntry(), 873 1, 2, GURL("http://blah/manifest/")); 874 875 job_ = handler_->MaybeLoadResource(request_.get(), 876 request_->context()->network_delegate()); 877 EXPECT_TRUE(job_.get()); 878 EXPECT_TRUE(job_->is_waiting()); 879 880 // We have to wait for completion of storage->FindResponseForMainRequest. 881 ScheduleNextTask(); 882 } 883 884 void Verify_MainResource_Blocked() { 885 EXPECT_FALSE(job_->is_waiting()); 886 EXPECT_FALSE(job_->is_delivering_appcache_response()); 887 888 EXPECT_EQ(0, handler_->found_cache_id_); 889 EXPECT_EQ(0, handler_->found_group_id_); 890 EXPECT_TRUE(handler_->found_manifest_url_.is_empty()); 891 EXPECT_TRUE(host_->preferred_manifest_url().is_empty()); 892 EXPECT_TRUE(host_->main_resource_blocked_); 893 EXPECT_TRUE(host_->blocked_manifest_url_ == GURL("http://blah/manifest/")); 894 895 TestFinished(); 896 } 897 898 // Test case helpers -------------------------------------------------- 899 900 AppCache* MakeNewCache() { 901 AppCache* cache = new AppCache( 902 mock_storage(), mock_storage()->NewCacheId()); 903 cache->set_complete(true); 904 AppCacheGroup* group = new AppCacheGroup( 905 mock_storage(), GURL("http://blah/manifest"), 906 mock_storage()->NewGroupId()); 907 group->AddCache(cache); 908 return cache; 909 } 910 911 MockAppCacheStorage* mock_storage() { 912 return reinterpret_cast<MockAppCacheStorage*>(mock_service_->storage()); 913 } 914 915 // Data members -------------------------------------------------- 916 917 scoped_ptr<base::WaitableEvent> test_finished_event_; 918 std::stack<base::Closure> task_stack_; 919 scoped_ptr<MockAppCacheService> mock_service_; 920 scoped_ptr<AppCacheBackendImpl> backend_impl_; 921 scoped_ptr<MockFrontend> mock_frontend_; 922 scoped_ptr<MockAppCachePolicy> mock_policy_; 923 AppCacheHost* host_; 924 net::URLRequestContext empty_context_; 925 scoped_ptr<MockURLRequestJobFactory> job_factory_; 926 MockURLRequestDelegate delegate_; 927 scoped_ptr<net::URLRequest> request_; 928 scoped_ptr<AppCacheRequestHandler> handler_; 929 scoped_refptr<AppCacheURLRequestJob> job_; 930 931 static scoped_ptr<base::Thread> io_thread_; 932 }; 933 934 // static 935 scoped_ptr<base::Thread> AppCacheRequestHandlerTest::io_thread_; 936 937 TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) { 938 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss); 939 } 940 941 TEST_F(AppCacheRequestHandlerTest, MainResource_Hit) { 942 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit); 943 } 944 945 TEST_F(AppCacheRequestHandlerTest, MainResource_Fallback) { 946 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback); 947 } 948 949 TEST_F(AppCacheRequestHandlerTest, MainResource_FallbackOverride) { 950 RunTestOnIOThread( 951 &AppCacheRequestHandlerTest::MainResource_FallbackOverride); 952 } 953 954 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) { 955 RunTestOnIOThread( 956 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected); 957 } 958 959 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) { 960 RunTestOnIOThread( 961 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected); 962 } 963 964 TEST_F(AppCacheRequestHandlerTest, 965 SubResource_Miss_WithWaitForCacheSelection) { 966 RunTestOnIOThread( 967 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection); 968 } 969 970 TEST_F(AppCacheRequestHandlerTest, SubResource_Hit) { 971 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit); 972 } 973 974 TEST_F(AppCacheRequestHandlerTest, SubResource_RedirectFallback) { 975 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback); 976 } 977 978 TEST_F(AppCacheRequestHandlerTest, SubResource_NoRedirectFallback) { 979 RunTestOnIOThread( 980 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback); 981 } 982 983 TEST_F(AppCacheRequestHandlerTest, SubResource_Network) { 984 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network); 985 } 986 987 TEST_F(AppCacheRequestHandlerTest, DestroyedHost) { 988 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost); 989 } 990 991 TEST_F(AppCacheRequestHandlerTest, DestroyedHostWithWaitingJob) { 992 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob); 993 } 994 995 TEST_F(AppCacheRequestHandlerTest, UnsupportedScheme) { 996 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme); 997 } 998 999 TEST_F(AppCacheRequestHandlerTest, CanceledRequest) { 1000 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest); 1001 } 1002 1003 TEST_F(AppCacheRequestHandlerTest, WorkerRequest) { 1004 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest); 1005 } 1006 1007 TEST_F(AppCacheRequestHandlerTest, MainResource_Blocked) { 1008 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked); 1009 } 1010 1011 } // namespace content 1012