15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stack> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility> 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/pickle.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_error_job.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/appcache/appcache_response.h" 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/appcache/appcache_url_request_job.h" 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "webkit/browser/appcache/mock_appcache_service.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::IOBuffer; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using net::WrappedIOBuffer; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace appcache { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kHttpBasicHeaders[] = 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.0 200 OK\0Content-Length: 5\0\0"; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kHttpBasicBody[] = "Hello"; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kNumBlocks = 4; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kBlockSize = 1024; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AppCacheURLRequestJobTest : public testing::Test { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Test Harness ------------------------------------------------------------- 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(michaeln): share this test harness with AppCacheResponseTest 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class MockStorageDelegate : public AppCacheStorage::Delegate { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit MockStorageDelegate(AppCacheURLRequestJobTest* test) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : loaded_info_id_(0), test_(test) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info, 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int64 response_id) OVERRIDE { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_info_ = info; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_info_id_ = response_id; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_->ScheduleNextTask(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<AppCacheResponseInfo> loaded_info_; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 loaded_info_id_; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheURLRequestJobTest* test_; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class MockURLRequestDelegate : public net::URLRequest::Delegate { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : test_(test), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) received_data_(new net::IOBuffer(kNumBlocks * kBlockSize)), 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_receive_headers_(false), amount_received_(0), 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kill_after_amount_received_(0), kill_with_io_pending_(false) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) amount_received_ = 0; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_receive_headers_ = false; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request->status().is_success()) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(request->response_headers()); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_receive_headers_ = true; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) received_info_ = request->response_info(); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadSome(request); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequestComplete(); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnReadCompleted(net::URLRequest* request, 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bytes_read) OVERRIDE { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bytes_read > 0) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) amount_received_ += bytes_read; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kill_after_amount_received_ && !kill_with_io_pending_) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (amount_received_ >= kill_after_amount_received_) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request->Cancel(); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadSome(request); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kill_after_amount_received_ && kill_with_io_pending_) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (amount_received_ >= kill_after_amount_received_) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request->Cancel(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequestComplete(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReadSome(net::URLRequest* request) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(amount_received_ + kBlockSize <= kNumBlocks * kBlockSize); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<IOBuffer> wrapped_buffer( 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new net::WrappedIOBuffer(received_data_->data() + amount_received_)); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bytes_read = 0; 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EXPECT_FALSE( 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) request->Read(wrapped_buffer.get(), kBlockSize, &bytes_read)); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, bytes_read); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RequestComplete() { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_->ScheduleNextTask(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheURLRequestJobTest* test_; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpResponseInfo received_info_; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<net::IOBuffer> received_data_; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool did_receive_headers_; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int amount_received_; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int kill_after_amount_received_; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool kill_with_io_pending_; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static net::URLRequestJob* MockHttpJobFactory( 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequest* request, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::NetworkDelegate* network_delegate, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& scheme) { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mock_factory_job_) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestJob* temp = mock_factory_job_; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_factory_job_ = NULL; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return temp; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new net::URLRequestErrorJob(request, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) network_delegate, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::ERR_INTERNET_DISCONNECTED); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper callback to run a test on our io_thread. The io_thread is spun up 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // once and reused for all tests. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template <class Method> 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MethodWrapper(Method method) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetUpTest(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (this->*method)(); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void SetUpTestCase() { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_thread_.reset(new base::Thread("AppCacheURLRequestJobTest Thread")); 157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_thread_->StartWithOptions(options); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void TearDownTestCase() { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_thread_.reset(NULL); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheURLRequestJobTest() {} 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template <class Method> 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RunTestOnIOThread(Method method) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_finished_event_ .reset(new base::WaitableEvent(false, false)); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_thread_->message_loop()->PostTask( 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper<Method>, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this), method)); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_finished_event_->Wait(); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetUpTest() { 177b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(task_stack_.empty()); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) orig_http_factory_ = net::URLRequest::Deprecated::RegisterProtocolFactory( 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http", MockHttpJobFactory); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_.reset(new MockURLRequestDelegate(this)); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_delegate_.reset(new MockStorageDelegate(this)); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service_.reset(new MockAppCacheService()); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_read_result_ = 0; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_write_result_ = 0; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) written_response_id_ = 0; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader_deletion_count_down_ = 0; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_deletion_count_down_ = 0; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TearDownTest() { 192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) net::URLRequest::Deprecated::RegisterProtocolFactory("http", 194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) orig_http_factory_); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) orig_http_factory_ = NULL; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.reset(); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_.reset(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!mock_factory_job_); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!task_stack_.empty()) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_stack_.pop(); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reader_.reset(); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_buffer_ = NULL; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_info_buffer_ = NULL; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_.reset(); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buffer_ = NULL; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_info_buffer_ = NULL; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) storage_delegate_.reset(); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service_.reset(); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TestFinished() { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We unwind the stack prior to finishing up to let stack 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // based objects get deleted. 216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->PostTask( 218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) FROM_HERE, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TestFinishedUnwound() { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TearDownTest(); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_finished_event_->Signal(); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void PushNextTask(const base::Closure& task) { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_stack_.push(std::pair<base::Closure, bool>(task, false)); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void PushNextTaskAsImmediate(const base::Closure& task) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_stack_.push(std::pair<base::Closure, bool>(task, true)); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ScheduleNextTask() { 237b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK(base::MessageLoop::current() == io_thread_->message_loop()); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (task_stack_.empty()) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Closure task =task_stack_.top().first; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool immediate = task_stack_.top().second; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task_stack_.pop(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (immediate) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) task.Run(); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 248b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, task); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrappers to call AppCacheResponseReader/Writer Read and Write methods 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WriteBasicResponse() { 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBasicBody)); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string raw_headers(kHttpBasicHeaders, arraysize(kHttpBasicHeaders)); 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) WriteResponse( 257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody)); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WriteResponse(net::HttpResponseInfo* head, 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IOBuffer* body, int body_len) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(body); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<IOBuffer> body_ref(body); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody, 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this), body_ref, body_len)); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteResponseHead(head); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WriteResponseHead(net::HttpResponseInfo* head) { 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(writer_->IsWritePending()); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_write_result_ = GetHttpResponseInfoSize(head); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_info_buffer_ = new HttpResponseInfoIOBuffer(head); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_->WriteInfo( 274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_info_buffer_.get(), 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete, 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(writer_->IsWritePending()); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buffer_ = io_buffer; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_write_result_ = buf_len; 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) writer_->WriteData(write_buffer_.get(), 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) buf_len, 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete, 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Unretained(this))); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(reader_->IsReadPending()); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_buffer_ = io_buffer; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_read_result_ = buf_len; 293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) reader_->ReadData(read_buffer_.get(), 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) buf_len, 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::OnReadComplete, 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Unretained(this))); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // AppCacheResponseReader / Writer completion callbacks 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnWriteInfoComplete(int result) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(writer_->IsWritePending()); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected_write_result_, result); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextTask(); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnWriteComplete(int result) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(writer_->IsWritePending()); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected_write_result_, result); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextTask(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnReadInfoComplete(int result) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(reader_->IsReadPending()); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected_read_result_, result); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextTask(); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnReadComplete(int result) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(reader_->IsReadPending()); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected_read_result_, result); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextTask(); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helpers to work with HttpResponseInfo objects 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpResponseInfo* info = new net::HttpResponseInfo; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->request_time = base::Time::Now(); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->response_time = base::Time::Now(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->was_cached = false; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->headers = new net::HttpResponseHeaders(raw_headers); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return info; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Pickle pickle; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PickleHttpResonseInfo(&pickle, info); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1, 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::HttpResponseInfo* info2) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Pickle pickle1; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Pickle pickle2; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PickleHttpResonseInfo(&pickle1, info1); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PickleHttpResonseInfo(&pickle2, info2); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (pickle1.size() == pickle2.size()) && 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size())); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool kSkipTransientHeaders = true; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool kTruncated = false; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->Persist(pickle, kSkipTransientHeaders, kTruncated); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pickle->size(); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helpers to fill and verify blocks of memory with a value 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void FillData(char value, char* data, int data_len) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(data, value, data_len); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool CheckData(char value, const char* data, int data_len) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < data_len; ++i, ++data) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*data != value) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Individual Tests --------------------------------------------------------- 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some of the individual tests involve multiple async steps. Each test 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is delineated with a section header. 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Basic ------------------------------------------------------------------- 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Basic() { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheStorage* storage = service_->storage(); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequest request(GURL("http://blah/"), NULL, &empty_context_); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<AppCacheURLRequestJob> job; 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance and see that it looks as expected. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job = new AppCacheURLRequestJob( 3857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) &request, NULL, storage, NULL); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_waiting()); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->is_delivering_appcache_response()); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->is_delivering_network_response()); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->is_delivering_error_response()); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_started()); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_killed()); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(GURL(), job->manifest_url()); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kNoCacheId, job->cache_id()); 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->entry().has_response_id()); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeliveryOrders ----------------------------------------------------- 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DeliveryOrders() { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheStorage* storage = service_->storage(); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequest request(GURL("http://blah/"), NULL, &empty_context_); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<AppCacheURLRequestJob> job; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance, give it a delivery order and see that 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it looks as expected. 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) job = new AppCacheURLRequestJob(&request, NULL, storage, NULL); 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->DeliverErrorResponse(); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_delivering_error_response()); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_started()); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) job = new AppCacheURLRequestJob(&request, NULL, storage, NULL); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->DeliverNetworkResponse(); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_delivering_network_response()); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_started()); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) job = new AppCacheURLRequestJob(&request, NULL, storage, NULL); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL kManifestUrl("http://blah/"); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int64 kCacheId(1); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int64 kGroupId(1); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AppCacheEntry kEntry(AppCacheEntry::EXPLICIT, 1); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->DeliverAppCachedResponse(kManifestUrl, kCacheId, kGroupId, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kEntry, false); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->is_waiting()); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_delivering_appcache_response()); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_started()); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kManifestUrl, job->manifest_url()); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kCacheId, job->cache_id()); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kGroupId, job->group_id()); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kEntry.types(), job->entry().types()); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(kEntry.response_id(), job->entry().response_id()); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeliverNetworkResponse -------------------------------------------------- 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DeliverNetworkResponse() { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has async steps. 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask( 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse, 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheStorage* storage = service_->storage(); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.reset(empty_context_.CreateRequest( 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL("http://blah/"), url_request_delegate_.get())); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Setup to create an AppCacheURLRequestJob with orders to deliver 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a network response. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_factory_job_ = new AppCacheURLRequestJob( 4527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) request_.get(), NULL, storage, NULL); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_factory_job_->DeliverNetworkResponse(); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(mock_factory_job_->is_delivering_network_response()); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(mock_factory_job_->has_been_started()); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start the request. 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_->Start(); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The job should have been picked up. 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(mock_factory_job_); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Completion is async. 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifyDeliverNetworkResponse() { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(request_->status().error(), 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::ERR_INTERNET_DISCONNECTED); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeliverErrorResponse -------------------------------------------------- 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DeliverErrorResponse() { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has async steps. 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask( 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse, 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheStorage* storage = service_->storage(); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.reset(empty_context_.CreateRequest(GURL( 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://blah/"), url_request_delegate_.get())); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Setup to create an AppCacheURLRequestJob with orders to deliver 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a network response. 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_factory_job_ = new AppCacheURLRequestJob( 4867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) request_.get(), NULL, storage, NULL); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_factory_job_->DeliverErrorResponse(); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(mock_factory_job_->is_delivering_error_response()); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(mock_factory_job_->has_been_started()); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start the request. 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_->Start(); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The job should have been picked up. 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(mock_factory_job_); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Completion is async. 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifyDeliverErrorResponse() { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(request_->status().error(), net::ERR_FAILED); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeliverSmallAppCachedResponse -------------------------------------- 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "Small" being small enough to read completely in a single 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // request->Read call. 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DeliverSmallAppCachedResponse() { 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has several async steps. 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. Write a small response to response storage. 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. Use net::URLRequest to retrieve it. 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. Verify we received what we expected to receive. 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse, 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask( 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource, 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this), false)); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0)); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) written_response_id_ = writer_->response_id(); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteBasicResponse(); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continues async 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RequestAppCachedResource(bool start_after_delivery_orders) { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheStorage* storage = service_->storage(); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.reset(empty_context_.CreateRequest( 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL("http://blah/"), url_request_delegate_.get())); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Setup to create an AppCacheURLRequestJob with orders to deliver 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a network response. 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob( 5357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) request_.get(), NULL, storage, NULL)); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start_after_delivery_orders) { 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->DeliverAppCachedResponse( 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL(), 0, 111, 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_delivering_appcache_response()); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start the request. 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_started()); 547868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) mock_factory_job_ = job.get(); 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_->Start(); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(mock_factory_job_); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->has_been_started()); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!start_after_delivery_orders) { 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->DeliverAppCachedResponse( 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL(), 0, 111, 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_delivering_appcache_response()); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Completion is async. 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifyDeliverSmallAppCachedResponse() { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(request_->status().is_success()); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(CompareHttpResponseInfos( 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_info_buffer_->http_info.get(), 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &url_request_delegate_->received_info_)); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(5, url_request_delegate_->amount_received_); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, memcmp(kHttpBasicBody, 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->received_data_->data(), 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strlen(kHttpBasicBody))); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeliverLargeAppCachedResponse -------------------------------------- 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "Large" enough to require multiple calls to request->Read to complete. 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DeliverLargeAppCachedResponse() { 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has several async steps. 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. Write a large response to response storage. 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. Use net::URLRequest to retrieve it. 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. Verify we received what we expected to receive. 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse, 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::RequestAppCachedResource, 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this), true)); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0)); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) written_response_id_ = writer_->response_id(); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteLargeResponse(); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continues async 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WriteLargeResponse() { 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3, 1k blocks 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kHttpHeaders[] = 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HTTP/1.0 200 OK\0Content-Length: 3072\0\0"; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<IOBuffer> body(new IOBuffer(kBlockSize * 3)); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* p = body->data(); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 3; ++i, p += kBlockSize) 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FillData(i + 1, p, kBlockSize); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders)); 606868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) WriteResponse( 607868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) MakeHttpResponseInfo(raw_headers), body.get(), kBlockSize * 3); 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifyDeliverLargeAppCachedResponse() { 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(request_->status().is_success()); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(CompareHttpResponseInfos( 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_info_buffer_->http_info.get(), 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &url_request_delegate_->received_info_)); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(3072, url_request_delegate_->amount_received_); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* p = url_request_delegate_->received_data_->data(); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < 3; ++i, p += kBlockSize) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(CheckData(i + 1, p, kBlockSize)); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeliverPartialResponse -------------------------------------- 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DeliverPartialResponse() { 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has several async steps. 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. Write a small response to response storage. 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. Use net::URLRequest to retrieve it a subset using a range request 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. Verify we received what we expected to receive. 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse, 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::MakeRangeRequest, base::Unretained(this))); 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0)); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) written_response_id_ = writer_->response_id(); 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteBasicResponse(); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continues async 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MakeRangeRequest() { 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheStorage* storage = service_->storage(); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_.reset(empty_context_.CreateRequest( 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL("http://blah/"), url_request_delegate_.get())); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Request a range, the 3 middle chars out of 'Hello' 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpRequestHeaders extra_headers; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra_headers.SetHeader("Range", "bytes= 1-3"); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_->SetExtraRequestHeaders(extra_headers); 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create job with orders to deliver an appcached entry. 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob( 6527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) request_.get(), NULL, storage, NULL)); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->DeliverAppCachedResponse( 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL(), 0, 111, 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->is_delivering_appcache_response()); 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start the request. 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(job->has_been_started()); 661868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) mock_factory_job_ = job.get(); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_->Start(); 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(mock_factory_job_); 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(job->has_been_started()); 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Completion is async. 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifyDeliverPartialResponse() { 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(request_->status().is_success()); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(3, url_request_delegate_->amount_received_); 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(0, memcmp(kHttpBasicBody + 1, 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->received_data_->data(), 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3)); 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpResponseHeaders* headers = 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->received_info_.headers.get(); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(206, headers->response_code()); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(3, headers->GetContentLength()); 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 range_start, range_end, object_size; 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE( 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->GetContentRange(&range_start, &range_end, &object_size)); 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1, range_start); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(3, range_end); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(5, object_size); 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CancelRequest -------------------------------------- 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CancelRequest() { 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has several async steps. 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. Write a large response to response storage. 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. Use net::URLRequest to retrieve it. 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. Cancel the request after data starts coming in. 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this))); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::RequestAppCachedResource, 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this), true)); 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0)); 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) written_response_id_ = writer_->response_id(); 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteLargeResponse(); 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->kill_after_amount_received_ = kBlockSize; 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->kill_with_io_pending_ = false; 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continues async 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void VerifyCancel() { 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(net::URLRequestStatus::CANCELED, 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_->status().status()); 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFinished(); 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CancelRequestWithIOPending -------------------------------------- 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CancelRequestWithIOPending() { 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This test has several async steps. 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. Write a large response to response storage. 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. Use net::URLRequest to retrieve it. 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. Cancel the request after data starts coming in. 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this))); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PushNextTask(base::Bind( 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AppCacheURLRequestJobTest::RequestAppCachedResource, 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this), true)); 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0)); 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) written_response_id_ = writer_->response_id(); 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteLargeResponse(); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->kill_after_amount_received_ = kBlockSize; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_request_delegate_->kill_with_io_pending_ = true; 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Continues async 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Data members -------------------------------------------------------- 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<base::WaitableEvent> test_finished_event_; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<MockStorageDelegate> storage_delegate_; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<MockAppCacheService> service_; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::stack<std::pair<base::Closure, bool> > task_stack_; 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<AppCacheResponseReader> reader_; 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<IOBuffer> read_buffer_; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expected_read_result_; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int reader_deletion_count_down_; 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 written_response_id_; 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<AppCacheResponseWriter> writer_; 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_; 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<IOBuffer> write_buffer_; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int expected_write_result_; 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int writer_deletion_count_down_; 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequest::ProtocolFactory* orig_http_factory_; 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContext empty_context_; 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::URLRequest> request_; 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<MockURLRequestDelegate> url_request_delegate_; 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static scoped_ptr<base::Thread> io_thread_; 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static AppCacheURLRequestJob* mock_factory_job_; 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<base::Thread> AppCacheURLRequestJobTest::io_thread_; 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AppCacheURLRequestJob* AppCacheURLRequestJobTest::mock_factory_job_ = NULL; 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, Basic) { 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic); 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, DeliveryOrders) { 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, DeliverNetworkResponse) { 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse); 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, DeliverErrorResponse) { 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, DeliverSmallAppCachedResponse) { 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, DeliverLargeAppCachedResponse) { 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse); 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, DeliverPartialResponse) { 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse); 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, CancelRequest) { 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest); 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(AppCacheURLRequestJobTest, CancelRequestWithIOPending) { 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending); 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace appcache 810