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_
);
258 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
259 RESOURCE_TYPE_MAIN_FRAME
,
261 EXPECT_TRUE(handler_
.get());
263 job_
= handler_
->MaybeLoadResource(request_
.get(),
264 request_
->context()->network_delegate());
265 EXPECT_TRUE(job_
.get());
266 EXPECT_TRUE(job_
->is_waiting());
268 // We have to wait for completion of storage->FindResponseForMainRequest.
272 void Verify_MainResource_Miss() {
273 EXPECT_FALSE(job_
->is_waiting());
274 EXPECT_TRUE(job_
->is_delivering_network_response());
276 int64 cache_id
= kAppCacheNoCacheId
;
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_
);
283 AppCacheURLRequestJob
* fallback_job
;
284 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
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
);
293 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
298 // MainResource_Hit --------------------------------------------------
300 void MainResource_Hit() {
302 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit
,
303 base::Unretained(this)));
305 request_
= empty_context_
.CreateRequest(
306 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
307 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
308 RESOURCE_TYPE_MAIN_FRAME
,
310 EXPECT_TRUE(handler_
.get());
312 mock_storage()->SimulateFindMainResource(
313 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
314 GURL(), AppCacheEntry(),
315 1, 2, GURL("http://blah/manifest/"));
317 job_
= handler_
->MaybeLoadResource(request_
.get(),
318 request_
->context()->network_delegate());
319 EXPECT_TRUE(job_
.get());
320 EXPECT_TRUE(job_
->is_waiting());
322 // We have to wait for completion of storage->FindResponseForMainRequest.
326 void Verify_MainResource_Hit() {
327 EXPECT_FALSE(job_
->is_waiting());
328 EXPECT_TRUE(job_
->is_delivering_appcache_response());
330 int64 cache_id
= kAppCacheNoCacheId
;
332 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
333 EXPECT_EQ(1, cache_id
);
334 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
335 EXPECT_EQ(2, handler_
->found_group_id_
);
337 AppCacheURLRequestJob
* fallback_job
;
338 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
339 request_
.get(), request_
->context()->network_delegate());
340 EXPECT_FALSE(fallback_job
);
342 EXPECT_EQ(GURL("http://blah/manifest/"),
343 host_
->preferred_manifest_url());
348 // MainResource_Fallback --------------------------------------------------
350 void MainResource_Fallback() {
352 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback
,
353 base::Unretained(this)));
355 request_
= empty_context_
.CreateRequest(
356 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
357 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
358 RESOURCE_TYPE_MAIN_FRAME
,
360 EXPECT_TRUE(handler_
.get());
362 mock_storage()->SimulateFindMainResource(
364 GURL("http://blah/fallbackurl"),
365 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
366 1, 2, GURL("http://blah/manifest/"));
368 job_
= handler_
->MaybeLoadResource(request_
.get(),
369 request_
->context()->network_delegate());
370 EXPECT_TRUE(job_
.get());
371 EXPECT_TRUE(job_
->is_waiting());
373 // We have to wait for completion of storage->FindResponseForMainRequest.
377 void SimulateResponseCode(int response_code
) {
378 job_factory_
->SetJob(
379 new MockURLRequestJob(
381 request_
->context()->network_delegate(),
384 // All our simulation needs to satisfy are the following two DCHECKs
385 DCHECK(request_
->status().is_success());
386 DCHECK_EQ(response_code
, request_
->GetResponseCode());
389 void SimulateResponseInfo(const net::HttpResponseInfo
& info
) {
390 job_factory_
->SetJob(
391 new MockURLRequestJob(
393 request_
->context()->network_delegate(), info
));
397 void Verify_MainResource_Fallback() {
398 EXPECT_FALSE(job_
->is_waiting());
399 EXPECT_TRUE(job_
->is_delivering_network_response());
401 // When the request is restarted, the existing job is dropped so a
402 // real network job gets created. We expect NULL here which will cause
403 // the net library to create a real job.
404 job_
= handler_
->MaybeLoadResource(request_
.get(),
405 request_
->context()->network_delegate());
406 EXPECT_FALSE(job_
.get());
408 // Simulate an http error of the real network job.
409 SimulateResponseCode(500);
411 job_
= handler_
->MaybeLoadFallbackForResponse(
412 request_
.get(), request_
->context()->network_delegate());
413 EXPECT_TRUE(job_
.get());
414 EXPECT_TRUE(job_
->is_delivering_appcache_response());
416 int64 cache_id
= kAppCacheNoCacheId
;
418 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
419 EXPECT_EQ(1, cache_id
);
420 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
421 EXPECT_TRUE(host_
->main_resource_was_namespace_entry_
);
422 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_
->namespace_entry_url_
);
424 EXPECT_EQ(GURL("http://blah/manifest/"),
425 host_
->preferred_manifest_url());
430 // MainResource_FallbackOverride --------------------------------------------
432 void MainResource_FallbackOverride() {
433 PushNextTask(base::Bind(
434 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride
,
435 base::Unretained(this)));
437 request_
= empty_context_
.CreateRequest(
438 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY
,
440 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
441 RESOURCE_TYPE_MAIN_FRAME
,
443 EXPECT_TRUE(handler_
.get());
445 mock_storage()->SimulateFindMainResource(
447 GURL("http://blah/fallbackurl"),
448 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
449 1, 2, GURL("http://blah/manifest/"));
451 job_
= handler_
->MaybeLoadResource(request_
.get(),
452 request_
->context()->network_delegate());
453 EXPECT_TRUE(job_
.get());
454 EXPECT_TRUE(job_
->is_waiting());
456 // We have to wait for completion of storage->FindResponseForMainRequest.
460 void Verify_MainResource_FallbackOverride() {
461 EXPECT_FALSE(job_
->is_waiting());
462 EXPECT_TRUE(job_
->is_delivering_network_response());
464 // When the request is restarted, the existing job is dropped so a
465 // real network job gets created. We expect NULL here which will cause
466 // the net library to create a real job.
467 job_
= handler_
->MaybeLoadResource(request_
.get(),
468 request_
->context()->network_delegate());
469 EXPECT_FALSE(job_
.get());
471 // Simulate an http error of the real network job, but with custom
472 // headers that override the fallback behavior.
473 const char kOverrideHeaders
[] =
474 "HTTP/1.1 404 BOO HOO\0"
475 "x-chromium-appcache-fallback-override: disallow-fallback\0"
477 net::HttpResponseInfo info
;
478 info
.headers
= new net::HttpResponseHeaders(
479 std::string(kOverrideHeaders
, arraysize(kOverrideHeaders
)));
480 SimulateResponseInfo(info
);
482 job_
= handler_
->MaybeLoadFallbackForResponse(
483 request_
.get(), request_
->context()->network_delegate());
484 EXPECT_FALSE(job_
.get());
489 // SubResource_Miss_WithNoCacheSelected ----------------------------------
491 void SubResource_Miss_WithNoCacheSelected() {
492 request_
= empty_context_
.CreateRequest(
493 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
494 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
495 RESOURCE_TYPE_SUB_RESOURCE
,
498 // We avoid creating handler when possible, sub-resource requests are not
499 // subject to retrieval from an appcache when there's no associated cache.
500 EXPECT_FALSE(handler_
.get());
505 // SubResource_Miss_WithCacheSelected ----------------------------------
507 void SubResource_Miss_WithCacheSelected() {
508 // A sub-resource load where the resource is not in an appcache, or
509 // in a network or fallback namespace, should result in a failed request.
510 host_
->AssociateCompleteCache(MakeNewCache());
512 request_
= empty_context_
.CreateRequest(
513 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
514 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
515 RESOURCE_TYPE_SUB_RESOURCE
,
517 EXPECT_TRUE(handler_
.get());
519 job_
= handler_
->MaybeLoadResource(request_
.get(),
520 request_
->context()->network_delegate());
521 EXPECT_TRUE(job_
.get());
522 EXPECT_TRUE(job_
->is_delivering_error_response());
524 AppCacheURLRequestJob
* fallback_job
;
525 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
527 request_
->context()->network_delegate(),
528 GURL("http://blah/redirect"));
529 EXPECT_FALSE(fallback_job
);
530 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
531 request_
.get(), request_
->context()->network_delegate());
532 EXPECT_FALSE(fallback_job
);
537 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
539 void SubResource_Miss_WithWaitForCacheSelection() {
540 // Precondition, the host is waiting on cache selection.
541 scoped_refptr
<AppCache
> cache(MakeNewCache());
542 host_
->pending_selected_cache_id_
= cache
->cache_id();
543 host_
->set_preferred_manifest_url(cache
->owning_group()->manifest_url());
545 request_
= empty_context_
.CreateRequest(
546 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
547 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
548 RESOURCE_TYPE_SUB_RESOURCE
,
550 EXPECT_TRUE(handler_
.get());
551 job_
= handler_
->MaybeLoadResource(request_
.get(),
552 request_
->context()->network_delegate());
553 EXPECT_TRUE(job_
.get());
554 EXPECT_TRUE(job_
->is_waiting());
556 host_
->FinishCacheSelection(cache
.get(), NULL
);
557 EXPECT_FALSE(job_
->is_waiting());
558 EXPECT_TRUE(job_
->is_delivering_error_response());
560 AppCacheURLRequestJob
* fallback_job
;
561 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
563 request_
->context()->network_delegate(),
564 GURL("http://blah/redirect"));
565 EXPECT_FALSE(fallback_job
);
566 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
567 request_
.get(), request_
->context()->network_delegate());
568 EXPECT_FALSE(fallback_job
);
573 // SubResource_Hit -----------------------------
575 void SubResource_Hit() {
576 host_
->AssociateCompleteCache(MakeNewCache());
578 mock_storage()->SimulateFindSubResource(
579 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
581 request_
= empty_context_
.CreateRequest(
582 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
583 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
584 RESOURCE_TYPE_SUB_RESOURCE
,
586 EXPECT_TRUE(handler_
.get());
587 job_
= handler_
->MaybeLoadResource(request_
.get(),
588 request_
->context()->network_delegate());
589 EXPECT_TRUE(job_
.get());
590 EXPECT_TRUE(job_
->is_delivering_appcache_response());
592 AppCacheURLRequestJob
* fallback_job
;
593 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
595 request_
->context()->network_delegate(),
596 GURL("http://blah/redirect"));
597 EXPECT_FALSE(fallback_job
);
598 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
599 request_
.get(), request_
->context()->network_delegate());
600 EXPECT_FALSE(fallback_job
);
605 // SubResource_RedirectFallback -----------------------------
607 void SubResource_RedirectFallback() {
608 // Redirects to resources in the a different origin are subject to
609 // fallback namespaces.
610 host_
->AssociateCompleteCache(MakeNewCache());
612 mock_storage()->SimulateFindSubResource(
613 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
615 request_
= empty_context_
.CreateRequest(
616 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
617 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
618 RESOURCE_TYPE_SUB_RESOURCE
,
620 EXPECT_TRUE(handler_
.get());
621 job_
= handler_
->MaybeLoadResource(request_
.get(),
622 request_
->context()->network_delegate());
623 EXPECT_FALSE(job_
.get());
625 job_
= handler_
->MaybeLoadFallbackForRedirect(
627 request_
->context()->network_delegate(),
628 GURL("http://not_blah/redirect"));
629 EXPECT_TRUE(job_
.get());
630 EXPECT_TRUE(job_
->is_delivering_appcache_response());
632 AppCacheURLRequestJob
* fallback_job
;
633 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
634 request_
.get(), request_
->context()->network_delegate());
635 EXPECT_FALSE(fallback_job
);
640 // SubResource_NoRedirectFallback -----------------------------
642 void SubResource_NoRedirectFallback() {
643 // Redirects to resources in the same-origin are not subject to
644 // fallback namespaces.
645 host_
->AssociateCompleteCache(MakeNewCache());
647 mock_storage()->SimulateFindSubResource(
648 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
650 request_
= empty_context_
.CreateRequest(
651 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
652 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
653 RESOURCE_TYPE_SUB_RESOURCE
,
655 EXPECT_TRUE(handler_
.get());
656 job_
= handler_
->MaybeLoadResource(request_
.get(),
657 request_
->context()->network_delegate());
658 EXPECT_FALSE(job_
.get());
660 AppCacheURLRequestJob
* fallback_job
;
661 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
663 request_
->context()->network_delegate(),
664 GURL("http://blah/redirect"));
665 EXPECT_FALSE(fallback_job
);
667 SimulateResponseCode(200);
668 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
669 request_
.get(), request_
->context()->network_delegate());
670 EXPECT_FALSE(fallback_job
);
675 // SubResource_Network -----------------------------
677 void SubResource_Network() {
678 // A sub-resource load where the resource is in a network namespace,
679 // should result in the system using a 'real' job to do the network
681 host_
->AssociateCompleteCache(MakeNewCache());
683 mock_storage()->SimulateFindSubResource(
684 AppCacheEntry(), AppCacheEntry(), true);
686 request_
= empty_context_
.CreateRequest(
687 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
688 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
689 RESOURCE_TYPE_SUB_RESOURCE
,
691 EXPECT_TRUE(handler_
.get());
692 job_
= handler_
->MaybeLoadResource(request_
.get(),
693 request_
->context()->network_delegate());
694 EXPECT_FALSE(job_
.get());
696 AppCacheURLRequestJob
* fallback_job
;
697 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
699 request_
->context()->network_delegate(),
700 GURL("http://blah/redirect"));
701 EXPECT_FALSE(fallback_job
);
702 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
703 request_
.get(), request_
->context()->network_delegate());
704 EXPECT_FALSE(fallback_job
);
709 // DestroyedHost -----------------------------
711 void DestroyedHost() {
712 host_
->AssociateCompleteCache(MakeNewCache());
714 mock_storage()->SimulateFindSubResource(
715 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
717 request_
= empty_context_
.CreateRequest(
718 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
719 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
720 RESOURCE_TYPE_SUB_RESOURCE
,
722 EXPECT_TRUE(handler_
.get());
724 backend_impl_
->UnregisterHost(1);
727 EXPECT_FALSE(handler_
->MaybeLoadResource(
728 request_
.get(), request_
->context()->network_delegate()));
729 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
731 request_
->context()->network_delegate(),
732 GURL("http://blah/redirect")));
733 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
734 request_
.get(), request_
->context()->network_delegate()));
739 // DestroyedHostWithWaitingJob -----------------------------
741 void DestroyedHostWithWaitingJob() {
742 // Precondition, the host is waiting on cache selection.
743 host_
->pending_selected_cache_id_
= 1;
745 request_
= empty_context_
.CreateRequest(
746 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
747 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
748 RESOURCE_TYPE_SUB_RESOURCE
,
750 EXPECT_TRUE(handler_
.get());
752 job_
= handler_
->MaybeLoadResource(request_
.get(),
753 request_
->context()->network_delegate());
754 EXPECT_TRUE(job_
.get());
755 EXPECT_TRUE(job_
->is_waiting());
757 backend_impl_
->UnregisterHost(1);
759 EXPECT_TRUE(job_
->has_been_killed());
761 EXPECT_FALSE(handler_
->MaybeLoadResource(
762 request_
.get(), request_
->context()->network_delegate()));
763 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
765 request_
->context()->network_delegate(),
766 GURL("http://blah/redirect")));
767 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
768 request_
.get(), request_
->context()->network_delegate()));
773 // UnsupportedScheme -----------------------------
775 void UnsupportedScheme() {
776 // Precondition, the host is waiting on cache selection.
777 host_
->pending_selected_cache_id_
= 1;
779 request_
= empty_context_
.CreateRequest(
780 GURL("ftp://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
781 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
782 RESOURCE_TYPE_SUB_RESOURCE
,
784 EXPECT_TRUE(handler_
.get()); // we could redirect to http (conceivably)
786 EXPECT_FALSE(handler_
->MaybeLoadResource(
787 request_
.get(), request_
->context()->network_delegate()));
788 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
790 request_
->context()->network_delegate(),
791 GURL("ftp://blah/redirect")));
792 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
793 request_
.get(), request_
->context()->network_delegate()));
798 // CanceledRequest -----------------------------
800 void CanceledRequest() {
801 request_
= empty_context_
.CreateRequest(
802 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
803 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
804 RESOURCE_TYPE_MAIN_FRAME
,
806 EXPECT_TRUE(handler_
.get());
808 job_
= handler_
->MaybeLoadResource(request_
.get(),
809 request_
->context()->network_delegate());
810 EXPECT_TRUE(job_
.get());
811 EXPECT_TRUE(job_
->is_waiting());
812 EXPECT_FALSE(job_
->has_been_started());
814 job_factory_
->SetJob(job_
.get());
816 EXPECT_TRUE(job_
->has_been_started());
819 EXPECT_TRUE(job_
->has_been_killed());
821 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
822 request_
.get(), request_
->context()->network_delegate()));
827 // WorkerRequest -----------------------------
829 void WorkerRequest() {
830 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
831 RESOURCE_TYPE_MAIN_FRAME
));
832 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
833 RESOURCE_TYPE_SUB_FRAME
));
834 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
835 RESOURCE_TYPE_SHARED_WORKER
));
836 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
837 RESOURCE_TYPE_WORKER
));
839 request_
= empty_context_
.CreateRequest(
840 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
842 const int kParentHostId
= host_
->host_id();
843 const int kWorkerHostId
= 2;
844 const int kAbandonedWorkerHostId
= 3;
845 const int kNonExsitingHostId
= 700;
847 backend_impl_
->RegisterHost(kWorkerHostId
);
848 AppCacheHost
* worker_host
= backend_impl_
->GetHost(kWorkerHostId
);
849 worker_host
->SelectCacheForWorker(kParentHostId
, kMockProcessId
);
850 handler_
.reset(worker_host
->CreateRequestHandler(
851 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
, false));
852 EXPECT_TRUE(handler_
.get());
853 // Verify that the handler is associated with the parent host.
854 EXPECT_EQ(host_
, handler_
->host_
);
856 // Create a new worker host, but associate it with a parent host that
857 // does not exists to simulate the host having been torn down.
858 backend_impl_
->UnregisterHost(kWorkerHostId
);
859 backend_impl_
->RegisterHost(kAbandonedWorkerHostId
);
860 worker_host
= backend_impl_
->GetHost(kAbandonedWorkerHostId
);
861 EXPECT_EQ(NULL
, backend_impl_
->GetHost(kNonExsitingHostId
));
862 worker_host
->SelectCacheForWorker(kNonExsitingHostId
, kMockProcessId
);
863 handler_
.reset(worker_host
->CreateRequestHandler(
864 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
, false));
865 EXPECT_FALSE(handler_
.get());
870 // MainResource_Blocked --------------------------------------------------
872 void MainResource_Blocked() {
874 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked
,
875 base::Unretained(this)));
877 request_
= empty_context_
.CreateRequest(
878 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
);
879 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
880 RESOURCE_TYPE_MAIN_FRAME
,
882 EXPECT_TRUE(handler_
.get());
884 mock_policy_
->can_load_return_value_
= false;
885 mock_storage()->SimulateFindMainResource(
886 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
887 GURL(), AppCacheEntry(),
888 1, 2, GURL("http://blah/manifest/"));
890 job_
= handler_
->MaybeLoadResource(request_
.get(),
891 request_
->context()->network_delegate());
892 EXPECT_TRUE(job_
.get());
893 EXPECT_TRUE(job_
->is_waiting());
895 // We have to wait for completion of storage->FindResponseForMainRequest.
899 void Verify_MainResource_Blocked() {
900 EXPECT_FALSE(job_
->is_waiting());
901 EXPECT_FALSE(job_
->is_delivering_appcache_response());
903 EXPECT_EQ(0, handler_
->found_cache_id_
);
904 EXPECT_EQ(0, handler_
->found_group_id_
);
905 EXPECT_TRUE(handler_
->found_manifest_url_
.is_empty());
906 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
907 EXPECT_TRUE(host_
->main_resource_blocked_
);
908 EXPECT_TRUE(host_
->blocked_manifest_url_
== GURL("http://blah/manifest/"));
913 // Test case helpers --------------------------------------------------
915 AppCache
* MakeNewCache() {
916 AppCache
* cache
= new AppCache(
917 mock_storage(), mock_storage()->NewCacheId());
918 cache
->set_complete(true);
919 AppCacheGroup
* group
= new AppCacheGroup(
920 mock_storage(), GURL("http://blah/manifest"),
921 mock_storage()->NewGroupId());
922 group
->AddCache(cache
);
926 MockAppCacheStorage
* mock_storage() {
927 return reinterpret_cast<MockAppCacheStorage
*>(mock_service_
->storage());
930 // Data members --------------------------------------------------
932 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
933 std::stack
<base::Closure
> task_stack_
;
934 scoped_ptr
<MockAppCacheService
> mock_service_
;
935 scoped_ptr
<AppCacheBackendImpl
> backend_impl_
;
936 scoped_ptr
<MockFrontend
> mock_frontend_
;
937 scoped_ptr
<MockAppCachePolicy
> mock_policy_
;
939 net::URLRequestContext empty_context_
;
940 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
941 MockURLRequestDelegate delegate_
;
942 scoped_ptr
<net::URLRequest
> request_
;
943 scoped_ptr
<AppCacheRequestHandler
> handler_
;
944 scoped_refptr
<AppCacheURLRequestJob
> job_
;
946 static scoped_ptr
<base::Thread
> io_thread_
;
950 scoped_ptr
<base::Thread
> AppCacheRequestHandlerTest::io_thread_
;
952 TEST_F(AppCacheRequestHandlerTest
, MainResource_Miss
) {
953 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss
);
956 TEST_F(AppCacheRequestHandlerTest
, MainResource_Hit
) {
957 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit
);
960 TEST_F(AppCacheRequestHandlerTest
, MainResource_Fallback
) {
961 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback
);
964 TEST_F(AppCacheRequestHandlerTest
, MainResource_FallbackOverride
) {
966 &AppCacheRequestHandlerTest::MainResource_FallbackOverride
);
969 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithNoCacheSelected
) {
971 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected
);
974 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithCacheSelected
) {
976 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected
);
979 TEST_F(AppCacheRequestHandlerTest
,
980 SubResource_Miss_WithWaitForCacheSelection
) {
982 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection
);
985 TEST_F(AppCacheRequestHandlerTest
, SubResource_Hit
) {
986 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit
);
989 TEST_F(AppCacheRequestHandlerTest
, SubResource_RedirectFallback
) {
990 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback
);
993 TEST_F(AppCacheRequestHandlerTest
, SubResource_NoRedirectFallback
) {
995 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback
);
998 TEST_F(AppCacheRequestHandlerTest
, SubResource_Network
) {
999 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network
);
1002 TEST_F(AppCacheRequestHandlerTest
, DestroyedHost
) {
1003 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost
);
1006 TEST_F(AppCacheRequestHandlerTest
, DestroyedHostWithWaitingJob
) {
1007 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob
);
1010 TEST_F(AppCacheRequestHandlerTest
, UnsupportedScheme
) {
1011 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme
);
1014 TEST_F(AppCacheRequestHandlerTest
, CanceledRequest
) {
1015 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest
);
1018 TEST_F(AppCacheRequestHandlerTest
, WorkerRequest
) {
1019 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest
);
1022 TEST_F(AppCacheRequestHandlerTest
, MainResource_Blocked
) {
1023 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked
);
1026 } // namespace content