Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include <memory> |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 6 | #include <string> |
| 7 | #include <vector> |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 8 | |
Avi Drissman | adac2199 | 2023-01-11 23:46:39 | [diff] [blame] | 9 | #include "base/functional/bind.h" |
| 10 | #include "base/functional/callback_helpers.h" |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 11 | #include "base/strings/utf_string_conversions.h" |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 12 | #include "base/synchronization/lock.h" |
David Sanders | ee13241 | 2025-06-25 17:50:29 | [diff] [blame] | 13 | #include "content/public/browser/web_contents.h" |
Peter Kasting | 919ce65 | 2020-05-07 10:22:36 | [diff] [blame] | 14 | #include "content/public/test/browser_test.h" |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 15 | #include "content/public/test/browser_test_utils.h" |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 16 | #include "content/public/test/content_browser_test.h" |
| 17 | #include "content/public/test/content_browser_test_utils.h" |
| 18 | #include "content/shell/browser/shell.h" |
| 19 | #include "net/test/embedded_test_server/embedded_test_server.h" |
| 20 | #include "net/test/embedded_test_server/http_request.h" |
| 21 | #include "net/test/embedded_test_server/http_response.h" |
| 22 | #include "testing/gtest/include/gtest/gtest.h" |
| 23 | #include "url/gurl.h" |
| 24 | |
| 25 | namespace content { |
| 26 | |
| 27 | namespace { |
| 28 | |
| 29 | using net::test_server::HttpRequest; |
| 30 | using net::test_server::HttpResponse; |
| 31 | |
toyoshim | 4562d4a | 2017-03-16 04:09:02 | [diff] [blame] | 32 | const char kReloadTestPath[] = "/loader/reload_test.html"; |
toyoshim | 4562d4a | 2017-03-16 04:09:02 | [diff] [blame] | 33 | // The test page should request resources as the content structure is described |
| 34 | // below. Reload and the same page navigation will affect only the top frame |
| 35 | // resource, reload_test.html. But bypassing reload will affect all resources. |
| 36 | // +- reload_test.html |
| 37 | // +- empty16x16.png |
| 38 | // +- simple_frame.html |
| 39 | // +- empty16x16.png |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 40 | |
| 41 | const char kNoCacheControl[] = ""; |
| 42 | const char kMaxAgeCacheControl[] = "max-age=0"; |
| 43 | const char kNoCacheCacheControl[] = "no-cache"; |
| 44 | |
| 45 | struct RequestLog { |
| 46 | std::string relative_url; |
| 47 | std::string cache_control; |
| 48 | }; |
| 49 | |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 50 | struct ExpectedCacheControl { |
| 51 | const char* top_main; |
| 52 | const char* others; |
| 53 | }; |
| 54 | |
| 55 | const ExpectedCacheControl kExpectedCacheControlForNormalLoad = { |
| 56 | kNoCacheControl, kNoCacheControl}; |
| 57 | const ExpectedCacheControl kExpectedCacheControlForReload = { |
| 58 | kMaxAgeCacheControl, kNoCacheControl}; |
| 59 | const ExpectedCacheControl kExpectedCacheControlForBypassingReload = { |
| 60 | kNoCacheCacheControl, kNoCacheCacheControl}; |
| 61 | |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 62 | // Tests end to end behaviors between Blink and content around reload variants. |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 63 | class ReloadCacheControlBrowserTest : public ContentBrowserTest { |
Peter Boström | 9b03653 | 2021-10-28 23:37:28 | [diff] [blame] | 64 | public: |
| 65 | ReloadCacheControlBrowserTest(const ReloadCacheControlBrowserTest&) = delete; |
| 66 | ReloadCacheControlBrowserTest& operator=( |
| 67 | const ReloadCacheControlBrowserTest&) = delete; |
| 68 | |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 69 | protected: |
toyoshim | 980f1170 | 2016-12-02 08:15:53 | [diff] [blame] | 70 | ReloadCacheControlBrowserTest() {} |
asvitkine | f1c4940 | 2016-11-19 00:25:13 | [diff] [blame] | 71 | ~ReloadCacheControlBrowserTest() override = default; |
toyoshim | 7ae0fd5 | 2016-07-08 09:29:50 | [diff] [blame] | 72 | |
asvitkine | f1c4940 | 2016-11-19 00:25:13 | [diff] [blame] | 73 | void SetUpOnMainThread() override { |
toyoshim | 7ae0fd5 | 2016-07-08 09:29:50 | [diff] [blame] | 74 | SetUpTestServerOnMainThread(); |
| 75 | } |
| 76 | |
| 77 | void SetUpTestServerOnMainThread() { |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 78 | // ContentBrowserTest creates embedded_test_server instance with |
| 79 | // a registered HandleFileRequest for "content/test/data". |
| 80 | // Because the handler is registered as the first handler, MonitorHandler |
| 81 | // is needed to capture all requests. |
Makoto Shimazu | 833e1c7 | 2019-10-09 21:14:50 | [diff] [blame] | 82 | embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( |
tzik | e04a147 | 2016-08-02 21:00:33 | [diff] [blame] | 83 | &ReloadCacheControlBrowserTest::MonitorRequestHandler, |
| 84 | base::Unretained(this))); |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 85 | |
| 86 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 87 | } |
| 88 | |
| 89 | protected: |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 90 | void CheckCacheControl(const ExpectedCacheControl& expectation) { |
| 91 | base::AutoLock lock(request_log_lock_); |
| 92 | EXPECT_EQ(4u, request_log_.size()); |
| 93 | for (const auto& log : request_log_) { |
Solomon Kinard | ab293bae | 2024-09-19 17:13:51 | [diff] [blame] | 94 | if (log.relative_url == kReloadTestPath) { |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 95 | EXPECT_EQ(expectation.top_main, log.cache_control); |
Solomon Kinard | ab293bae | 2024-09-19 17:13:51 | [diff] [blame] | 96 | } else { |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 97 | EXPECT_EQ(expectation.others, log.cache_control); |
Solomon Kinard | ab293bae | 2024-09-19 17:13:51 | [diff] [blame] | 98 | } |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 99 | } |
| 100 | request_log_.clear(); |
| 101 | } |
| 102 | |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 103 | std::vector<RequestLog> request_log_; |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 104 | base::Lock request_log_lock_; |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 105 | |
| 106 | private: |
| 107 | void MonitorRequestHandler(const HttpRequest& request) { |
| 108 | RequestLog log; |
| 109 | log.relative_url = request.relative_url; |
| 110 | auto cache_control = request.headers.find("Cache-Control"); |
| 111 | log.cache_control = cache_control == request.headers.end() |
| 112 | ? kNoCacheControl |
| 113 | : cache_control->second; |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 114 | base::AutoLock lock(request_log_lock_); |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 115 | request_log_.push_back(log); |
| 116 | } |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 117 | }; |
| 118 | |
toyoshim | 4562d4a | 2017-03-16 04:09:02 | [diff] [blame] | 119 | // Test if reload issues requests with proper cache control flags. |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 120 | IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NormalReload) { |
| 121 | GURL url(embedded_test_server()->GetURL(kReloadTestPath)); |
| 122 | |
| 123 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 124 | CheckCacheControl(kExpectedCacheControlForNormalLoad); |
| 125 | |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 126 | ReloadBlockUntilNavigationsComplete(shell(), 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 127 | CheckCacheControl(kExpectedCacheControlForReload); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 128 | |
| 129 | shell()->ShowDevTools(); |
| 130 | ReloadBlockUntilNavigationsComplete(shell(), 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 131 | CheckCacheControl(kExpectedCacheControlForReload); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 132 | |
| 133 | shell()->CloseDevTools(); |
| 134 | ReloadBlockUntilNavigationsComplete(shell(), 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 135 | CheckCacheControl(kExpectedCacheControlForReload); |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 136 | } |
| 137 | |
toyoshim | 4562d4a | 2017-03-16 04:09:02 | [diff] [blame] | 138 | // Test if bypassing reload issues requests with proper cache control flags. |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 139 | IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, BypassingReload) { |
| 140 | GURL url(embedded_test_server()->GetURL(kReloadTestPath)); |
| 141 | |
arthursonzogni | e7a4456 | 2017-05-11 19:06:46 | [diff] [blame] | 142 | NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 143 | CheckCacheControl(kExpectedCacheControlForNormalLoad); |
arthursonzogni | e7a4456 | 2017-05-11 19:06:46 | [diff] [blame] | 144 | |
| 145 | ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 146 | CheckCacheControl(kExpectedCacheControlForBypassingReload); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 147 | |
| 148 | shell()->ShowDevTools(); |
| 149 | ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 150 | CheckCacheControl(kExpectedCacheControlForBypassingReload); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 151 | |
| 152 | shell()->CloseDevTools(); |
| 153 | ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1); |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 154 | CheckCacheControl(kExpectedCacheControlForBypassingReload); |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 155 | } |
| 156 | |
toyoshim | 4562d4a | 2017-03-16 04:09:02 | [diff] [blame] | 157 | // Test if the same page navigation issues requests with proper cache control |
| 158 | // flags. |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 159 | IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NavigateToSame) { |
| 160 | GURL url(embedded_test_server()->GetURL(kReloadTestPath)); |
| 161 | |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 162 | // The first navigation is just a normal load. |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 163 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
| 164 | CheckCacheControl(kExpectedCacheControlForNormalLoad); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 165 | |
Liang Zhao | 0351d76 | 2024-11-13 00:10:07 | [diff] [blame] | 166 | // The second navigation is the same page navigation from address bar. This |
| 167 | // should be handled as a replacement navigation, with normal load cache |
| 168 | // protocols. See https://github.com/whatwg/html/issues/10597 for spec |
| 169 | // discussion. |
Takashi Toyoshima | bf69830 | 2017-05-31 13:23:05 | [diff] [blame] | 170 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
Liang Zhao | 0351d76 | 2024-11-13 00:10:07 | [diff] [blame] | 171 | CheckCacheControl(kExpectedCacheControlForNormalLoad); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 172 | |
| 173 | shell()->ShowDevTools(); |
| 174 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
Liang Zhao | 0351d76 | 2024-11-13 00:10:07 | [diff] [blame] | 175 | CheckCacheControl(kExpectedCacheControlForNormalLoad); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 176 | |
| 177 | shell()->CloseDevTools(); |
| 178 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
Liang Zhao | 0351d76 | 2024-11-13 00:10:07 | [diff] [blame] | 179 | CheckCacheControl(kExpectedCacheControlForNormalLoad); |
toyoshim | a27638a | 2016-12-06 10:20:47 | [diff] [blame] | 180 | } |
toyoshim | 8a956ec | 2016-05-19 07:24:36 | [diff] [blame] | 181 | |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 182 | // Reloading with ReloadType::NORMAL should respect service workers. |
| 183 | IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, |
| 184 | NormalReload_ControlledByServiceWorker) { |
| 185 | // Prepare for a service worker. |
| 186 | EXPECT_TRUE(NavigateToURL(shell(), |
| 187 | embedded_test_server()->GetURL( |
| 188 | "/service_worker/create_service_worker.html"))); |
| 189 | EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event_blob.js');")); |
| 190 | |
| 191 | // Open a page served by the service worker. |
| 192 | EXPECT_TRUE(NavigateToURL( |
| 193 | shell(), embedded_test_server()->GetURL("/service_worker/empty.html"))); |
Jan Wilken Dörrie | 2c470ea | 2021-03-22 22:26:24 | [diff] [blame] | 194 | EXPECT_EQ(u"Title", shell()->web_contents()->GetTitle()); |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 195 | |
| 196 | // Reload from the browser. The page is still controlled by the service |
| 197 | // worker. |
| 198 | ReloadBlockUntilNavigationsComplete(shell(), 1); |
| 199 | EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
Jan Wilken Dörrie | 2c470ea | 2021-03-22 22:26:24 | [diff] [blame] | 200 | EXPECT_EQ(u"Title", shell()->web_contents()->GetTitle()); |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | // Reloading with ReloadType::BYPASSING_CACHE should bypass service workers. |
| 204 | IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, |
| 205 | BypassingReload_ControlledByServiceWorker) { |
| 206 | // Prepare for a service worker. |
| 207 | EXPECT_TRUE(NavigateToURL(shell(), |
| 208 | embedded_test_server()->GetURL( |
| 209 | "/service_worker/create_service_worker.html"))); |
| 210 | EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event_blob.js');")); |
| 211 | |
| 212 | // Open a page served by the service worker. |
| 213 | EXPECT_TRUE(NavigateToURL( |
| 214 | shell(), embedded_test_server()->GetURL("/service_worker/empty.html"))); |
Jan Wilken Dörrie | 2c470ea | 2021-03-22 22:26:24 | [diff] [blame] | 215 | EXPECT_EQ(u"Title", shell()->web_contents()->GetTitle()); |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 216 | |
| 217 | // Reload from the browser with pressing shift key. It bypasses the service |
| 218 | // worker. |
| 219 | ReloadBypassingCacheBlockUntilNavigationsComplete(shell(), 1); |
Jan Wilken Dörrie | 2c470ea | 2021-03-22 22:26:24 | [diff] [blame] | 220 | EXPECT_EQ(u"ServiceWorker test - empty page", |
Makoto Shimazu | fd87502 | 2018-11-26 08:10:01 | [diff] [blame] | 221 | shell()->web_contents()->GetTitle()); |
| 222 | } |
| 223 | |
toyoshim | e5aaf6a | 2016-05-18 08:07:48 | [diff] [blame] | 224 | } // namespace |
| 225 | |
| 226 | } // namespace content |