| // Copyright 2019 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/json/json_reader.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "chrome/browser/extensions/extension_browsertest.h" | 
 | #include "chrome/browser/net/profile_network_context_service.h" | 
 | #include "chrome/browser/net/profile_network_context_service_factory.h" | 
 | #include "components/network_session_configurator/common/network_switches.h" | 
 | #include "content/public/test/browser_test.h" | 
 | #include "extensions/test/extension_test_message_listener.h" | 
 | #include "extensions/test/test_extension_dir.h" | 
 | #include "net/dns/mock_host_resolver.h" | 
 | #include "net/ssl/client_cert_store.h" | 
 | #include "services/network/public/cpp/features.h" | 
 | #include "url/gurl.h" | 
 |  | 
 | namespace extensions { | 
 |  | 
 | namespace { | 
 |  | 
 | std::unique_ptr<net::ClientCertStore> CreateNullCertStore() { | 
 |   return nullptr; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | class BackgroundHeaderTest : public ExtensionBrowserTest { | 
 |  public: | 
 |   BackgroundHeaderTest() | 
 |       : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} | 
 |  | 
 |   BackgroundHeaderTest(const BackgroundHeaderTest& other) = delete; | 
 |   BackgroundHeaderTest& operator=(const BackgroundHeaderTest& other) = delete; | 
 |  | 
 |   void SetUpCommandLine(base::CommandLine* command_line) override { | 
 |     ExtensionBrowserTest::SetUpCommandLine(command_line); | 
 |     command_line->AppendSwitch(switches::kIgnoreCertificateErrors); | 
 |   } | 
 |  | 
 |   GURL GetSecFetchUrl(const std::string& hostname) { | 
 |     if (hostname.empty()) | 
 |       return https_test_server_.GetURL("/echoheader?sec-fetch-site"); | 
 |     return https_test_server_.GetURL(hostname, "/echoheader?sec-fetch-site"); | 
 |   } | 
 |  | 
 |   const base::FilePath GetTestDataFilePath() { | 
 |     return base::FilePath(FILE_PATH_LITERAL("chrome/test/data")); | 
 |   } | 
 |  | 
 |   void SetUpOnMainThread() override { | 
 |     ExtensionBrowserTest::SetUpOnMainThread(); | 
 |  | 
 |     host_resolver()->AddRule("*", "127.0.0.1"); | 
 |     https_test_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK); | 
 |     https_test_server_.AddDefaultHandlers(GetTestDataFilePath()); | 
 |     ASSERT_TRUE(https_test_server_.Start()); | 
 |  | 
 |     ProfileNetworkContextServiceFactory::GetForContext(browser()->profile()) | 
 |         ->set_client_cert_store_factory_for_testing( | 
 |             base::BindRepeating(&CreateNullCertStore)); | 
 |   } | 
 |  | 
 |   std::string ExecuteFetch(const Extension* extension, const GURL& url) { | 
 |     ExtensionHost* host = | 
 |         ProcessManager::Get(profile())->GetBackgroundHostForExtension( | 
 |             extension->id()); | 
 |     if (!host) { | 
 |       ADD_FAILURE() << "No background page found."; | 
 |       return ""; | 
 |     } | 
 |     content::DOMMessageQueue message_queue(host->host_contents()); | 
 |  | 
 |     browsertest_util::ExecuteScriptInBackgroundPageNoWait( | 
 |         profile(), extension->id(), | 
 |         content::JsReplace("executeFetch($1);", url)); | 
 |     std::string json; | 
 |     EXPECT_TRUE(message_queue.WaitForMessage(&json)); | 
 |     absl::optional<base::Value> value = | 
 |         base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS); | 
 |     if (!value) { | 
 |       ADD_FAILURE() << "Received invalid response: " << json; | 
 |       return std::string(); | 
 |     } | 
 |     EXPECT_TRUE(value->is_string()); | 
 |     std::string trimmed_result; | 
 |     base::TrimWhitespaceASCII(value->GetString(), base::TRIM_ALL, | 
 |                               &trimmed_result); | 
 |     return trimmed_result; | 
 |   } | 
 |  | 
 |   const Extension* LoadFetchExtension(const std::string& host) { | 
 |     ExtensionTestMessageListener listener("ready"); | 
 |     TestExtensionDir test_dir; | 
 |     constexpr char kManifestTemplate[] = R"( | 
 |     { | 
 |       "name": "XHR Test", | 
 |       "manifest_version": 2, | 
 |       "version": "0.1", | 
 |       "background": {"scripts": ["background.js"]}, | 
 |       "permissions": ["%s"] | 
 |     })"; | 
 |     test_dir.WriteManifest(base::StringPrintf(kManifestTemplate, host.c_str())); | 
 |     constexpr char kBackgroundScriptFile[] = R"( | 
 |     function executeFetch(url) { | 
 |       console.warn('Fetching: ' + url); | 
 |       fetch(url) | 
 |           .then(response => response.text()) | 
 |           .then(text => domAutomationController.send(text)) | 
 |           .catch(err => domAutomationController.send('ERROR: ' + err)); | 
 |     } | 
 |     chrome.test.sendMessage('ready');)"; | 
 |  | 
 |     test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), | 
 |                        kBackgroundScriptFile); | 
 |     const Extension* extension = LoadExtension(test_dir.UnpackedPath()); | 
 |     EXPECT_TRUE(listener.WaitUntilSatisfied()); | 
 |     return extension; | 
 |   } | 
 |  | 
 |  private: | 
 |   net::EmbeddedTestServer https_test_server_; | 
 |   base::test::ScopedFeatureList feature_list_; | 
 | }; | 
 |  | 
 | // Test the response headers of fetch a HTTPS request in extension background | 
 | // page. | 
 | IN_PROC_BROWSER_TEST_F(BackgroundHeaderTest, SecFetchSite) { | 
 |   const Extension* extension = LoadFetchExtension("<all_urls>"); | 
 |   ASSERT_TRUE(extension); | 
 |  | 
 |   EXPECT_EQ("none", ExecuteFetch(extension, GetSecFetchUrl("example.com"))); | 
 | } | 
 |  | 
 | // Test the response headers of fetch a HTTPS request with non-privileged host | 
 | // in extension background page. | 
 | IN_PROC_BROWSER_TEST_F(BackgroundHeaderTest, | 
 |                        SecFetchSiteFromPermissionBlockedHost) { | 
 |   const Extension* extension = LoadFetchExtension("*://example.com:*/*"); | 
 |   ASSERT_TRUE(extension); | 
 |  | 
 |   EXPECT_EQ("cross-site", | 
 |             ExecuteFetch(extension, GetSecFetchUrl("example2.com"))); | 
 | } | 
 |  | 
 | }  // namespace extensions |