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/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/pickle.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/threading/thread.h"
17 #include "content/browser/appcache/appcache_response.h"
18 #include "content/browser/appcache/appcache_url_request_job.h"
19 #include "content/browser/appcache/mock_appcache_service.h"
20 #include "net/base/io_buffer.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 using net::WrappedIOBuffer
;
38 const char kHttpBasicHeaders
[] = "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
39 const char kHttpBasicBody
[] = "Hello";
41 const int kNumBlocks
= 4;
42 const int kBlockSize
= 1024;
44 class MockURLRequestJobFactory
: public net::URLRequestJobFactory
{
46 MockURLRequestJobFactory() : job_(NULL
) {
49 ~MockURLRequestJobFactory() override
{ DCHECK(!job_
); }
51 void SetJob(net::URLRequestJob
* job
) {
55 bool has_job() const {
59 // net::URLRequestJobFactory implementation.
60 net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
61 const std::string
& scheme
,
62 net::URLRequest
* request
,
63 net::NetworkDelegate
* network_delegate
) const override
{
65 net::URLRequestJob
* temp
= job_
;
69 return new net::URLRequestErrorJob(request
,
71 net::ERR_INTERNET_DISCONNECTED
);
75 net::URLRequestJob
* MaybeInterceptRedirect(
76 net::URLRequest
* request
,
77 net::NetworkDelegate
* network_delegate
,
78 const GURL
& location
) const override
{
82 net::URLRequestJob
* MaybeInterceptResponse(
83 net::URLRequest
* request
,
84 net::NetworkDelegate
* network_delegate
) const override
{
88 bool IsHandledProtocol(const std::string
& scheme
) const override
{
89 return scheme
== "http";
92 bool IsHandledURL(const GURL
& url
) const override
{
93 return url
.SchemeIs("http");
96 bool IsSafeRedirectTarget(const GURL
& location
) const override
{
101 mutable net::URLRequestJob
* job_
;
104 class AppCacheURLRequestJobTest
: public testing::Test
{
107 // Test Harness -------------------------------------------------------------
108 // TODO(michaeln): share this test harness with AppCacheResponseTest
110 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
112 explicit MockStorageDelegate(AppCacheURLRequestJobTest
* test
)
113 : loaded_info_id_(0), test_(test
) {
116 void OnResponseInfoLoaded(AppCacheResponseInfo
* info
,
117 int64 response_id
) override
{
119 loaded_info_id_
= response_id
;
120 test_
->ScheduleNextTask();
123 scoped_refptr
<AppCacheResponseInfo
> loaded_info_
;
124 int64 loaded_info_id_
;
125 AppCacheURLRequestJobTest
* test_
;
128 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
130 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest
* test
)
132 received_data_(new net::IOBuffer(kNumBlocks
* kBlockSize
)),
133 did_receive_headers_(false), amount_received_(0),
134 kill_after_amount_received_(0), kill_with_io_pending_(false) {
137 void OnResponseStarted(net::URLRequest
* request
) override
{
138 amount_received_
= 0;
139 did_receive_headers_
= false;
140 if (request
->status().is_success()) {
141 EXPECT_TRUE(request
->response_headers());
142 did_receive_headers_
= true;
143 received_info_
= request
->response_info();
150 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{
151 if (bytes_read
> 0) {
152 amount_received_
+= bytes_read
;
154 if (kill_after_amount_received_
&& !kill_with_io_pending_
) {
155 if (amount_received_
>= kill_after_amount_received_
) {
163 if (kill_after_amount_received_
&& kill_with_io_pending_
) {
164 if (amount_received_
>= kill_after_amount_received_
) {
174 void ReadSome(net::URLRequest
* request
) {
175 DCHECK(amount_received_
+ kBlockSize
<= kNumBlocks
* kBlockSize
);
176 scoped_refptr
<IOBuffer
> wrapped_buffer(
177 new net::WrappedIOBuffer(received_data_
->data() + amount_received_
));
180 request
->Read(wrapped_buffer
.get(), kBlockSize
, &bytes_read
));
181 EXPECT_EQ(0, bytes_read
);
184 void RequestComplete() {
185 test_
->ScheduleNextTask();
188 AppCacheURLRequestJobTest
* test_
;
189 net::HttpResponseInfo received_info_
;
190 scoped_refptr
<net::IOBuffer
> received_data_
;
191 bool did_receive_headers_
;
192 int amount_received_
;
193 int kill_after_amount_received_
;
194 bool kill_with_io_pending_
;
197 // Helper callback to run a test on our io_thread. The io_thread is spun up
198 // once and reused for all tests.
199 template <class Method
>
200 void MethodWrapper(Method method
) {
205 static void SetUpTestCase() {
206 io_thread_
.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
207 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
208 io_thread_
->StartWithOptions(options
);
211 static void TearDownTestCase() {
212 io_thread_
.reset(NULL
);
215 AppCacheURLRequestJobTest() {}
217 template <class Method
>
218 void RunTestOnIOThread(Method method
) {
219 test_finished_event_
.reset(new base::WaitableEvent(false, false));
220 io_thread_
->message_loop()->PostTask(
221 FROM_HERE
, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper
<Method
>,
222 base::Unretained(this), method
));
223 test_finished_event_
->Wait();
227 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
228 DCHECK(task_stack_
.empty());
230 storage_delegate_
.reset(new MockStorageDelegate(this));
231 service_
.reset(new MockAppCacheService());
232 expected_read_result_
= 0;
233 expected_write_result_
= 0;
234 written_response_id_
= 0;
235 reader_deletion_count_down_
= 0;
236 writer_deletion_count_down_
= 0;
238 url_request_delegate_
.reset(new MockURLRequestDelegate(this));
239 job_factory_
.reset(new MockURLRequestJobFactory());
240 empty_context_
.reset(new net::URLRequestContext());
241 empty_context_
->set_job_factory(job_factory_
.get());
244 void TearDownTest() {
245 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
248 while (!task_stack_
.empty())
253 read_info_buffer_
= NULL
;
255 write_buffer_
= NULL
;
256 write_info_buffer_
= NULL
;
257 storage_delegate_
.reset();
260 DCHECK(!job_factory_
->has_job());
261 empty_context_
.reset();
262 job_factory_
.reset();
263 url_request_delegate_
.reset();
266 void TestFinished() {
267 // We unwind the stack prior to finishing up to let stack
268 // based objects get deleted.
269 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
270 base::MessageLoop::current()->PostTask(
272 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound
,
273 base::Unretained(this)));
276 void TestFinishedUnwound() {
278 test_finished_event_
->Signal();
281 void PushNextTask(const base::Closure
& task
) {
282 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, false));
285 void PushNextTaskAsImmediate(const base::Closure
& task
) {
286 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, true));
289 void ScheduleNextTask() {
290 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
291 if (task_stack_
.empty()) {
295 base::Closure task
=task_stack_
.top().first
;
296 bool immediate
= task_stack_
.top().second
;
301 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
304 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
306 void WriteBasicResponse() {
307 scoped_refptr
<IOBuffer
> body(new WrappedIOBuffer(kHttpBasicBody
));
308 std::string
raw_headers(kHttpBasicHeaders
, arraysize(kHttpBasicHeaders
));
310 MakeHttpResponseInfo(raw_headers
), body
.get(), strlen(kHttpBasicBody
));
313 void WriteResponse(net::HttpResponseInfo
* head
,
314 IOBuffer
* body
, int body_len
) {
316 scoped_refptr
<IOBuffer
> body_ref(body
);
317 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody
,
318 base::Unretained(this), body_ref
, body_len
));
319 WriteResponseHead(head
);
322 void WriteResponseHead(net::HttpResponseInfo
* head
) {
323 EXPECT_FALSE(writer_
->IsWritePending());
324 expected_write_result_
= GetHttpResponseInfoSize(head
);
325 write_info_buffer_
= new HttpResponseInfoIOBuffer(head
);
327 write_info_buffer_
.get(),
328 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete
,
329 base::Unretained(this)));
332 void WriteResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
333 EXPECT_FALSE(writer_
->IsWritePending());
334 write_buffer_
= io_buffer
;
335 expected_write_result_
= buf_len
;
336 writer_
->WriteData(write_buffer_
.get(),
338 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete
,
339 base::Unretained(this)));
342 void ReadResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
343 EXPECT_FALSE(reader_
->IsReadPending());
344 read_buffer_
= io_buffer
;
345 expected_read_result_
= buf_len
;
346 reader_
->ReadData(read_buffer_
.get(),
348 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete
,
349 base::Unretained(this)));
352 // AppCacheResponseReader / Writer completion callbacks
354 void OnWriteInfoComplete(int result
) {
355 EXPECT_FALSE(writer_
->IsWritePending());
356 EXPECT_EQ(expected_write_result_
, result
);
360 void OnWriteComplete(int result
) {
361 EXPECT_FALSE(writer_
->IsWritePending());
362 EXPECT_EQ(expected_write_result_
, result
);
366 void OnReadInfoComplete(int result
) {
367 EXPECT_FALSE(reader_
->IsReadPending());
368 EXPECT_EQ(expected_read_result_
, result
);
372 void OnReadComplete(int result
) {
373 EXPECT_FALSE(reader_
->IsReadPending());
374 EXPECT_EQ(expected_read_result_
, result
);
378 // Helpers to work with HttpResponseInfo objects
380 net::HttpResponseInfo
* MakeHttpResponseInfo(const std::string
& raw_headers
) {
381 net::HttpResponseInfo
* info
= new net::HttpResponseInfo
;
382 info
->request_time
= base::Time::Now();
383 info
->response_time
= base::Time::Now();
384 info
->was_cached
= false;
385 info
->headers
= new net::HttpResponseHeaders(raw_headers
);
389 int GetHttpResponseInfoSize(const net::HttpResponseInfo
* info
) {
391 return PickleHttpResonseInfo(&pickle
, info
);
394 bool CompareHttpResponseInfos(const net::HttpResponseInfo
* info1
,
395 const net::HttpResponseInfo
* info2
) {
398 PickleHttpResonseInfo(&pickle1
, info1
);
399 PickleHttpResonseInfo(&pickle2
, info2
);
400 return (pickle1
.size() == pickle2
.size()) &&
401 (0 == memcmp(pickle1
.data(), pickle2
.data(), pickle1
.size()));
404 int PickleHttpResonseInfo(Pickle
* pickle
, const net::HttpResponseInfo
* info
) {
405 const bool kSkipTransientHeaders
= true;
406 const bool kTruncated
= false;
407 info
->Persist(pickle
, kSkipTransientHeaders
, kTruncated
);
408 return pickle
->size();
411 // Helpers to fill and verify blocks of memory with a value
413 void FillData(char value
, char* data
, int data_len
) {
414 memset(data
, value
, data_len
);
417 bool CheckData(char value
, const char* data
, int data_len
) {
418 for (int i
= 0; i
< data_len
; ++i
, ++data
) {
425 // Individual Tests ---------------------------------------------------------
426 // Some of the individual tests involve multiple async steps. Each test
427 // is delineated with a section header.
429 // Basic -------------------------------------------------------------------
431 AppCacheStorage
* storage
= service_
->storage();
432 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
433 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
));
434 scoped_refptr
<AppCacheURLRequestJob
> job
;
436 // Create an instance and see that it looks as expected.
438 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
439 EXPECT_TRUE(job
->is_waiting());
440 EXPECT_FALSE(job
->is_delivering_appcache_response());
441 EXPECT_FALSE(job
->is_delivering_network_response());
442 EXPECT_FALSE(job
->is_delivering_error_response());
443 EXPECT_FALSE(job
->has_been_started());
444 EXPECT_FALSE(job
->has_been_killed());
445 EXPECT_EQ(GURL(), job
->manifest_url());
446 EXPECT_EQ(kAppCacheNoCacheId
, job
->cache_id());
447 EXPECT_FALSE(job
->entry().has_response_id());
452 // DeliveryOrders -----------------------------------------------------
453 void DeliveryOrders() {
454 AppCacheStorage
* storage
= service_
->storage();
455 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
456 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
));
457 scoped_refptr
<AppCacheURLRequestJob
> job
;
459 // Create an instance, give it a delivery order and see that
460 // it looks as expected.
462 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
463 job
->DeliverErrorResponse();
464 EXPECT_TRUE(job
->is_delivering_error_response());
465 EXPECT_FALSE(job
->has_been_started());
467 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
468 job
->DeliverNetworkResponse();
469 EXPECT_TRUE(job
->is_delivering_network_response());
470 EXPECT_FALSE(job
->has_been_started());
472 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
473 const GURL
kManifestUrl("http://blah/");
474 const int64
kCacheId(1);
475 const int64
kGroupId(1);
476 const AppCacheEntry
kEntry(AppCacheEntry::EXPLICIT
, 1);
477 job
->DeliverAppCachedResponse(kManifestUrl
, kCacheId
, kGroupId
,
479 EXPECT_FALSE(job
->is_waiting());
480 EXPECT_TRUE(job
->is_delivering_appcache_response());
481 EXPECT_FALSE(job
->has_been_started());
482 EXPECT_EQ(kManifestUrl
, job
->manifest_url());
483 EXPECT_EQ(kCacheId
, job
->cache_id());
484 EXPECT_EQ(kGroupId
, job
->group_id());
485 EXPECT_EQ(kEntry
.types(), job
->entry().types());
486 EXPECT_EQ(kEntry
.response_id(), job
->entry().response_id());
491 // DeliverNetworkResponse --------------------------------------------------
493 void DeliverNetworkResponse() {
494 // This test has async steps.
496 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse
,
497 base::Unretained(this)));
499 AppCacheStorage
* storage
= service_
->storage();
500 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
501 net::DEFAULT_PRIORITY
,
502 url_request_delegate_
.get());
504 // Setup to create an AppCacheURLRequestJob with orders to deliver
505 // a network response.
506 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
507 request_
.get(), NULL
, storage
, NULL
, false);
508 job_factory_
->SetJob(mock_job
);
509 mock_job
->DeliverNetworkResponse();
510 EXPECT_TRUE(mock_job
->is_delivering_network_response());
511 EXPECT_FALSE(mock_job
->has_been_started());
513 // Start the request.
516 // The job should have been picked up.
517 EXPECT_FALSE(job_factory_
->has_job());
518 // Completion is async.
521 void VerifyDeliverNetworkResponse() {
522 EXPECT_EQ(request_
->status().error(),
523 net::ERR_INTERNET_DISCONNECTED
);
527 // DeliverErrorResponse --------------------------------------------------
529 void DeliverErrorResponse() {
530 // This test has async steps.
532 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse
,
533 base::Unretained(this)));
535 AppCacheStorage
* storage
= service_
->storage();
536 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
537 net::DEFAULT_PRIORITY
,
538 url_request_delegate_
.get());
540 // Setup to create an AppCacheURLRequestJob with orders to deliver
541 // a network response.
542 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
543 request_
.get(), NULL
, storage
, NULL
, false);
544 job_factory_
->SetJob(mock_job
);
545 mock_job
->DeliverErrorResponse();
546 EXPECT_TRUE(mock_job
->is_delivering_error_response());
547 EXPECT_FALSE(mock_job
->has_been_started());
549 // Start the request.
552 // The job should have been picked up.
553 EXPECT_FALSE(job_factory_
->has_job());
554 // Completion is async.
557 void VerifyDeliverErrorResponse() {
558 EXPECT_EQ(request_
->status().error(), net::ERR_FAILED
);
562 // DeliverSmallAppCachedResponse --------------------------------------
563 // "Small" being small enough to read completely in a single
564 // request->Read call.
566 void DeliverSmallAppCachedResponse() {
567 // This test has several async steps.
568 // 1. Write a small response to response storage.
569 // 2. Use net::URLRequest to retrieve it.
570 // 3. Verify we received what we expected to receive.
572 PushNextTask(base::Bind(
573 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse
,
574 base::Unretained(this)));
576 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource
,
577 base::Unretained(this), false));
579 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
580 written_response_id_
= writer_
->response_id();
581 WriteBasicResponse();
585 void RequestAppCachedResource(bool start_after_delivery_orders
) {
586 AppCacheStorage
* storage
= service_
->storage();
587 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
588 net::DEFAULT_PRIORITY
,
589 url_request_delegate_
.get());
591 // Setup to create an AppCacheURLRequestJob with orders to deliver
592 // a network response.
593 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
594 request_
.get(), NULL
, storage
, NULL
, false));
596 if (start_after_delivery_orders
) {
597 job
->DeliverAppCachedResponse(
599 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
601 EXPECT_TRUE(job
->is_delivering_appcache_response());
604 // Start the request.
605 EXPECT_FALSE(job
->has_been_started());
606 job_factory_
->SetJob(job
.get());
608 EXPECT_FALSE(job_factory_
->has_job());
609 EXPECT_TRUE(job
->has_been_started());
611 if (!start_after_delivery_orders
) {
612 job
->DeliverAppCachedResponse(
614 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
616 EXPECT_TRUE(job
->is_delivering_appcache_response());
619 // Completion is async.
622 void VerifyDeliverSmallAppCachedResponse() {
623 EXPECT_TRUE(request_
->status().is_success());
624 EXPECT_TRUE(CompareHttpResponseInfos(
625 write_info_buffer_
->http_info
.get(),
626 &url_request_delegate_
->received_info_
));
627 EXPECT_EQ(5, url_request_delegate_
->amount_received_
);
628 EXPECT_EQ(0, memcmp(kHttpBasicBody
,
629 url_request_delegate_
->received_data_
->data(),
630 strlen(kHttpBasicBody
)));
634 // DeliverLargeAppCachedResponse --------------------------------------
635 // "Large" enough to require multiple calls to request->Read to complete.
637 void DeliverLargeAppCachedResponse() {
638 // This test has several async steps.
639 // 1. Write a large response to response storage.
640 // 2. Use net::URLRequest to retrieve it.
641 // 3. Verify we received what we expected to receive.
643 PushNextTask(base::Bind(
644 &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse
,
645 base::Unretained(this)));
646 PushNextTask(base::Bind(
647 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
648 base::Unretained(this), true));
650 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
651 written_response_id_
= writer_
->response_id();
652 WriteLargeResponse();
656 void WriteLargeResponse() {
658 static const char kHttpHeaders
[] =
659 "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
660 scoped_refptr
<IOBuffer
> body(new IOBuffer(kBlockSize
* 3));
661 char* p
= body
->data();
662 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
663 FillData(i
+ 1, p
, kBlockSize
);
664 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
666 MakeHttpResponseInfo(raw_headers
), body
.get(), kBlockSize
* 3);
669 void VerifyDeliverLargeAppCachedResponse() {
670 EXPECT_TRUE(request_
->status().is_success());
671 EXPECT_TRUE(CompareHttpResponseInfos(
672 write_info_buffer_
->http_info
.get(),
673 &url_request_delegate_
->received_info_
));
674 EXPECT_EQ(3072, url_request_delegate_
->amount_received_
);
675 char* p
= url_request_delegate_
->received_data_
->data();
676 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
677 EXPECT_TRUE(CheckData(i
+ 1, p
, kBlockSize
));
681 // DeliverPartialResponse --------------------------------------
683 void DeliverPartialResponse() {
684 // This test has several async steps.
685 // 1. Write a small response to response storage.
686 // 2. Use net::URLRequest to retrieve it a subset using a range request
687 // 3. Verify we received what we expected to receive.
688 PushNextTask(base::Bind(
689 &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse
,
690 base::Unretained(this)));
691 PushNextTask(base::Bind(
692 &AppCacheURLRequestJobTest::MakeRangeRequest
, base::Unretained(this)));
693 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
694 written_response_id_
= writer_
->response_id();
695 WriteBasicResponse();
699 void MakeRangeRequest() {
700 AppCacheStorage
* storage
= service_
->storage();
701 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
702 net::DEFAULT_PRIORITY
,
703 url_request_delegate_
.get());
705 // Request a range, the 3 middle chars out of 'Hello'
706 net::HttpRequestHeaders extra_headers
;
707 extra_headers
.SetHeader("Range", "bytes= 1-3");
708 request_
->SetExtraRequestHeaders(extra_headers
);
710 // Create job with orders to deliver an appcached entry.
711 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
712 request_
.get(), NULL
, storage
, NULL
, false));
713 job
->DeliverAppCachedResponse(
715 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
717 EXPECT_TRUE(job
->is_delivering_appcache_response());
719 // Start the request.
720 EXPECT_FALSE(job
->has_been_started());
721 job_factory_
->SetJob(job
.get());
723 EXPECT_FALSE(job_factory_
->has_job());
724 EXPECT_TRUE(job
->has_been_started());
725 // Completion is async.
728 void VerifyDeliverPartialResponse() {
729 EXPECT_TRUE(request_
->status().is_success());
730 EXPECT_EQ(3, url_request_delegate_
->amount_received_
);
731 EXPECT_EQ(0, memcmp(kHttpBasicBody
+ 1,
732 url_request_delegate_
->received_data_
->data(),
734 net::HttpResponseHeaders
* headers
=
735 url_request_delegate_
->received_info_
.headers
.get();
736 EXPECT_EQ(206, headers
->response_code());
737 EXPECT_EQ(3, headers
->GetContentLength());
738 int64 range_start
, range_end
, object_size
;
740 headers
->GetContentRange(&range_start
, &range_end
, &object_size
));
741 EXPECT_EQ(1, range_start
);
742 EXPECT_EQ(3, range_end
);
743 EXPECT_EQ(5, object_size
);
747 // CancelRequest --------------------------------------
749 void CancelRequest() {
750 // This test has several async steps.
751 // 1. Write a large response to response storage.
752 // 2. Use net::URLRequest to retrieve it.
753 // 3. Cancel the request after data starts coming in.
755 PushNextTask(base::Bind(
756 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
757 PushNextTask(base::Bind(
758 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
759 base::Unretained(this), true));
761 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
762 written_response_id_
= writer_
->response_id();
763 WriteLargeResponse();
765 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
766 url_request_delegate_
->kill_with_io_pending_
= false;
770 void VerifyCancel() {
771 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
772 request_
->status().status());
776 // CancelRequestWithIOPending --------------------------------------
778 void CancelRequestWithIOPending() {
779 // This test has several async steps.
780 // 1. Write a large response to response storage.
781 // 2. Use net::URLRequest to retrieve it.
782 // 3. Cancel the request after data starts coming in.
784 PushNextTask(base::Bind(
785 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
786 PushNextTask(base::Bind(
787 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
788 base::Unretained(this), true));
790 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
791 written_response_id_
= writer_
->response_id();
792 WriteLargeResponse();
794 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
795 url_request_delegate_
->kill_with_io_pending_
= true;
800 // Data members --------------------------------------------------------
802 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
803 scoped_ptr
<MockStorageDelegate
> storage_delegate_
;
804 scoped_ptr
<MockAppCacheService
> service_
;
805 std::stack
<std::pair
<base::Closure
, bool> > task_stack_
;
807 scoped_ptr
<AppCacheResponseReader
> reader_
;
808 scoped_refptr
<HttpResponseInfoIOBuffer
> read_info_buffer_
;
809 scoped_refptr
<IOBuffer
> read_buffer_
;
810 int expected_read_result_
;
811 int reader_deletion_count_down_
;
813 int64 written_response_id_
;
814 scoped_ptr
<AppCacheResponseWriter
> writer_
;
815 scoped_refptr
<HttpResponseInfoIOBuffer
> write_info_buffer_
;
816 scoped_refptr
<IOBuffer
> write_buffer_
;
817 int expected_write_result_
;
818 int writer_deletion_count_down_
;
820 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
821 scoped_ptr
<net::URLRequestContext
> empty_context_
;
822 scoped_ptr
<net::URLRequest
> request_
;
823 scoped_ptr
<MockURLRequestDelegate
> url_request_delegate_
;
825 static scoped_ptr
<base::Thread
> io_thread_
;
829 scoped_ptr
<base::Thread
> AppCacheURLRequestJobTest::io_thread_
;
831 TEST_F(AppCacheURLRequestJobTest
, Basic
) {
832 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic
);
835 TEST_F(AppCacheURLRequestJobTest
, DeliveryOrders
) {
836 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders
);
839 TEST_F(AppCacheURLRequestJobTest
, DeliverNetworkResponse
) {
840 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse
);
843 TEST_F(AppCacheURLRequestJobTest
, DeliverErrorResponse
) {
844 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse
);
847 TEST_F(AppCacheURLRequestJobTest
, DeliverSmallAppCachedResponse
) {
848 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse
);
851 TEST_F(AppCacheURLRequestJobTest
, DeliverLargeAppCachedResponse
) {
852 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse
);
855 TEST_F(AppCacheURLRequestJobTest
, DeliverPartialResponse
) {
856 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse
);
859 TEST_F(AppCacheURLRequestJobTest
, CancelRequest
) {
860 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest
);
863 TEST_F(AppCacheURLRequestJobTest
, CancelRequestWithIOPending
) {
864 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending
);
869 } // namespace content