| // Copyright 2019 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/loader/prefetch_browsertest_base.h" |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/post_task.h" |
| #include "content/browser/loader/prefetch_url_loader_service.h" |
| #include "content/browser/storage_partition_impl.h" |
| #include "content/browser/web_package/signed_exchange_handler.h" |
| #include "content/browser/web_package/signed_exchange_loader.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| |
| namespace content { |
| |
| PrefetchBrowserTestBase::ResponseEntry::ResponseEntry() = default; |
| |
| PrefetchBrowserTestBase::ResponseEntry::ResponseEntry( |
| const std::string& content, |
| const std::string& content_type, |
| const std::vector<std::pair<std::string, std::string>>& headers, |
| net::HttpStatusCode code) |
| : content(content), |
| content_type(content_type), |
| headers(headers), |
| code(code) {} |
| |
| PrefetchBrowserTestBase::ResponseEntry::ResponseEntry(ResponseEntry&& other) = |
| default; |
| |
| PrefetchBrowserTestBase::ResponseEntry::~ResponseEntry() = default; |
| |
| PrefetchBrowserTestBase::ResponseEntry& PrefetchBrowserTestBase::ResponseEntry:: |
| operator=(ResponseEntry&& other) = default; |
| |
| PrefetchBrowserTestBase::ScopedSignedExchangeHandlerFactory:: |
| ScopedSignedExchangeHandlerFactory(SignedExchangeHandlerFactory* factory) { |
| SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(factory); |
| } |
| |
| PrefetchBrowserTestBase::ScopedSignedExchangeHandlerFactory:: |
| ~ScopedSignedExchangeHandlerFactory() { |
| SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(nullptr); |
| } |
| |
| PrefetchBrowserTestBase::PrefetchBrowserTestBase() = default; |
| PrefetchBrowserTestBase::~PrefetchBrowserTestBase() = default; |
| |
| void PrefetchBrowserTestBase::SetUpOnMainThread() { |
| ContentBrowserTest::SetUpOnMainThread(); |
| StoragePartitionImpl* partition = |
| static_cast<StoragePartitionImpl*>(shell() |
| ->web_contents() |
| ->GetBrowserContext() |
| ->GetDefaultStoragePartition()); |
| partition->GetPrefetchURLLoaderService() |
| ->RegisterPrefetchLoaderCallbackForTest(base::BindRepeating( |
| &PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled, |
| base::Unretained(this))); |
| } |
| |
| void PrefetchBrowserTestBase::RegisterResponse(const std::string& url, |
| ResponseEntry&& entry) { |
| response_map_[url] = std::move(entry); |
| } |
| |
| std::unique_ptr<net::test_server::HttpResponse> |
| PrefetchBrowserTestBase::ServeResponses( |
| const net::test_server::HttpRequest& request) { |
| auto found = response_map_.find(request.relative_url); |
| if (found != response_map_.end()) { |
| auto response = std::make_unique<net::test_server::BasicHttpResponse>(); |
| response->set_code(found->second.code); |
| response->set_content(found->second.content); |
| response->set_content_type(found->second.content_type); |
| for (const auto& header : found->second.headers) { |
| response->AddCustomHeader(header.first, header.second); |
| } |
| return std::move(response); |
| } |
| return nullptr; |
| } |
| |
| void PrefetchBrowserTestBase::OnPrefetchURLLoaderCalled() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| base::AutoLock lock(lock_); |
| prefetch_url_loader_called_++; |
| } |
| |
| int PrefetchBrowserTestBase::GetPrefetchURLLoaderCallCount() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| base::AutoLock lock(lock_); |
| return prefetch_url_loader_called_; |
| } |
| |
| void PrefetchBrowserTestBase::RegisterRequestHandler( |
| net::EmbeddedTestServer* test_server) { |
| test_server->RegisterRequestHandler(base::BindRepeating( |
| &PrefetchBrowserTestBase::ServeResponses, base::Unretained(this))); |
| } |
| |
| void PrefetchBrowserTestBase::NavigateToURLAndWaitTitle( |
| const GURL& url, |
| const std::string& title) { |
| std::u16string title16 = base::ASCIIToUTF16(title); |
| TitleWatcher title_watcher(shell()->web_contents(), title16); |
| // Execute the JavaScript code to trigger the followup navigation from the |
| // current page. |
| EXPECT_TRUE( |
| ExecJs(shell()->web_contents(), JsReplace("location.href = $1;", url))); |
| EXPECT_EQ(title16, title_watcher.WaitAndGetTitle()); |
| } |
| |
| void PrefetchBrowserTestBase::WaitUntilLoaded(const GURL& url) { |
| std::string script = R"( |
| new Promise((resolve) => { |
| const url = $1; |
| if (performance.getEntriesByName(url).length > 0) { |
| resolve(); |
| return; |
| } |
| new PerformanceObserver((list) => { |
| if (list.getEntriesByName(url).length > 0) { |
| resolve(); |
| } |
| }).observe({ entryTypes: ['resource'] }); |
| }) |
| )"; |
| |
| ASSERT_TRUE(ExecJs(shell()->web_contents(), JsReplace(script, url))); |
| } |
| |
| // static |
| scoped_refptr<PrefetchBrowserTestBase::RequestCounter> |
| PrefetchBrowserTestBase::RequestCounter::CreateAndMonitor( |
| net::EmbeddedTestServer* test_server, |
| const std::string& path, |
| base::RunLoop* waiter) { |
| auto counter = base::MakeRefCounted<RequestCounter>(path, waiter); |
| test_server->RegisterRequestMonitor( |
| base::BindRepeating(&RequestCounter::OnRequest, counter)); |
| return counter; |
| } |
| |
| PrefetchBrowserTestBase::RequestCounter::RequestCounter(const std::string& path, |
| base::RunLoop* waiter) |
| : waiter_closure_(waiter ? waiter->QuitClosure() : base::OnceClosure()), |
| path_(path) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| } |
| |
| PrefetchBrowserTestBase::RequestCounter::~RequestCounter() = default; |
| |
| int PrefetchBrowserTestBase::RequestCounter::GetRequestCount() { |
| base::AutoLock lock(lock_); |
| return request_count_; |
| } |
| |
| void PrefetchBrowserTestBase::RequestCounter::OnRequest( |
| const net::test_server::HttpRequest& request) { |
| if (request.relative_url != path_) |
| return; |
| base::AutoLock lock(lock_); |
| ++request_count_; |
| if (waiter_closure_) |
| std::move(waiter_closure_).Run(); |
| } |
| |
| } // namespace content |