#include <memory>
#include <string>
#include <vector>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_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"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
namespace {
using net::test_server::HttpRequest;
using net::test_server::HttpResponse;
const char kReloadTestPath[] = "/loader/reload_test.html";
const char kNoCacheControl[] = "";
const char kMaxAgeCacheControl[] = "max-age=0";
const char kNoCacheCacheControl[] = "no-cache";
struct RequestLog {
std::string relative_url;
std::string cache_control;
};
struct ExpectedCacheControl {
const char* top_main;
const char* others;
};
const ExpectedCacheControl kExpectedCacheControlForNormalLoad = {
kNoCacheControl, kNoCacheControl};
const ExpectedCacheControl kExpectedCacheControlForReload = {
kMaxAgeCacheControl, kNoCacheControl};
const ExpectedCacheControl kExpectedCacheControlForBypassingReload = {
kNoCacheCacheControl, kNoCacheCacheControl};
class ReloadCacheControlBrowserTest : public ContentBrowserTest {
public:
ReloadCacheControlBrowserTest(const ReloadCacheControlBrowserTest&) = delete;
ReloadCacheControlBrowserTest& operator=(
const ReloadCacheControlBrowserTest&) = delete;
protected:
ReloadCacheControlBrowserTest() {}
~ReloadCacheControlBrowserTest() override = default;
void SetUpOnMainThread() override {
SetUpTestServerOnMainThread();
}
void SetUpTestServerOnMainThread() {
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&ReloadCacheControlBrowserTest::MonitorRequestHandler,
base::Unretained(this)));
ASSERT_TRUE(embedded_test_server()->Start());
}
protected:
void CheckCacheControl(const ExpectedCacheControl& expectation) {
base::AutoLock lock(request_log_lock_);
EXPECT_EQ(4u, request_log_.size());
for (const auto& log : request_log_) {
if (log.relative_url == kReloadTestPath) {
EXPECT_EQ(expectation.top_main, log.cache_control);
} else {
EXPECT_EQ(expectation.others, log.cache_control);
}
}
request_log_.clear();
}
std::vector<RequestLog> request_log_;
base::Lock request_log_lock_;
private:
void MonitorRequestHandler(const HttpRequest& request) {
RequestLog log;
log.relative_url = request.relative_url;
auto cache_control = request.headers.find("Cache-Control");
log.cache_control = cache_control == request.headers.end()
? kNoCacheControl
: cache_control->second;
base::AutoLock lock(request_log_lock_);
request_log_.push_back(log);
}
};
IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NormalReload) {
GURL url(embedded_test_server()->GetURL(kReloadTestPath));
EXPECT_TRUE(NavigateToURL(shell(), url));
CheckCacheControl(kExpectedCacheControlForNormalLoad);
ReloadBlockUntilNavigationsComplete(shell(), 1);
CheckCacheControl(kExpectedCacheControlForReload);
shell()->ShowDevTools();
ReloadBlockUntilNavigationsComplete(shell(), 1);
CheckCacheControl(kExpectedCacheControlForReload);
shell()->CloseDevTools();
ReloadBlockUntilNavigationsComplete(shell(), 1);
CheckCacheControl(kExpectedCacheControlForReload);
}
IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, BypassingReload) {
GURL url(embedded_test_server()->GetURL(kReloadTestPath));
NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
CheckCacheControl(kExpectedCacheControlForNormalLoad);
ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1);
CheckCacheControl(kExpectedCacheControlForBypassingReload);
shell()->ShowDevTools();
ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1);
CheckCacheControl(kExpectedCacheControlForBypassingReload);
shell()->CloseDevTools();
ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1);
CheckCacheControl(kExpectedCacheControlForBypassingReload);
}
IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NavigateToSame) {
GURL url(embedded_test_server()->GetURL(kReloadTestPath));
EXPECT_TRUE(NavigateToURL(shell(), url));
CheckCacheControl(kExpectedCacheControlForNormalLoad);
EXPECT_TRUE(NavigateToURL(shell(), url));
CheckCacheControl(kExpectedCacheControlForNormalLoad);
shell()->ShowDevTools();
EXPECT_TRUE(NavigateToURL(shell(), url));
CheckCacheControl(kExpectedCacheControlForNormalLoad);
shell()->CloseDevTools();
EXPECT_TRUE(NavigateToURL(shell(), url));
CheckCacheControl(kExpectedCacheControlForNormalLoad);
}
IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest,
NormalReload_ControlledByServiceWorker) {
EXPECT_TRUE(NavigateToURL(shell(),
embedded_test_server()->GetURL(
"/service_worker/create_service_worker.html")));
EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event_blob.js');"));
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("/service_worker/empty.html")));
EXPECT_EQ(u"Title", shell()->web_contents()->GetTitle());
ReloadBlockUntilNavigationsComplete(shell(), 1);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(u"Title", shell()->web_contents()->GetTitle());
}
IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest,
BypassingReload_ControlledByServiceWorker) {
EXPECT_TRUE(NavigateToURL(shell(),
embedded_test_server()->GetURL(
"/service_worker/create_service_worker.html")));
EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event_blob.js');"));
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("/service_worker/empty.html")));
EXPECT_EQ(u"Title", shell()->web_contents()->GetTitle());
ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1);
EXPECT_EQ(u"ServiceWorker test - empty page",
shell()->web_contents()->GetTitle());
}
}
}