blob: 3ba178b2c93593051fa93a76cfd84084b8768550 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/appcache/appcache_request_handler.h"
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/containers/stack.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/post_task.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/appcache/appcache.h"
#include "content/browser/appcache/appcache_backend_impl.h"
#include "content/browser/appcache/appcache_job.h"
#include "content/browser/appcache/appcache_url_loader_job.h"
#include "content/browser/appcache/appcache_url_loader_request.h"
#include "content/browser/appcache/mock_appcache_policy.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/common/content_features.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/resource_request.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
namespace content {
static const int kMockProcessId = 1;
// TODO(michaeln/ananta)
// Build on the abstractions provided by the request and the job classes to
// provide mock request and job classes to the AppCacheRequestHandler class
// which would make it testable. It would also allow us to avoid the URLRequest
// and URLLoader semantics in the test cases here,
class AppCacheRequestHandlerTest : public ::testing::Test {
public:
// Helper callback to run a test on our io_thread. The io_thread is spun up
// once and reused for all tests.
template <class Method>
void MethodWrapper(Method method) {
SetUpTest();
(this->*method)();
}
static void SetUpTestCase() {
thread_bundle_ = std::make_unique<TestBrowserThreadBundle>(
TestBrowserThreadBundle::REAL_IO_THREAD);
io_task_runner_ = base::CreateSingleThreadTaskRunner({BrowserThread::IO});
}
static void TearDownTestCase() {
thread_bundle_.reset();
io_task_runner_ = nullptr;
}
// Test harness --------------------------------------------------
AppCacheRequestHandlerTest() : host_(nullptr), request_(nullptr) {
AppCacheRequestHandler::SetRunningInTests(true);
// TODO(http://crbug.com/824840): Enable NavigationLoaderOnUI for these
// tests.
feature_list_.InitWithFeatures({}, {features::kNavigationLoaderOnUI});
}
~AppCacheRequestHandlerTest() override {
AppCacheRequestHandler::SetRunningInTests(false);
}
template <class Method>
void RunTestOnIOThread(Method method) {
test_finished_event_ = std::make_unique<base::WaitableEvent>(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
base::Unretained(this), method));
test_finished_event_->Wait();
}
void SetUpTest() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
mock_service_ = std::make_unique<MockAppCacheService>();
mock_policy_ = std::make_unique<MockAppCachePolicy>();
mock_service_->set_appcache_policy(mock_policy_.get());
const auto kHostId = base::UnguessableToken::Create();
const int kRenderFrameId = 2;
mojo::PendingRemote<blink::mojom::AppCacheFrontend> frontend_remote;
ignore_result(frontend_remote.InitWithNewPipeAndPassReceiver());
mock_service_->RegisterHostForFrame(
host_remote_.BindNewPipeAndPassReceiver(), std::move(frontend_remote),
kHostId, kRenderFrameId, kMockProcessId, GetBadMessageCallback());
host_ = mock_service_->GetHost(kHostId);
}
void TearDownTest() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (appcache_url_loader_job_)
appcache_url_loader_job_->DeleteIfNeeded();
appcache_url_loader_job_.reset();
handler_.reset();
request_ = nullptr;
url_request_.reset();
mock_service_.reset();
mock_policy_.reset();
host_remote_.reset();
host_ = nullptr;
}
void TestFinished() {
// We unwind the stack prior to finishing up to let stack
// based objects get deleted.
DCHECK(io_task_runner_->BelongsToCurrentThread());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&AppCacheRequestHandlerTest::TestFinishedUnwound,
base::Unretained(this)));
}
void TestFinishedUnwound() {
TearDownTest();
test_finished_event_->Signal();
}
void PushNextTask(base::OnceClosure task) {
task_stack_.push(std::move(task));
}
void ScheduleNextTask() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (task_stack_.empty()) {
TestFinished();
return;
}
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(task_stack_.top()));
task_stack_.pop();
}
void SetAppCacheJob(AppCacheJob* job) {
if (appcache_url_loader_job_)
appcache_url_loader_job_->DeleteIfNeeded();
appcache_url_loader_job_ = nullptr;
if (!job)
return;
appcache_url_loader_job_ = job->AsURLLoaderJob()->GetDerivedWeakPtr();
}
AppCacheJob* job() { return appcache_url_loader_job_.get(); }
// MainResource_Miss --------------------------------------------------
void MainResource_Miss() {
PushNextTask(
base::BindOnce(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
base::Unretained(this)));
CreateRequestAndHandler(GURL("http://blah"), host_,
ResourceType::kMainFrame);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
// We have to wait for completion of storage->FindResponseForMainRequest.
ScheduleNextTask();
}
void Verify_MainResource_Miss() {
EXPECT_FALSE(job()->IsWaiting());
EXPECT_TRUE(job()->IsDeliveringNetworkResponse());
int64_t cache_id = blink::mojom::kAppCacheNoCacheId;
GURL manifest_url;
handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
EXPECT_EQ(blink::mojom::kAppCacheNoCacheId, cache_id);
EXPECT_EQ(GURL(), manifest_url);
EXPECT_EQ(0, handler_->found_group_id_);
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
TestFinished();
}
// MainResource_Hit --------------------------------------------------
void MainResource_Hit() {
PushNextTask(
base::BindOnce(&AppCacheRequestHandlerTest::Verify_MainResource_Hit,
base::Unretained(this)));
CreateRequestAndHandler(GURL("http://blah"), host_,
ResourceType::kMainFrame);
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), GURL(), AppCacheEntry(), 1,
2, GURL("http://blah/manifest/"));
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
// We have to wait for completion of storage->FindResponseForMainRequest.
ScheduleNextTask();
}
void Verify_MainResource_Hit() {
EXPECT_FALSE(job()->IsWaiting());
EXPECT_TRUE(job()->IsDeliveringAppCacheResponse());
int64_t cache_id = blink::mojom::kAppCacheNoCacheId;
GURL manifest_url;
handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
EXPECT_EQ(1, cache_id);
EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
EXPECT_EQ(2, handler_->found_group_id_);
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
EXPECT_EQ(GURL("http://blah/manifest/"), host_->preferred_manifest_url());
TestFinished();
}
// MainResource_Fallback --------------------------------------------------
void MainResource_Fallback() {
PushNextTask(base::BindOnce(
&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
base::Unretained(this)));
CreateRequestAndHandler(GURL("http://blah"), host_,
ResourceType::kMainFrame);
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
AppCacheEntry(), GURL("http://blah/fallbackurl"),
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), 1, 2,
GURL("http://blah/manifest/"));
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
// We have to wait for completion of storage->FindResponseForMainRequest.
ScheduleNextTask();
}
void SimulateResponseCode(int response_code) {
net::HttpResponseInfo info;
std::string headers =
base::StringPrintf("HTTP/1.1 %i Muffin\r\n\r\n", response_code);
info.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
net::HttpUtil::AssembleRawHeaders(headers));
network::ResourceResponseHead response;
response.headers = info.headers;
request_->AsURLLoaderRequest()->set_response(response);
DCHECK_EQ(response_code, request_->GetResponseCode());
}
void SimulateResponseInfo(const net::HttpResponseInfo& info) {
network::ResourceResponseHead response;
response.headers = info.headers;
request_->AsURLLoaderRequest()->set_response(response);
}
void Verify_MainResource_Fallback() {
EXPECT_FALSE(job()->IsWaiting());
EXPECT_TRUE(job()->IsDeliveringNetworkResponse());
// Simulate an http error of the real network job.
SimulateResponseCode(500);
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsDeliveringAppCacheResponse());
int64_t cache_id = blink::mojom::kAppCacheNoCacheId;
GURL manifest_url;
handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
EXPECT_EQ(1, cache_id);
EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
EXPECT_TRUE(host_->main_resource_was_namespace_entry_);
EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->namespace_entry_url_);
EXPECT_EQ(GURL("http://blah/manifest/"), host_->preferred_manifest_url());
TestFinished();
}
// MainResource_FallbackOverride --------------------------------------------
void MainResource_FallbackOverride() {
PushNextTask(base::BindOnce(
&AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
base::Unretained(this)));
CreateRequestAndHandler(GURL("http://blah/fallback-override"), host_,
ResourceType::kMainFrame);
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
AppCacheEntry(), GURL("http://blah/fallbackurl"),
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), 1, 2,
GURL("http://blah/manifest/"));
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
// We have to wait for completion of storage->FindResponseForMainRequest.
ScheduleNextTask();
}
void Verify_MainResource_FallbackOverride() {
EXPECT_FALSE(job()->IsWaiting());
EXPECT_TRUE(job()->IsDeliveringNetworkResponse());
// Simulate an http error of the real network job, but with custom
// headers that override the fallback behavior.
const char kOverrideHeaders[] =
"HTTP/1.1 404 BOO HOO\0"
"x-chromium-appcache-fallback-override: disallow-fallback\0"
"\0";
net::HttpResponseInfo info;
info.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
std::string(kOverrideHeaders, base::size(kOverrideHeaders)));
SimulateResponseInfo(info);
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
// GetExtraResponseInfo should return no information.
int64_t cache_id = blink::mojom::kAppCacheNoCacheId;
GURL manifest_url;
handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
EXPECT_EQ(blink::mojom::kAppCacheNoCacheId, cache_id);
EXPECT_TRUE(manifest_url.is_empty());
TestFinished();
}
// SubResource_Miss_WithNoCacheSelected ----------------------------------
void SubResource_Miss_WithNoCacheSelected() {
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
// We avoid creating handler when possible, sub-resource requests are not
// subject to retrieval from an appcache when there's no associated cache.
EXPECT_FALSE(handler_.get());
TestFinished();
}
// SubResource_Miss_WithCacheSelected ----------------------------------
void SubResource_Miss_WithCacheSelected() {
// A sub-resource load where the resource is not in an appcache, or
// in a network or fallback namespace, should result in a failed request.
host_->AssociateCompleteCache(MakeNewCache());
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsDeliveringErrorResponse());
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
TestFinished();
}
// SubResource_Miss_WithWaitForCacheSelection -----------------------------
void SubResource_Miss_WithWaitForCacheSelection() {
// Precondition, the host is waiting on cache selection.
scoped_refptr<AppCache> cache(MakeNewCache());
host_->pending_selected_cache_id_ = cache->cache_id();
host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
host_->FinishCacheSelection(cache.get(), nullptr, base::DoNothing());
EXPECT_FALSE(job()->IsWaiting());
EXPECT_TRUE(job()->IsDeliveringErrorResponse());
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
TestFinished();
}
// SubResource_Hit -----------------------------
void SubResource_Hit() {
host_->AssociateCompleteCache(MakeNewCache());
mock_storage()->SimulateFindSubResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsDeliveringAppCacheResponse());
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
TestFinished();
}
// SubResource_RedirectFallback -----------------------------
void SubResource_RedirectFallback() {
// Redirects to resources in the a different origin are subject to
// fallback namespaces.
host_->AssociateCompleteCache(MakeNewCache());
mock_storage()->SimulateFindSubResource(
AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://not_blah/redirect")));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsDeliveringAppCacheResponse());
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
TestFinished();
}
// SubResource_NoRedirectFallback -----------------------------
void SubResource_NoRedirectFallback() {
// Redirects to resources in the same-origin are not subject to
// fallback namespaces.
host_->AssociateCompleteCache(MakeNewCache());
mock_storage()->SimulateFindSubResource(
AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(job());
SimulateResponseCode(200);
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
TestFinished();
}
// SubResource_Network -----------------------------
void SubResource_Network() {
// A sub-resource load where the resource is in a network namespace,
// should result in the system using a 'real' job to do the network
// retrieval.
host_->AssociateCompleteCache(MakeNewCache());
mock_storage()->SimulateFindSubResource(AppCacheEntry(), AppCacheEntry(),
true);
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(job());
SetAppCacheJob(handler_->MaybeLoadFallbackForResponse(nullptr));
EXPECT_FALSE(job());
TestFinished();
}
// DestroyedHost -----------------------------
void DestroyedHost() {
host_->AssociateCompleteCache(MakeNewCache());
mock_storage()->SimulateFindSubResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
mock_service_->EraseHost(host_->host_id());
host_ = nullptr;
EXPECT_FALSE(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(nullptr));
TestFinished();
}
// DestroyedHostWithWaitingJob -----------------------------
void DestroyedHostWithWaitingJob() {
// Precondition, the host is waiting on cache selection.
host_->pending_selected_cache_id_ = 1;
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
mock_service_->EraseHost(host_->host_id());
host_ = nullptr;
EXPECT_FALSE(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(nullptr));
TestFinished();
}
// DestroyedService -----------------------------
void DestroyedService() {
host_->AssociateCompleteCache(MakeNewCache());
mock_storage()->SimulateFindSubResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
mock_service_.reset();
mock_policy_.reset();
host_ = nullptr;
EXPECT_FALSE(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("http://blah/redirect")));
EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(nullptr));
TestFinished();
}
// UnsupportedScheme -----------------------------
void UnsupportedScheme() {
// Precondition, the host is waiting on cache selection.
host_->pending_selected_cache_id_ = 1;
CreateRequestAndHandler(GURL("ftp://blah/"), host_,
ResourceType::kSubResource);
EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
EXPECT_FALSE(handler_->MaybeLoadResource(nullptr));
EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
nullptr, GURL("ftp://blah/redirect")));
EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(nullptr));
TestFinished();
}
// CanceledRequest -----------------------------
void CanceledRequest() {
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kMainFrame);
EXPECT_TRUE(handler_.get());
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
EXPECT_FALSE(job()->IsStarted());
base::WeakPtr<AppCacheJob> weak_job = job()->GetWeakPtr();
EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(nullptr));
TestFinished();
}
// MainResource_Blocked --------------------------------------------------
void MainResource_Blocked() {
PushNextTask(
base::BindOnce(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
base::Unretained(this)));
CreateRequestAndHandler(GURL("http://blah/"), host_,
ResourceType::kMainFrame);
EXPECT_TRUE(handler_.get());
mock_policy_->can_load_return_value_ = false;
mock_storage()->SimulateFindMainResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), GURL(), AppCacheEntry(), 1,
2, GURL("http://blah/manifest/"));
SetAppCacheJob(handler_->MaybeLoadResource(nullptr));
EXPECT_TRUE(job());
EXPECT_TRUE(job()->IsWaiting());
// We have to wait for completion of storage->FindResponseForMainRequest.
ScheduleNextTask();
}
void Verify_MainResource_Blocked() {
EXPECT_FALSE(job()->IsWaiting());
EXPECT_FALSE(job()->IsDeliveringAppCacheResponse());
EXPECT_EQ(0, handler_->found_cache_id_);
EXPECT_EQ(0, handler_->found_group_id_);
EXPECT_TRUE(handler_->found_manifest_url_.is_empty());
EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
EXPECT_TRUE(host_->main_resource_blocked_);
EXPECT_EQ(host_->blocked_manifest_url_, "http://blah/manifest/");
TestFinished();
}
// Test case helpers --------------------------------------------------
AppCache* MakeNewCache() {
AppCache* cache =
new AppCache(mock_storage(), mock_storage()->NewCacheId());
cache->set_complete(true);
AppCacheGroup* group =
new AppCacheGroup(mock_storage(), GURL("http://blah/manifest"),
mock_storage()->NewGroupId());
group->AddCache(cache);
return cache;
}
mojo::ReportBadMessageCallback GetBadMessageCallback() {
return base::BindOnce(&AppCacheRequestHandlerTest::OnBadMessage,
base::Unretained(this));
}
void OnBadMessage(const std::string& reason) { NOTREACHED(); }
MockAppCacheStorage* mock_storage() {
return reinterpret_cast<MockAppCacheStorage*>(mock_service_->storage());
}
void CreateRequestAndHandler(const GURL& url,
AppCacheHost* host,
ResourceType resource_type) {
network::ResourceRequest resource_request;
resource_request.url = url;
resource_request.method = "GET";
auto request = std::make_unique<AppCacheURLLoaderRequest>(resource_request);
request_ = request.get();
handler_ =
host->CreateRequestHandler(std::move(request), resource_type, false);
}
// Data members --------------------------------------------------
std::unique_ptr<base::WaitableEvent> test_finished_event_;
base::stack<base::OnceClosure> task_stack_;
std::unique_ptr<MockAppCacheService> mock_service_;
std::unique_ptr<MockAppCachePolicy> mock_policy_;
AppCacheHost* host_;
mojo::Remote<blink::mojom::AppCacheHost> host_remote_;
AppCacheRequest* request_;
std::unique_ptr<net::URLRequest> url_request_;
std::unique_ptr<AppCacheRequestHandler> handler_;
base::WeakPtr<AppCacheURLLoaderJob> appcache_url_loader_job_;
static std::unique_ptr<TestBrowserThreadBundle> thread_bundle_;
static scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
base::test::ScopedFeatureList feature_list_;
};
// static
std::unique_ptr<TestBrowserThreadBundle>
AppCacheRequestHandlerTest::thread_bundle_;
scoped_refptr<base::SingleThreadTaskRunner>
AppCacheRequestHandlerTest::io_task_runner_;
TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss);
}
TEST_F(AppCacheRequestHandlerTest, MainResource_Hit) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit);
}
TEST_F(AppCacheRequestHandlerTest, MainResource_Fallback) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback);
}
TEST_F(AppCacheRequestHandlerTest, MainResource_FallbackOverride) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_FallbackOverride);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) {
RunTestOnIOThread(
&AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) {
RunTestOnIOThread(
&AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithWaitForCacheSelection) {
RunTestOnIOThread(
&AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_Hit) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_RedirectFallback) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_NoRedirectFallback) {
RunTestOnIOThread(
&AppCacheRequestHandlerTest::SubResource_NoRedirectFallback);
}
TEST_F(AppCacheRequestHandlerTest, SubResource_Network) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network);
}
TEST_F(AppCacheRequestHandlerTest, DestroyedHost) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost);
}
TEST_F(AppCacheRequestHandlerTest, DestroyedHostWithWaitingJob) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob);
}
TEST_F(AppCacheRequestHandlerTest, DestroyedService) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedService);
}
TEST_F(AppCacheRequestHandlerTest, UnsupportedScheme) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme);
}
TEST_F(AppCacheRequestHandlerTest, CanceledRequest) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest);
}
TEST_F(AppCacheRequestHandlerTest, MainResource_Blocked) {
RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked);
}
} // namespace content