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.
9 #include "base/bind_helpers.h"
10 #include "base/callback.h"
11 #include "base/compiler_specific.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/pickle.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/threading/thread.h"
20 #include "content/browser/appcache/appcache_response.h"
21 #include "content/browser/appcache/appcache_url_request_job.h"
22 #include "content/browser/appcache/mock_appcache_service.h"
23 #include "net/base/io_buffer.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/request_priority.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/url_request.h"
28 #include "net/url_request/url_request_context.h"
29 #include "net/url_request/url_request_error_job.h"
30 #include "net/url_request/url_request_job_factory.h"
31 #include "testing/gtest/include/gtest/gtest.h"
35 using net::WrappedIOBuffer
;
41 const char kHttpBasicHeaders
[] = "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
42 const char kHttpBasicBody
[] = "Hello";
44 const int kNumBlocks
= 4;
45 const int kBlockSize
= 1024;
47 class MockURLRequestJobFactory
: public net::URLRequestJobFactory
{
49 MockURLRequestJobFactory() : job_(NULL
) {
52 ~MockURLRequestJobFactory() override
{ DCHECK(!job_
); }
54 void SetJob(net::URLRequestJob
* job
) {
58 bool has_job() const {
62 // net::URLRequestJobFactory implementation.
63 net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
64 const std::string
& scheme
,
65 net::URLRequest
* request
,
66 net::NetworkDelegate
* network_delegate
) const override
{
68 net::URLRequestJob
* temp
= job_
;
72 return new net::URLRequestErrorJob(request
,
74 net::ERR_INTERNET_DISCONNECTED
);
78 net::URLRequestJob
* MaybeInterceptRedirect(
79 net::URLRequest
* request
,
80 net::NetworkDelegate
* network_delegate
,
81 const GURL
& location
) const override
{
85 net::URLRequestJob
* MaybeInterceptResponse(
86 net::URLRequest
* request
,
87 net::NetworkDelegate
* network_delegate
) const override
{
91 bool IsHandledProtocol(const std::string
& scheme
) const override
{
92 return scheme
== "http";
95 bool IsHandledURL(const GURL
& url
) const override
{
96 return url
.SchemeIs("http");
99 bool IsSafeRedirectTarget(const GURL
& location
) const override
{
104 mutable net::URLRequestJob
* job_
;
107 class AppCacheURLRequestJobTest
: public testing::Test
{
110 // Test Harness -------------------------------------------------------------
111 // TODO(michaeln): share this test harness with AppCacheResponseTest
113 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
115 explicit MockStorageDelegate(AppCacheURLRequestJobTest
* test
)
116 : loaded_info_id_(0), test_(test
) {
119 void OnResponseInfoLoaded(AppCacheResponseInfo
* info
,
120 int64 response_id
) override
{
122 loaded_info_id_
= response_id
;
123 test_
->ScheduleNextTask();
126 scoped_refptr
<AppCacheResponseInfo
> loaded_info_
;
127 int64 loaded_info_id_
;
128 AppCacheURLRequestJobTest
* test_
;
131 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
133 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest
* test
)
135 received_data_(new net::IOBuffer(kNumBlocks
* kBlockSize
)),
136 did_receive_headers_(false), amount_received_(0),
137 kill_after_amount_received_(0), kill_with_io_pending_(false) {
140 void OnResponseStarted(net::URLRequest
* request
) override
{
141 amount_received_
= 0;
142 did_receive_headers_
= false;
143 if (request
->status().is_success()) {
144 EXPECT_TRUE(request
->response_headers());
145 did_receive_headers_
= true;
146 received_info_
= request
->response_info();
153 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{
154 if (bytes_read
> 0) {
155 amount_received_
+= bytes_read
;
157 if (kill_after_amount_received_
&& !kill_with_io_pending_
) {
158 if (amount_received_
>= kill_after_amount_received_
) {
166 if (kill_after_amount_received_
&& kill_with_io_pending_
) {
167 if (amount_received_
>= kill_after_amount_received_
) {
177 void ReadSome(net::URLRequest
* request
) {
178 DCHECK(amount_received_
+ kBlockSize
<= kNumBlocks
* kBlockSize
);
179 scoped_refptr
<IOBuffer
> wrapped_buffer(
180 new net::WrappedIOBuffer(received_data_
->data() + amount_received_
));
183 request
->Read(wrapped_buffer
.get(), kBlockSize
, &bytes_read
));
184 EXPECT_EQ(0, bytes_read
);
187 void RequestComplete() {
188 test_
->ScheduleNextTask();
191 AppCacheURLRequestJobTest
* test_
;
192 net::HttpResponseInfo received_info_
;
193 scoped_refptr
<net::IOBuffer
> received_data_
;
194 bool did_receive_headers_
;
195 int amount_received_
;
196 int kill_after_amount_received_
;
197 bool kill_with_io_pending_
;
200 // Helper callback to run a test on our io_thread. The io_thread is spun up
201 // once and reused for all tests.
202 template <class Method
>
203 void MethodWrapper(Method method
) {
208 static void SetUpTestCase() {
209 io_thread_
.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
210 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
211 io_thread_
->StartWithOptions(options
);
214 static void TearDownTestCase() {
215 io_thread_
.reset(NULL
);
218 AppCacheURLRequestJobTest() {}
220 template <class Method
>
221 void RunTestOnIOThread(Method method
) {
222 test_finished_event_
.reset(new base::WaitableEvent(false, false));
223 io_thread_
->task_runner()->PostTask(
224 FROM_HERE
, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper
<Method
>,
225 base::Unretained(this), method
));
226 test_finished_event_
->Wait();
230 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
231 DCHECK(task_stack_
.empty());
233 storage_delegate_
.reset(new MockStorageDelegate(this));
234 service_
.reset(new MockAppCacheService());
235 expected_read_result_
= 0;
236 expected_write_result_
= 0;
237 written_response_id_
= 0;
238 reader_deletion_count_down_
= 0;
239 writer_deletion_count_down_
= 0;
241 url_request_delegate_
.reset(new MockURLRequestDelegate(this));
242 job_factory_
.reset(new MockURLRequestJobFactory());
243 empty_context_
.reset(new net::URLRequestContext());
244 empty_context_
->set_job_factory(job_factory_
.get());
247 void TearDownTest() {
248 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
251 while (!task_stack_
.empty())
256 read_info_buffer_
= NULL
;
258 write_buffer_
= NULL
;
259 write_info_buffer_
= NULL
;
260 storage_delegate_
.reset();
263 DCHECK(!job_factory_
->has_job());
264 empty_context_
.reset();
265 job_factory_
.reset();
266 url_request_delegate_
.reset();
269 void TestFinished() {
270 // We unwind the stack prior to finishing up to let stack
271 // based objects get deleted.
272 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
273 base::ThreadTaskRunnerHandle::Get()->PostTask(
274 FROM_HERE
, base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound
,
275 base::Unretained(this)));
278 void TestFinishedUnwound() {
280 test_finished_event_
->Signal();
283 void PushNextTask(const base::Closure
& task
) {
284 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, false));
287 void PushNextTaskAsImmediate(const base::Closure
& task
) {
288 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, true));
291 void ScheduleNextTask() {
292 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
293 if (task_stack_
.empty()) {
297 base::Closure task
=task_stack_
.top().first
;
298 bool immediate
= task_stack_
.top().second
;
303 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, task
);
306 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
308 void WriteBasicResponse() {
309 scoped_refptr
<IOBuffer
> body(new WrappedIOBuffer(kHttpBasicBody
));
310 std::string
raw_headers(kHttpBasicHeaders
, arraysize(kHttpBasicHeaders
));
312 MakeHttpResponseInfo(raw_headers
), body
.get(), strlen(kHttpBasicBody
));
315 void WriteResponse(net::HttpResponseInfo
* head
,
316 IOBuffer
* body
, int body_len
) {
318 scoped_refptr
<IOBuffer
> body_ref(body
);
319 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody
,
320 base::Unretained(this), body_ref
, body_len
));
321 WriteResponseHead(head
);
324 void WriteResponseHead(net::HttpResponseInfo
* head
) {
325 EXPECT_FALSE(writer_
->IsWritePending());
326 expected_write_result_
= GetHttpResponseInfoSize(head
);
327 write_info_buffer_
= new HttpResponseInfoIOBuffer(head
);
329 write_info_buffer_
.get(),
330 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete
,
331 base::Unretained(this)));
334 void WriteResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
335 EXPECT_FALSE(writer_
->IsWritePending());
336 write_buffer_
= io_buffer
;
337 expected_write_result_
= buf_len
;
338 writer_
->WriteData(write_buffer_
.get(),
340 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete
,
341 base::Unretained(this)));
344 void ReadResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
345 EXPECT_FALSE(reader_
->IsReadPending());
346 read_buffer_
= io_buffer
;
347 expected_read_result_
= buf_len
;
348 reader_
->ReadData(read_buffer_
.get(),
350 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete
,
351 base::Unretained(this)));
354 // AppCacheResponseReader / Writer completion callbacks
356 void OnWriteInfoComplete(int result
) {
357 EXPECT_FALSE(writer_
->IsWritePending());
358 EXPECT_EQ(expected_write_result_
, result
);
362 void OnWriteComplete(int result
) {
363 EXPECT_FALSE(writer_
->IsWritePending());
364 EXPECT_EQ(expected_write_result_
, result
);
368 void OnReadInfoComplete(int result
) {
369 EXPECT_FALSE(reader_
->IsReadPending());
370 EXPECT_EQ(expected_read_result_
, result
);
374 void OnReadComplete(int result
) {
375 EXPECT_FALSE(reader_
->IsReadPending());
376 EXPECT_EQ(expected_read_result_
, result
);
380 // Helpers to work with HttpResponseInfo objects
382 net::HttpResponseInfo
* MakeHttpResponseInfo(const std::string
& raw_headers
) {
383 net::HttpResponseInfo
* info
= new net::HttpResponseInfo
;
384 info
->request_time
= base::Time::Now();
385 info
->response_time
= base::Time::Now();
386 info
->was_cached
= false;
387 info
->headers
= new net::HttpResponseHeaders(raw_headers
);
391 int GetHttpResponseInfoSize(const net::HttpResponseInfo
* info
) {
393 return PickleHttpResonseInfo(&pickle
, info
);
396 bool CompareHttpResponseInfos(const net::HttpResponseInfo
* info1
,
397 const net::HttpResponseInfo
* info2
) {
398 base::Pickle pickle1
;
399 base::Pickle pickle2
;
400 PickleHttpResonseInfo(&pickle1
, info1
);
401 PickleHttpResonseInfo(&pickle2
, info2
);
402 return (pickle1
.size() == pickle2
.size()) &&
403 (0 == memcmp(pickle1
.data(), pickle2
.data(), pickle1
.size()));
406 int PickleHttpResonseInfo(base::Pickle
* pickle
,
407 const net::HttpResponseInfo
* info
) {
408 const bool kSkipTransientHeaders
= true;
409 const bool kTruncated
= false;
410 info
->Persist(pickle
, kSkipTransientHeaders
, kTruncated
);
411 return pickle
->size();
414 // Helpers to fill and verify blocks of memory with a value
416 void FillData(char value
, char* data
, int data_len
) {
417 memset(data
, value
, data_len
);
420 bool CheckData(char value
, const char* data
, int data_len
) {
421 for (int i
= 0; i
< data_len
; ++i
, ++data
) {
428 // Individual Tests ---------------------------------------------------------
429 // Some of the individual tests involve multiple async steps. Each test
430 // is delineated with a section header.
432 // Basic -------------------------------------------------------------------
434 AppCacheStorage
* storage
= service_
->storage();
435 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
436 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
));
437 scoped_refptr
<AppCacheURLRequestJob
> job
;
439 // Create an instance and see that it looks as expected.
441 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
442 EXPECT_TRUE(job
->is_waiting());
443 EXPECT_FALSE(job
->is_delivering_appcache_response());
444 EXPECT_FALSE(job
->is_delivering_network_response());
445 EXPECT_FALSE(job
->is_delivering_error_response());
446 EXPECT_FALSE(job
->has_been_started());
447 EXPECT_FALSE(job
->has_been_killed());
448 EXPECT_EQ(GURL(), job
->manifest_url());
449 EXPECT_EQ(kAppCacheNoCacheId
, job
->cache_id());
450 EXPECT_FALSE(job
->entry().has_response_id());
455 // DeliveryOrders -----------------------------------------------------
456 void DeliveryOrders() {
457 AppCacheStorage
* storage
= service_
->storage();
458 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
459 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
));
460 scoped_refptr
<AppCacheURLRequestJob
> job
;
462 // Create an instance, give it a delivery order and see that
463 // it looks as expected.
465 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
466 job
->DeliverErrorResponse();
467 EXPECT_TRUE(job
->is_delivering_error_response());
468 EXPECT_FALSE(job
->has_been_started());
470 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
471 job
->DeliverNetworkResponse();
472 EXPECT_TRUE(job
->is_delivering_network_response());
473 EXPECT_FALSE(job
->has_been_started());
475 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
476 const GURL
kManifestUrl("http://blah/");
477 const int64
kCacheId(1);
478 const int64
kGroupId(1);
479 const AppCacheEntry
kEntry(AppCacheEntry::EXPLICIT
, 1);
480 job
->DeliverAppCachedResponse(kManifestUrl
, kCacheId
, kGroupId
,
482 EXPECT_FALSE(job
->is_waiting());
483 EXPECT_TRUE(job
->is_delivering_appcache_response());
484 EXPECT_FALSE(job
->has_been_started());
485 EXPECT_EQ(kManifestUrl
, job
->manifest_url());
486 EXPECT_EQ(kCacheId
, job
->cache_id());
487 EXPECT_EQ(kGroupId
, job
->group_id());
488 EXPECT_EQ(kEntry
.types(), job
->entry().types());
489 EXPECT_EQ(kEntry
.response_id(), job
->entry().response_id());
494 // DeliverNetworkResponse --------------------------------------------------
496 void DeliverNetworkResponse() {
497 // This test has async steps.
499 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse
,
500 base::Unretained(this)));
502 AppCacheStorage
* storage
= service_
->storage();
503 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
504 net::DEFAULT_PRIORITY
,
505 url_request_delegate_
.get());
507 // Setup to create an AppCacheURLRequestJob with orders to deliver
508 // a network response.
509 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
510 request_
.get(), NULL
, storage
, NULL
, false);
511 job_factory_
->SetJob(mock_job
);
512 mock_job
->DeliverNetworkResponse();
513 EXPECT_TRUE(mock_job
->is_delivering_network_response());
514 EXPECT_FALSE(mock_job
->has_been_started());
516 // Start the request.
519 // The job should have been picked up.
520 EXPECT_FALSE(job_factory_
->has_job());
521 // Completion is async.
524 void VerifyDeliverNetworkResponse() {
525 EXPECT_EQ(request_
->status().error(),
526 net::ERR_INTERNET_DISCONNECTED
);
530 // DeliverErrorResponse --------------------------------------------------
532 void DeliverErrorResponse() {
533 // This test has async steps.
535 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse
,
536 base::Unretained(this)));
538 AppCacheStorage
* storage
= service_
->storage();
539 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
540 net::DEFAULT_PRIORITY
,
541 url_request_delegate_
.get());
543 // Setup to create an AppCacheURLRequestJob with orders to deliver
544 // a network response.
545 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
546 request_
.get(), NULL
, storage
, NULL
, false);
547 job_factory_
->SetJob(mock_job
);
548 mock_job
->DeliverErrorResponse();
549 EXPECT_TRUE(mock_job
->is_delivering_error_response());
550 EXPECT_FALSE(mock_job
->has_been_started());
552 // Start the request.
555 // The job should have been picked up.
556 EXPECT_FALSE(job_factory_
->has_job());
557 // Completion is async.
560 void VerifyDeliverErrorResponse() {
561 EXPECT_EQ(request_
->status().error(), net::ERR_FAILED
);
565 // DeliverSmallAppCachedResponse --------------------------------------
566 // "Small" being small enough to read completely in a single
567 // request->Read call.
569 void DeliverSmallAppCachedResponse() {
570 // This test has several async steps.
571 // 1. Write a small response to response storage.
572 // 2. Use net::URLRequest to retrieve it.
573 // 3. Verify we received what we expected to receive.
575 PushNextTask(base::Bind(
576 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse
,
577 base::Unretained(this)));
579 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource
,
580 base::Unretained(this), false));
582 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
583 written_response_id_
= writer_
->response_id();
584 WriteBasicResponse();
588 void RequestAppCachedResource(bool start_after_delivery_orders
) {
589 AppCacheStorage
* storage
= service_
->storage();
590 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
591 net::DEFAULT_PRIORITY
,
592 url_request_delegate_
.get());
594 // Setup to create an AppCacheURLRequestJob with orders to deliver
595 // a network response.
596 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
597 request_
.get(), NULL
, storage
, NULL
, false));
599 if (start_after_delivery_orders
) {
600 job
->DeliverAppCachedResponse(
602 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
604 EXPECT_TRUE(job
->is_delivering_appcache_response());
607 // Start the request.
608 EXPECT_FALSE(job
->has_been_started());
609 job_factory_
->SetJob(job
.get());
611 EXPECT_FALSE(job_factory_
->has_job());
612 EXPECT_TRUE(job
->has_been_started());
614 if (!start_after_delivery_orders
) {
615 job
->DeliverAppCachedResponse(
617 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
619 EXPECT_TRUE(job
->is_delivering_appcache_response());
622 // Completion is async.
625 void VerifyDeliverSmallAppCachedResponse() {
626 EXPECT_TRUE(request_
->status().is_success());
627 EXPECT_TRUE(CompareHttpResponseInfos(
628 write_info_buffer_
->http_info
.get(),
629 &url_request_delegate_
->received_info_
));
630 EXPECT_EQ(5, url_request_delegate_
->amount_received_
);
631 EXPECT_EQ(0, memcmp(kHttpBasicBody
,
632 url_request_delegate_
->received_data_
->data(),
633 strlen(kHttpBasicBody
)));
637 // DeliverLargeAppCachedResponse --------------------------------------
638 // "Large" enough to require multiple calls to request->Read to complete.
640 void DeliverLargeAppCachedResponse() {
641 // This test has several async steps.
642 // 1. Write a large response to response storage.
643 // 2. Use net::URLRequest to retrieve it.
644 // 3. Verify we received what we expected to receive.
646 PushNextTask(base::Bind(
647 &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse
,
648 base::Unretained(this)));
649 PushNextTask(base::Bind(
650 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
651 base::Unretained(this), true));
653 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
654 written_response_id_
= writer_
->response_id();
655 WriteLargeResponse();
659 void WriteLargeResponse() {
661 static const char kHttpHeaders
[] =
662 "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
663 scoped_refptr
<IOBuffer
> body(new IOBuffer(kBlockSize
* 3));
664 char* p
= body
->data();
665 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
666 FillData(i
+ 1, p
, kBlockSize
);
667 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
669 MakeHttpResponseInfo(raw_headers
), body
.get(), kBlockSize
* 3);
672 void VerifyDeliverLargeAppCachedResponse() {
673 EXPECT_TRUE(request_
->status().is_success());
674 EXPECT_TRUE(CompareHttpResponseInfos(
675 write_info_buffer_
->http_info
.get(),
676 &url_request_delegate_
->received_info_
));
677 EXPECT_EQ(3072, url_request_delegate_
->amount_received_
);
678 char* p
= url_request_delegate_
->received_data_
->data();
679 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
680 EXPECT_TRUE(CheckData(i
+ 1, p
, kBlockSize
));
684 // DeliverPartialResponse --------------------------------------
686 void DeliverPartialResponse() {
687 // This test has several async steps.
688 // 1. Write a small response to response storage.
689 // 2. Use net::URLRequest to retrieve it a subset using a range request
690 // 3. Verify we received what we expected to receive.
691 PushNextTask(base::Bind(
692 &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse
,
693 base::Unretained(this)));
694 PushNextTask(base::Bind(
695 &AppCacheURLRequestJobTest::MakeRangeRequest
, base::Unretained(this)));
696 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
697 written_response_id_
= writer_
->response_id();
698 WriteBasicResponse();
702 void MakeRangeRequest() {
703 AppCacheStorage
* storage
= service_
->storage();
704 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
705 net::DEFAULT_PRIORITY
,
706 url_request_delegate_
.get());
708 // Request a range, the 3 middle chars out of 'Hello'
709 net::HttpRequestHeaders extra_headers
;
710 extra_headers
.SetHeader("Range", "bytes= 1-3");
711 request_
->SetExtraRequestHeaders(extra_headers
);
713 // Create job with orders to deliver an appcached entry.
714 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
715 request_
.get(), NULL
, storage
, NULL
, false));
716 job
->DeliverAppCachedResponse(
718 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
720 EXPECT_TRUE(job
->is_delivering_appcache_response());
722 // Start the request.
723 EXPECT_FALSE(job
->has_been_started());
724 job_factory_
->SetJob(job
.get());
726 EXPECT_FALSE(job_factory_
->has_job());
727 EXPECT_TRUE(job
->has_been_started());
728 // Completion is async.
731 void VerifyDeliverPartialResponse() {
732 EXPECT_TRUE(request_
->status().is_success());
733 EXPECT_EQ(3, url_request_delegate_
->amount_received_
);
734 EXPECT_EQ(0, memcmp(kHttpBasicBody
+ 1,
735 url_request_delegate_
->received_data_
->data(),
737 net::HttpResponseHeaders
* headers
=
738 url_request_delegate_
->received_info_
.headers
.get();
739 EXPECT_EQ(206, headers
->response_code());
740 EXPECT_EQ(3, headers
->GetContentLength());
741 int64 range_start
, range_end
, object_size
;
743 headers
->GetContentRange(&range_start
, &range_end
, &object_size
));
744 EXPECT_EQ(1, range_start
);
745 EXPECT_EQ(3, range_end
);
746 EXPECT_EQ(5, object_size
);
750 // CancelRequest --------------------------------------
752 void CancelRequest() {
753 // This test has several async steps.
754 // 1. Write a large response to response storage.
755 // 2. Use net::URLRequest to retrieve it.
756 // 3. Cancel the request after data starts coming in.
758 PushNextTask(base::Bind(
759 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
760 PushNextTask(base::Bind(
761 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
762 base::Unretained(this), true));
764 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
765 written_response_id_
= writer_
->response_id();
766 WriteLargeResponse();
768 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
769 url_request_delegate_
->kill_with_io_pending_
= false;
773 void VerifyCancel() {
774 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
775 request_
->status().status());
779 // CancelRequestWithIOPending --------------------------------------
781 void CancelRequestWithIOPending() {
782 // This test has several async steps.
783 // 1. Write a large response to response storage.
784 // 2. Use net::URLRequest to retrieve it.
785 // 3. Cancel the request after data starts coming in.
787 PushNextTask(base::Bind(
788 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
789 PushNextTask(base::Bind(
790 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
791 base::Unretained(this), true));
793 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
794 written_response_id_
= writer_
->response_id();
795 WriteLargeResponse();
797 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
798 url_request_delegate_
->kill_with_io_pending_
= true;
803 // Data members --------------------------------------------------------
805 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
806 scoped_ptr
<MockStorageDelegate
> storage_delegate_
;
807 scoped_ptr
<MockAppCacheService
> service_
;
808 std::stack
<std::pair
<base::Closure
, bool> > task_stack_
;
810 scoped_ptr
<AppCacheResponseReader
> reader_
;
811 scoped_refptr
<HttpResponseInfoIOBuffer
> read_info_buffer_
;
812 scoped_refptr
<IOBuffer
> read_buffer_
;
813 int expected_read_result_
;
814 int reader_deletion_count_down_
;
816 int64 written_response_id_
;
817 scoped_ptr
<AppCacheResponseWriter
> writer_
;
818 scoped_refptr
<HttpResponseInfoIOBuffer
> write_info_buffer_
;
819 scoped_refptr
<IOBuffer
> write_buffer_
;
820 int expected_write_result_
;
821 int writer_deletion_count_down_
;
823 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
824 scoped_ptr
<net::URLRequestContext
> empty_context_
;
825 scoped_ptr
<net::URLRequest
> request_
;
826 scoped_ptr
<MockURLRequestDelegate
> url_request_delegate_
;
828 static scoped_ptr
<base::Thread
> io_thread_
;
832 scoped_ptr
<base::Thread
> AppCacheURLRequestJobTest::io_thread_
;
834 TEST_F(AppCacheURLRequestJobTest
, Basic
) {
835 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic
);
838 TEST_F(AppCacheURLRequestJobTest
, DeliveryOrders
) {
839 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders
);
842 TEST_F(AppCacheURLRequestJobTest
, DeliverNetworkResponse
) {
843 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse
);
846 TEST_F(AppCacheURLRequestJobTest
, DeliverErrorResponse
) {
847 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse
);
850 TEST_F(AppCacheURLRequestJobTest
, DeliverSmallAppCachedResponse
) {
851 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse
);
854 TEST_F(AppCacheURLRequestJobTest
, DeliverLargeAppCachedResponse
) {
855 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse
);
858 TEST_F(AppCacheURLRequestJobTest
, DeliverPartialResponse
) {
859 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse
);
862 TEST_F(AppCacheURLRequestJobTest
, CancelRequest
) {
863 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest
);
866 TEST_F(AppCacheURLRequestJobTest
, CancelRequestWithIOPending
) {
867 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending
);
872 } // namespace content