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.
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"
32 static const int kMockProcessId = 1;
34 class AppCacheRequestHandlerTest : public testing::Test {
36 class MockFrontend : public AppCacheFrontend {
38 void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
40 void OnStatusChanged(const std::vector<int>& host_ids,
41 AppCacheStatus status) override {}
43 void OnEventRaised(const std::vector<int>& host_ids,
44 AppCacheEventID event_id) override {}
46 void OnErrorEventRaised(const std::vector<int>& host_ids,
47 const AppCacheErrorDetails& details) override {}
49 void OnProgressEventRaised(const std::vector<int>& host_ids,
52 int num_complete) override {}
54 void OnLogMessage(int host_id,
55 AppCacheLogLevel log_level,
56 const std::string& message) override {}
58 void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
61 // Helper callback to run a test on our io_thread. The io_thread is spun up
62 // once and reused for all tests.
63 template <class Method>
64 void MethodWrapper(Method method) {
69 // Subclasses to simulate particular responses so test cases can
70 // exercise fallback code paths.
72 class MockURLRequestDelegate : public net::URLRequest::Delegate {
73 void OnResponseStarted(net::URLRequest* request) override {}
74 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {}
77 class MockURLRequestJob : public net::URLRequestJob {
79 MockURLRequestJob(net::URLRequest* request,
80 net::NetworkDelegate* network_delegate,
82 : net::URLRequestJob(request, network_delegate),
83 response_code_(response_code),
84 has_response_info_(false) {}
85 MockURLRequestJob(net::URLRequest* request,
86 net::NetworkDelegate* network_delegate,
87 const net::HttpResponseInfo& info)
88 : net::URLRequestJob(request, network_delegate),
89 response_code_(info.headers->response_code()),
90 has_response_info_(true),
91 response_info_(info) {}
94 ~MockURLRequestJob() override {}
95 void Start() override { NotifyHeadersComplete(); }
96 int GetResponseCode() const override { return response_code_; }
97 void GetResponseInfo(net::HttpResponseInfo* info) override {
98 if (!has_response_info_)
100 *info = response_info_;
105 bool has_response_info_;
106 net::HttpResponseInfo response_info_;
109 class MockURLRequestJobFactory : public net::URLRequestJobFactory {
111 MockURLRequestJobFactory() : job_(NULL) {
114 ~MockURLRequestJobFactory() override { DCHECK(!job_); }
116 void SetJob(net::URLRequestJob* job) {
120 net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
121 const std::string& scheme,
122 net::URLRequest* request,
123 net::NetworkDelegate* network_delegate) const override {
125 net::URLRequestJob* temp = job_;
129 // Some of these tests trigger UpdateJobs which start URLRequests.
130 // We short circuit those be returning error jobs.
131 return new net::URLRequestErrorJob(request,
133 net::ERR_INTERNET_DISCONNECTED);
137 net::URLRequestJob* MaybeInterceptRedirect(
138 net::URLRequest* request,
139 net::NetworkDelegate* network_delegate,
140 const GURL& location) const override {
144 net::URLRequestJob* MaybeInterceptResponse(
145 net::URLRequest* request,
146 net::NetworkDelegate* network_delegate) const override {
150 bool IsHandledProtocol(const std::string& scheme) const override {
151 return scheme == "http";
154 bool IsHandledURL(const GURL& url) const override {
155 return url.SchemeIs("http");
158 bool IsSafeRedirectTarget(const GURL& location) const override {
163 mutable net::URLRequestJob* job_;
166 static void SetUpTestCase() {
167 io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
168 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
169 io_thread_->StartWithOptions(options);
172 static void TearDownTestCase() {
173 io_thread_.reset(NULL);
176 // Test harness --------------------------------------------------
178 AppCacheRequestHandlerTest() : host_(NULL) {}
180 template <class Method>
181 void RunTestOnIOThread(Method method) {
182 test_finished_event_ .reset(new base::WaitableEvent(false, false));
183 io_thread_->message_loop()->PostTask(
185 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
186 base::Unretained(this), method));
187 test_finished_event_->Wait();
191 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
192 mock_service_.reset(new MockAppCacheService);
193 mock_service_->set_request_context(&empty_context_);
194 mock_policy_.reset(new MockAppCachePolicy);
195 mock_service_->set_appcache_policy(mock_policy_.get());
196 mock_frontend_.reset(new MockFrontend);
197 backend_impl_.reset(new AppCacheBackendImpl);
198 backend_impl_->Initialize(mock_service_.get(), mock_frontend_.get(),
200 const int kHostId = 1;
201 backend_impl_->RegisterHost(kHostId);
202 host_ = backend_impl_->GetHost(kHostId);
203 job_factory_.reset(new MockURLRequestJobFactory());
204 empty_context_.set_job_factory(job_factory_.get());
207 void TearDownTest() {
208 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
212 backend_impl_.reset();
213 mock_frontend_.reset();
214 mock_service_.reset();
215 mock_policy_.reset();
216 job_factory_.reset();
220 void TestFinished() {
221 // We unwind the stack prior to finishing up to let stack
222 // based objects get deleted.
223 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
224 base::MessageLoop::current()->PostTask(
226 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
227 base::Unretained(this)));
230 void TestFinishedUnwound() {
232 test_finished_event_->Signal();
235 void PushNextTask(const base::Closure& task) {
236 task_stack_.push(task);
239 void ScheduleNextTask() {
240 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
241 if (task_stack_.empty()) {
245 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
249 // MainResource_Miss --------------------------------------------------
251 void MainResource_Miss() {
253 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
254 base::Unretained(this)));
256 request_ = empty_context_.CreateRequest(
257 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
258 handler_.reset(host_->CreateRequestHandler(request_.get(),
259 RESOURCE_TYPE_MAIN_FRAME));
260 EXPECT_TRUE(handler_.get());
262 job_ = handler_->MaybeLoadResource(request_.get(),
263 request_->context()->network_delegate());
264 EXPECT_TRUE(job_.get());
265 EXPECT_TRUE(job_->is_waiting());
267 // We have to wait for completion of storage->FindResponseForMainRequest.
271 void Verify_MainResource_Miss() {
272 EXPECT_FALSE(job_->is_waiting());
273 EXPECT_TRUE(job_->is_delivering_network_response());
275 int64 cache_id = kAppCacheNoCacheId;
277 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
278 EXPECT_EQ(kAppCacheNoCacheId, cache_id);
279 EXPECT_EQ(GURL(), manifest_url);
280 EXPECT_EQ(0, handler_->found_group_id_);
282 AppCacheURLRequestJob* fallback_job;
283 fallback_job = handler_->MaybeLoadFallbackForRedirect(
285 request_->context()->network_delegate(),
286 GURL("http://blah/redirect"));
287 EXPECT_FALSE(fallback_job);
288 fallback_job = handler_->MaybeLoadFallbackForResponse(
289 request_.get(), request_->context()->network_delegate());
290 EXPECT_FALSE(fallback_job);
292 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
297 // MainResource_Hit --------------------------------------------------
299 void MainResource_Hit() {
301 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit,
302 base::Unretained(this)));
304 request_ = empty_context_.CreateRequest(
305 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
306 handler_.reset(host_->CreateRequestHandler(request_.get(),
307 RESOURCE_TYPE_MAIN_FRAME));
308 EXPECT_TRUE(handler_.get());
310 mock_storage()->SimulateFindMainResource(
311 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
312 GURL(), AppCacheEntry(),
313 1, 2, GURL("http://blah/manifest/"));
315 job_ = handler_->MaybeLoadResource(request_.get(),
316 request_->context()->network_delegate());
317 EXPECT_TRUE(job_.get());
318 EXPECT_TRUE(job_->is_waiting());
320 // We have to wait for completion of storage->FindResponseForMainRequest.
324 void Verify_MainResource_Hit() {
325 EXPECT_FALSE(job_->is_waiting());
326 EXPECT_TRUE(job_->is_delivering_appcache_response());
328 int64 cache_id = kAppCacheNoCacheId;
330 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
331 EXPECT_EQ(1, cache_id);
332 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
333 EXPECT_EQ(2, handler_->found_group_id_);
335 AppCacheURLRequestJob* fallback_job;
336 fallback_job = handler_->MaybeLoadFallbackForResponse(
337 request_.get(), request_->context()->network_delegate());
338 EXPECT_FALSE(fallback_job);
340 EXPECT_EQ(GURL("http://blah/manifest/"),
341 host_->preferred_manifest_url());
346 // MainResource_Fallback --------------------------------------------------
348 void MainResource_Fallback() {
350 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
351 base::Unretained(this)));
353 request_ = empty_context_.CreateRequest(
354 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
355 handler_.reset(host_->CreateRequestHandler(request_.get(),
356 RESOURCE_TYPE_MAIN_FRAME));
357 EXPECT_TRUE(handler_.get());
359 mock_storage()->SimulateFindMainResource(
361 GURL("http://blah/fallbackurl"),
362 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
363 1, 2, GURL("http://blah/manifest/"));
365 job_ = handler_->MaybeLoadResource(request_.get(),
366 request_->context()->network_delegate());
367 EXPECT_TRUE(job_.get());
368 EXPECT_TRUE(job_->is_waiting());
370 // We have to wait for completion of storage->FindResponseForMainRequest.
374 void SimulateResponseCode(int response_code) {
375 job_factory_->SetJob(
376 new MockURLRequestJob(
378 request_->context()->network_delegate(),
381 // All our simulation needs to satisfy are the following two DCHECKs
382 DCHECK(request_->status().is_success());
383 DCHECK_EQ(response_code, request_->GetResponseCode());
386 void SimulateResponseInfo(const net::HttpResponseInfo& info) {
387 job_factory_->SetJob(
388 new MockURLRequestJob(
390 request_->context()->network_delegate(), info));
394 void Verify_MainResource_Fallback() {
395 EXPECT_FALSE(job_->is_waiting());
396 EXPECT_TRUE(job_->is_delivering_network_response());
398 // When the request is restarted, the existing job is dropped so a
399 // real network job gets created. We expect NULL here which will cause
400 // the net library to create a real job.
401 job_ = handler_->MaybeLoadResource(request_.get(),
402 request_->context()->network_delegate());
403 EXPECT_FALSE(job_.get());
405 // Simulate an http error of the real network job.
406 SimulateResponseCode(500);
408 job_ = handler_->MaybeLoadFallbackForResponse(
409 request_.get(), request_->context()->network_delegate());
410 EXPECT_TRUE(job_.get());
411 EXPECT_TRUE(job_->is_delivering_appcache_response());
413 int64 cache_id = kAppCacheNoCacheId;
415 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
416 EXPECT_EQ(1, cache_id);
417 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
418 EXPECT_TRUE(host_->main_resource_was_namespace_entry_);
419 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->namespace_entry_url_);
421 EXPECT_EQ(GURL("http://blah/manifest/"),
422 host_->preferred_manifest_url());
427 // MainResource_FallbackOverride --------------------------------------------
429 void MainResource_FallbackOverride() {
430 PushNextTask(base::Bind(
431 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
432 base::Unretained(this)));
434 request_ = empty_context_.CreateRequest(
435 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY,
437 handler_.reset(host_->CreateRequestHandler(request_.get(),
438 RESOURCE_TYPE_MAIN_FRAME));
439 EXPECT_TRUE(handler_.get());
441 mock_storage()->SimulateFindMainResource(
443 GURL("http://blah/fallbackurl"),
444 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
445 1, 2, GURL("http://blah/manifest/"));
447 job_ = handler_->MaybeLoadResource(request_.get(),
448 request_->context()->network_delegate());
449 EXPECT_TRUE(job_.get());
450 EXPECT_TRUE(job_->is_waiting());
452 // We have to wait for completion of storage->FindResponseForMainRequest.
456 void Verify_MainResource_FallbackOverride() {
457 EXPECT_FALSE(job_->is_waiting());
458 EXPECT_TRUE(job_->is_delivering_network_response());
460 // When the request is restarted, the existing job is dropped so a
461 // real network job gets created. We expect NULL here which will cause
462 // the net library to create a real job.
463 job_ = handler_->MaybeLoadResource(request_.get(),
464 request_->context()->network_delegate());
465 EXPECT_FALSE(job_.get());
467 // Simulate an http error of the real network job, but with custom
468 // headers that override the fallback behavior.
469 const char kOverrideHeaders[] =
470 "HTTP/1.1 404 BOO HOO\0"
471 "x-chromium-appcache-fallback-override: disallow-fallback\0"
473 net::HttpResponseInfo info;
474 info.headers = new net::HttpResponseHeaders(
475 std::string(kOverrideHeaders, arraysize(kOverrideHeaders)));
476 SimulateResponseInfo(info);
478 job_ = handler_->MaybeLoadFallbackForResponse(
479 request_.get(), request_->context()->network_delegate());
480 EXPECT_FALSE(job_.get());
485 // SubResource_Miss_WithNoCacheSelected ----------------------------------
487 void SubResource_Miss_WithNoCacheSelected() {
488 request_ = empty_context_.CreateRequest(
489 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
490 handler_.reset(host_->CreateRequestHandler(request_.get(),
491 RESOURCE_TYPE_SUB_RESOURCE));
493 // We avoid creating handler when possible, sub-resource requests are not
494 // subject to retrieval from an appcache when there's no associated cache.
495 EXPECT_FALSE(handler_.get());
500 // SubResource_Miss_WithCacheSelected ----------------------------------
502 void SubResource_Miss_WithCacheSelected() {
503 // A sub-resource load where the resource is not in an appcache, or
504 // in a network or fallback namespace, should result in a failed request.
505 host_->AssociateCompleteCache(MakeNewCache());
507 request_ = empty_context_.CreateRequest(
508 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
509 handler_.reset(host_->CreateRequestHandler(request_.get(),
510 RESOURCE_TYPE_SUB_RESOURCE));
511 EXPECT_TRUE(handler_.get());
513 job_ = handler_->MaybeLoadResource(request_.get(),
514 request_->context()->network_delegate());
515 EXPECT_TRUE(job_.get());
516 EXPECT_TRUE(job_->is_delivering_error_response());
518 AppCacheURLRequestJob* fallback_job;
519 fallback_job = handler_->MaybeLoadFallbackForRedirect(
521 request_->context()->network_delegate(),
522 GURL("http://blah/redirect"));
523 EXPECT_FALSE(fallback_job);
524 fallback_job = handler_->MaybeLoadFallbackForResponse(
525 request_.get(), request_->context()->network_delegate());
526 EXPECT_FALSE(fallback_job);
531 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
533 void SubResource_Miss_WithWaitForCacheSelection() {
534 // Precondition, the host is waiting on cache selection.
535 scoped_refptr<AppCache> cache(MakeNewCache());
536 host_->pending_selected_cache_id_ = cache->cache_id();
537 host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
539 request_ = empty_context_.CreateRequest(
540 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
541 handler_.reset(host_->CreateRequestHandler(request_.get(),
542 RESOURCE_TYPE_SUB_RESOURCE));
543 EXPECT_TRUE(handler_.get());
544 job_ = handler_->MaybeLoadResource(request_.get(),
545 request_->context()->network_delegate());
546 EXPECT_TRUE(job_.get());
547 EXPECT_TRUE(job_->is_waiting());
549 host_->FinishCacheSelection(cache.get(), NULL);
550 EXPECT_FALSE(job_->is_waiting());
551 EXPECT_TRUE(job_->is_delivering_error_response());
553 AppCacheURLRequestJob* fallback_job;
554 fallback_job = handler_->MaybeLoadFallbackForRedirect(
556 request_->context()->network_delegate(),
557 GURL("http://blah/redirect"));
558 EXPECT_FALSE(fallback_job);
559 fallback_job = handler_->MaybeLoadFallbackForResponse(
560 request_.get(), request_->context()->network_delegate());
561 EXPECT_FALSE(fallback_job);
566 // SubResource_Hit -----------------------------
568 void SubResource_Hit() {
569 host_->AssociateCompleteCache(MakeNewCache());
571 mock_storage()->SimulateFindSubResource(
572 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
574 request_ = empty_context_.CreateRequest(
575 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
576 handler_.reset(host_->CreateRequestHandler(request_.get(),
577 RESOURCE_TYPE_SUB_RESOURCE));
578 EXPECT_TRUE(handler_.get());
579 job_ = handler_->MaybeLoadResource(request_.get(),
580 request_->context()->network_delegate());
581 EXPECT_TRUE(job_.get());
582 EXPECT_TRUE(job_->is_delivering_appcache_response());
584 AppCacheURLRequestJob* fallback_job;
585 fallback_job = handler_->MaybeLoadFallbackForRedirect(
587 request_->context()->network_delegate(),
588 GURL("http://blah/redirect"));
589 EXPECT_FALSE(fallback_job);
590 fallback_job = handler_->MaybeLoadFallbackForResponse(
591 request_.get(), request_->context()->network_delegate());
592 EXPECT_FALSE(fallback_job);
597 // SubResource_RedirectFallback -----------------------------
599 void SubResource_RedirectFallback() {
600 // Redirects to resources in the a different origin are subject to
601 // fallback namespaces.
602 host_->AssociateCompleteCache(MakeNewCache());
604 mock_storage()->SimulateFindSubResource(
605 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
607 request_ = empty_context_.CreateRequest(
608 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
609 handler_.reset(host_->CreateRequestHandler(request_.get(),
610 RESOURCE_TYPE_SUB_RESOURCE));
611 EXPECT_TRUE(handler_.get());
612 job_ = handler_->MaybeLoadResource(request_.get(),
613 request_->context()->network_delegate());
614 EXPECT_FALSE(job_.get());
616 job_ = handler_->MaybeLoadFallbackForRedirect(
618 request_->context()->network_delegate(),
619 GURL("http://not_blah/redirect"));
620 EXPECT_TRUE(job_.get());
621 EXPECT_TRUE(job_->is_delivering_appcache_response());
623 AppCacheURLRequestJob* fallback_job;
624 fallback_job = handler_->MaybeLoadFallbackForResponse(
625 request_.get(), request_->context()->network_delegate());
626 EXPECT_FALSE(fallback_job);
631 // SubResource_NoRedirectFallback -----------------------------
633 void SubResource_NoRedirectFallback() {
634 // Redirects to resources in the same-origin are not subject to
635 // fallback namespaces.
636 host_->AssociateCompleteCache(MakeNewCache());
638 mock_storage()->SimulateFindSubResource(
639 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
641 request_ = empty_context_.CreateRequest(
642 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
643 handler_.reset(host_->CreateRequestHandler(request_.get(),
644 RESOURCE_TYPE_SUB_RESOURCE));
645 EXPECT_TRUE(handler_.get());
646 job_ = handler_->MaybeLoadResource(request_.get(),
647 request_->context()->network_delegate());
648 EXPECT_FALSE(job_.get());
650 AppCacheURLRequestJob* fallback_job;
651 fallback_job = handler_->MaybeLoadFallbackForRedirect(
653 request_->context()->network_delegate(),
654 GURL("http://blah/redirect"));
655 EXPECT_FALSE(fallback_job);
657 SimulateResponseCode(200);
658 fallback_job = handler_->MaybeLoadFallbackForResponse(
659 request_.get(), request_->context()->network_delegate());
660 EXPECT_FALSE(fallback_job);
665 // SubResource_Network -----------------------------
667 void SubResource_Network() {
668 // A sub-resource load where the resource is in a network namespace,
669 // should result in the system using a 'real' job to do the network
671 host_->AssociateCompleteCache(MakeNewCache());
673 mock_storage()->SimulateFindSubResource(
674 AppCacheEntry(), AppCacheEntry(), true);
676 request_ = empty_context_.CreateRequest(
677 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
678 handler_.reset(host_->CreateRequestHandler(request_.get(),
679 RESOURCE_TYPE_SUB_RESOURCE));
680 EXPECT_TRUE(handler_.get());
681 job_ = handler_->MaybeLoadResource(request_.get(),
682 request_->context()->network_delegate());
683 EXPECT_FALSE(job_.get());
685 AppCacheURLRequestJob* fallback_job;
686 fallback_job = handler_->MaybeLoadFallbackForRedirect(
688 request_->context()->network_delegate(),
689 GURL("http://blah/redirect"));
690 EXPECT_FALSE(fallback_job);
691 fallback_job = handler_->MaybeLoadFallbackForResponse(
692 request_.get(), request_->context()->network_delegate());
693 EXPECT_FALSE(fallback_job);
698 // DestroyedHost -----------------------------
700 void DestroyedHost() {
701 host_->AssociateCompleteCache(MakeNewCache());
703 mock_storage()->SimulateFindSubResource(
704 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
706 request_ = empty_context_.CreateRequest(
707 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
708 handler_.reset(host_->CreateRequestHandler(request_.get(),
709 RESOURCE_TYPE_SUB_RESOURCE));
710 EXPECT_TRUE(handler_.get());
712 backend_impl_->UnregisterHost(1);
715 EXPECT_FALSE(handler_->MaybeLoadResource(
716 request_.get(), request_->context()->network_delegate()));
717 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
719 request_->context()->network_delegate(),
720 GURL("http://blah/redirect")));
721 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
722 request_.get(), request_->context()->network_delegate()));
727 // DestroyedHostWithWaitingJob -----------------------------
729 void DestroyedHostWithWaitingJob() {
730 // Precondition, the host is waiting on cache selection.
731 host_->pending_selected_cache_id_ = 1;
733 request_ = empty_context_.CreateRequest(
734 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
735 handler_.reset(host_->CreateRequestHandler(request_.get(),
736 RESOURCE_TYPE_SUB_RESOURCE));
737 EXPECT_TRUE(handler_.get());
739 job_ = handler_->MaybeLoadResource(request_.get(),
740 request_->context()->network_delegate());
741 EXPECT_TRUE(job_.get());
742 EXPECT_TRUE(job_->is_waiting());
744 backend_impl_->UnregisterHost(1);
746 EXPECT_TRUE(job_->has_been_killed());
748 EXPECT_FALSE(handler_->MaybeLoadResource(
749 request_.get(), request_->context()->network_delegate()));
750 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
752 request_->context()->network_delegate(),
753 GURL("http://blah/redirect")));
754 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
755 request_.get(), request_->context()->network_delegate()));
760 // UnsupportedScheme -----------------------------
762 void UnsupportedScheme() {
763 // Precondition, the host is waiting on cache selection.
764 host_->pending_selected_cache_id_ = 1;
766 request_ = empty_context_.CreateRequest(
767 GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
768 handler_.reset(host_->CreateRequestHandler(request_.get(),
769 RESOURCE_TYPE_SUB_RESOURCE));
770 EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
772 EXPECT_FALSE(handler_->MaybeLoadResource(
773 request_.get(), request_->context()->network_delegate()));
774 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
776 request_->context()->network_delegate(),
777 GURL("ftp://blah/redirect")));
778 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
779 request_.get(), request_->context()->network_delegate()));
784 // CanceledRequest -----------------------------
786 void CanceledRequest() {
787 request_ = empty_context_.CreateRequest(
788 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
789 handler_.reset(host_->CreateRequestHandler(request_.get(),
790 RESOURCE_TYPE_MAIN_FRAME));
791 EXPECT_TRUE(handler_.get());
793 job_ = handler_->MaybeLoadResource(request_.get(),
794 request_->context()->network_delegate());
795 EXPECT_TRUE(job_.get());
796 EXPECT_TRUE(job_->is_waiting());
797 EXPECT_FALSE(job_->has_been_started());
799 job_factory_->SetJob(job_.get());
801 EXPECT_TRUE(job_->has_been_started());
804 EXPECT_TRUE(job_->has_been_killed());
806 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
807 request_.get(), request_->context()->network_delegate()));
812 // WorkerRequest -----------------------------
814 void WorkerRequest() {
815 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
816 RESOURCE_TYPE_MAIN_FRAME));
817 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
818 RESOURCE_TYPE_SUB_FRAME));
819 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
820 RESOURCE_TYPE_SHARED_WORKER));
821 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
822 RESOURCE_TYPE_WORKER));
824 request_ = empty_context_.CreateRequest(
825 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
827 const int kParentHostId = host_->host_id();
828 const int kWorkerHostId = 2;
829 const int kAbandonedWorkerHostId = 3;
830 const int kNonExsitingHostId = 700;
832 backend_impl_->RegisterHost(kWorkerHostId);
833 AppCacheHost* worker_host = backend_impl_->GetHost(kWorkerHostId);
834 worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId);
835 handler_.reset(worker_host->CreateRequestHandler(
836 request_.get(), RESOURCE_TYPE_SHARED_WORKER));
837 EXPECT_TRUE(handler_.get());
838 // Verify that the handler is associated with the parent host.
839 EXPECT_EQ(host_, handler_->host_);
841 // Create a new worker host, but associate it with a parent host that
842 // does not exists to simulate the host having been torn down.
843 backend_impl_->UnregisterHost(kWorkerHostId);
844 backend_impl_->RegisterHost(kAbandonedWorkerHostId);
845 worker_host = backend_impl_->GetHost(kAbandonedWorkerHostId);
846 EXPECT_EQ(NULL, backend_impl_->GetHost(kNonExsitingHostId));
847 worker_host->SelectCacheForWorker(kNonExsitingHostId, kMockProcessId);
848 handler_.reset(worker_host->CreateRequestHandler(
849 request_.get(), RESOURCE_TYPE_SHARED_WORKER));
850 EXPECT_FALSE(handler_.get());
855 // MainResource_Blocked --------------------------------------------------
857 void MainResource_Blocked() {
859 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
860 base::Unretained(this)));
862 request_ = empty_context_.CreateRequest(
863 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
864 handler_.reset(host_->CreateRequestHandler(request_.get(),
865 RESOURCE_TYPE_MAIN_FRAME));
866 EXPECT_TRUE(handler_.get());
868 mock_policy_->can_load_return_value_ = false;
869 mock_storage()->SimulateFindMainResource(
870 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
871 GURL(), AppCacheEntry(),
872 1, 2, GURL("http://blah/manifest/"));
874 job_ = handler_->MaybeLoadResource(request_.get(),
875 request_->context()->network_delegate());
876 EXPECT_TRUE(job_.get());
877 EXPECT_TRUE(job_->is_waiting());
879 // We have to wait for completion of storage->FindResponseForMainRequest.
883 void Verify_MainResource_Blocked() {
884 EXPECT_FALSE(job_->is_waiting());
885 EXPECT_FALSE(job_->is_delivering_appcache_response());
887 EXPECT_EQ(0, handler_->found_cache_id_);
888 EXPECT_EQ(0, handler_->found_group_id_);
889 EXPECT_TRUE(handler_->found_manifest_url_.is_empty());
890 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
891 EXPECT_TRUE(host_->main_resource_blocked_);
892 EXPECT_TRUE(host_->blocked_manifest_url_ == GURL("http://blah/manifest/"));
897 // Test case helpers --------------------------------------------------
899 AppCache* MakeNewCache() {
900 AppCache* cache = new AppCache(
901 mock_storage(), mock_storage()->NewCacheId());
902 cache->set_complete(true);
903 AppCacheGroup* group = new AppCacheGroup(
904 mock_storage(), GURL("http://blah/manifest"),
905 mock_storage()->NewGroupId());
906 group->AddCache(cache);
910 MockAppCacheStorage* mock_storage() {
911 return reinterpret_cast<MockAppCacheStorage*>(mock_service_->storage());
914 // Data members --------------------------------------------------
916 scoped_ptr<base::WaitableEvent> test_finished_event_;
917 std::stack<base::Closure> task_stack_;
918 scoped_ptr<MockAppCacheService> mock_service_;
919 scoped_ptr<AppCacheBackendImpl> backend_impl_;
920 scoped_ptr<MockFrontend> mock_frontend_;
921 scoped_ptr<MockAppCachePolicy> mock_policy_;
923 net::URLRequestContext empty_context_;
924 scoped_ptr<MockURLRequestJobFactory> job_factory_;
925 MockURLRequestDelegate delegate_;
926 scoped_ptr<net::URLRequest> request_;
927 scoped_ptr<AppCacheRequestHandler> handler_;
928 scoped_refptr<AppCacheURLRequestJob> job_;
930 static scoped_ptr<base::Thread> io_thread_;
934 scoped_ptr<base::Thread> AppCacheRequestHandlerTest::io_thread_;
936 TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) {
937 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss);
940 TEST_F(AppCacheRequestHandlerTest, MainResource_Hit) {
941 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit);
944 TEST_F(AppCacheRequestHandlerTest, MainResource_Fallback) {
945 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback);
948 TEST_F(AppCacheRequestHandlerTest, MainResource_FallbackOverride) {
950 &AppCacheRequestHandlerTest::MainResource_FallbackOverride);
953 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) {
955 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected);
958 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) {
960 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected);
963 TEST_F(AppCacheRequestHandlerTest,
964 SubResource_Miss_WithWaitForCacheSelection) {
966 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection);
969 TEST_F(AppCacheRequestHandlerTest, SubResource_Hit) {
970 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit);
973 TEST_F(AppCacheRequestHandlerTest, SubResource_RedirectFallback) {
974 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback);
977 TEST_F(AppCacheRequestHandlerTest, SubResource_NoRedirectFallback) {
979 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback);
982 TEST_F(AppCacheRequestHandlerTest, SubResource_Network) {
983 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network);
986 TEST_F(AppCacheRequestHandlerTest, DestroyedHost) {
987 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost);
990 TEST_F(AppCacheRequestHandlerTest, DestroyedHostWithWaitingJob) {
991 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob);
994 TEST_F(AppCacheRequestHandlerTest, UnsupportedScheme) {
995 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme);
998 TEST_F(AppCacheRequestHandlerTest, CanceledRequest) {
999 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest);
1002 TEST_F(AppCacheRequestHandlerTest, WorkerRequest) {
1003 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest);
1006 TEST_F(AppCacheRequestHandlerTest, MainResource_Blocked) {
1007 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked);
1010 } // namespace content