File: prefetch_browsertest.cc

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (204 lines) | stat: -rw-r--r-- 8,425 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/base_switches.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "chrome/browser/preloading/preloading_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/base/network_change_notifier.h"
#include "net/dns/mock_host_resolver.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"

using net::NetworkChangeNotifier;
using prefetch::PreloadPagesState;

namespace {

const char kPrefetchPage[] = "/prerender/simple_prefetch.html";
const char kRedirectPrefetchPage[] = "/redirect_prefetch.html";
const char kRedirectPrefetchUrl[] = "/redirect";
const char kRedirectedPrefetchUrl[] = "/redirected";

bool HasVariationsHeader(
    const net::test_server::HttpRequest::HeaderMap& headers) {
  return headers.find("X-Client-Data") != headers.end();
}

class MockNetworkChangeNotifierWIFI : public NetworkChangeNotifier {
 public:
  ConnectionType GetCurrentConnectionType() const override {
    return NetworkChangeNotifier::CONNECTION_WIFI;
  }
};

class MockNetworkChangeNotifier4G : public NetworkChangeNotifier {
 public:
  ConnectionType GetCurrentConnectionType() const override {
    return NetworkChangeNotifier::CONNECTION_4G;
  }
};

class PrefetchBrowserTest : public InProcessBrowserTest {
 public:
  PrefetchBrowserTest() = default;

  void SetUpOnMainThread() override {
    host_resolver()->AddRule("*", "127.0.0.1");
    ASSERT_TRUE(embedded_test_server()->Start());
  }

  void SetUpCommandLine(base::CommandLine* command_line) override {
    // Set a dummy variation ID to send X-Client-Data header to Google hosts
    // in RedirectedPrefetch test.
    command_line->AppendSwitchASCII("force-variation-ids", "42");
    // Need to ignore cert errors to use a HTTPS server for the test domains.
    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
  }

  void SetPreference(prefetch::PreloadPagesState value) {
    prefetch::SetPreloadPagesState(browser()->profile()->GetPrefs(), value);
  }

  bool RunPrefetchExperiment(bool expect_success, Browser* browser) {
    GURL url = embedded_test_server()->GetURL(kPrefetchPage);

    const std::u16string expected_title =
        expect_success ? u"link onload" : u"link onerror";
    content::TitleWatcher title_watcher(
        browser->tab_strip_model()->GetActiveWebContents(), expected_title);
    EXPECT_TRUE(ui_test_utils::NavigateToURL(browser, url));
    return expected_title == title_watcher.WaitAndGetTitle();
  }
};

// When initiated from the renderer, prefetch should be allowed regardless of
// the network type.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, PreferenceWorks) {
  // Set real NetworkChangeNotifier singleton aside.
  std::unique_ptr<NetworkChangeNotifier::DisableForTest> disable_for_test(
      new NetworkChangeNotifier::DisableForTest);

  // Preference defaults to ALWAYS.
  {
    std::unique_ptr<NetworkChangeNotifier> mock(
        new MockNetworkChangeNotifierWIFI);
    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
  }
  {
    std::unique_ptr<NetworkChangeNotifier> mock(
        new MockNetworkChangeNotifier4G);
    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
  }

  // Set preference to no preloading: prefetch should be unaffected.
  SetPreference(PreloadPagesState::kNoPreloading);
  {
    std::unique_ptr<NetworkChangeNotifier> mock(
        new MockNetworkChangeNotifierWIFI);
    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
  }
  {
    std::unique_ptr<NetworkChangeNotifier> mock(
        new MockNetworkChangeNotifier4G);
    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
  }
}

// Bug 339909: When in incognito mode the browser crashed due to an
// uninitialized preference member. Verify that it no longer does.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, IncognitoTest) {
  Profile* incognito_profile =
      browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true);
  Browser* incognito_browser =
      Browser::Create(Browser::CreateParams(incognito_profile, true));

  // Navigate just to have a tab in this window, otherwise there is no
  // WebContents for the incognito browser.
  OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));

  EXPECT_TRUE(RunPrefetchExperiment(true, incognito_browser));
}

// https://crbug.com/922362: When the prefetched request is redirected, DCHECKs
// in PrefetchURLLoader::FollowRedirect() failed due to "X-Client-Data" in
// removed_headers. Verify that it no longer does, and the header is removed
// when redirected to non-Google host.
IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, RedirectedPrefetch) {
  std::vector<net::test_server::HttpRequest> requests;
  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
  https_server.RegisterRequestHandler(base::BindLambdaForTesting(
      [&requests](const net::test_server::HttpRequest& request)
          -> std::unique_ptr<net::test_server::HttpResponse> {
        auto response = std::make_unique<net::test_server::BasicHttpResponse>();
        if (request.relative_url == std::string(kRedirectPrefetchPage)) {
          requests.push_back(request);
          response->set_content_type("text/html");
          response->set_content(
              base::StringPrintf("<link rel=\"prefetch\" href=\"%s\" "
                                 "onload=\"document.title='done'\">",
                                 kRedirectPrefetchUrl));
          return response;
        } else if (request.relative_url == std::string(kRedirectPrefetchUrl)) {
          requests.push_back(request);
          response->set_code(net::HTTP_MOVED_PERMANENTLY);
          response->AddCustomHeader(
              "Location", base::StringPrintf("https://example.com:%s%s",
                                             request.GetURL().port().c_str(),
                                             kRedirectedPrefetchUrl));
          return response;
        } else if (request.relative_url ==
                   std::string(kRedirectedPrefetchUrl)) {
          requests.push_back(request);
          return response;
        }
        return nullptr;
      }));

  https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
  ASSERT_TRUE(https_server.Start());

  GURL url = https_server.GetURL("www.google.com", kRedirectPrefetchPage);
  const std::u16string expected_title = u"done";
  content::TitleWatcher title_watcher(
      browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
  ASSERT_EQ(3U, requests.size());

  EXPECT_EQ(base::StringPrintf("www.google.com:%u", https_server.port()),
            requests[0].headers["Host"]);
  EXPECT_EQ(kRedirectPrefetchPage, requests[0].relative_url);
  // The navigation request to Google host must have X-Client-Data header.
  EXPECT_TRUE(HasVariationsHeader(requests[0].headers));

  EXPECT_EQ(base::StringPrintf("www.google.com:%u", https_server.port()),
            requests[1].headers["Host"]);
  EXPECT_EQ(kRedirectPrefetchUrl, requests[1].relative_url);
  // The prefetch request to Google host must have X-Client-Data header.
  EXPECT_TRUE(HasVariationsHeader(requests[1].headers));

  EXPECT_EQ(base::StringPrintf("example.com:%u", https_server.port()),
            requests[2].headers["Host"]);
  EXPECT_EQ(kRedirectedPrefetchUrl, requests[2].relative_url);
  // The redirected prefetch request to non-Google host must not have
  // X-Client-Data header.
  EXPECT_FALSE(HasVariationsHeader(requests[2].headers));
}

}  // namespace