910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/chrome_content_client.h"

#include <string>

#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/test/scoped_command_line.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/origin_util.h"
#include "content/public/test/test_utils.h"
#include "extensions/buildflags/buildflags.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "url/url_util.h"

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/common/constants.h"
#endif

namespace chrome_common {

TEST(ChromeContentClientTest, AdditionalSchemes) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  EXPECT_TRUE(url::IsStandard(
      extensions::kExtensionScheme,
      url::Component(0, strlen(extensions::kExtensionScheme))));

  GURL extension_url(
      "chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/foo.html");
  url::Origin origin = url::Origin::Create(extension_url);
  EXPECT_EQ("chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef",
            origin.Serialize());
#endif

  // IsUrlPotentiallyTrustworthy assertions test for https://crbug.com/734581.
  constexpr const char* kChromeLayerUrlsRegisteredAsSecure[] = {
      // The schemes below are registered both as secure and no-access.  Product
      // code needs to treat such URLs as trustworthy, even though no-access
      // schemes translate into an opaque origin (which is untrustworthy).
      "chrome-native://newtab/",
      "chrome-error://foo/",
      // The schemes below are registered as secure (but not as no-access).
      "chrome://foo/",
      "chrome-untrusted://foo/",
      "chrome-search://foo/",
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
      "isolated-app://foo/",
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
        // BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(ENABLE_EXTENSIONS)
      "chrome-extension://foo/",
#endif
      "devtools://foo/",
  };
  for (const std::string& str : kChromeLayerUrlsRegisteredAsSecure) {
    SCOPED_TRACE(str);
    GURL url(str);
    EXPECT_TRUE(base::Contains(url::GetSecureSchemes(), url.GetScheme()));
    EXPECT_TRUE(network::IsUrlPotentiallyTrustworthy(url));
  }

  GURL chrome_url(content::GetWebUIURL("dummyurl"));
  EXPECT_TRUE(network::IsUrlPotentiallyTrustworthy(chrome_url));
  EXPECT_TRUE(content::OriginCanAccessServiceWorkers(chrome_url));
  EXPECT_TRUE(
      network::IsOriginPotentiallyTrustworthy(url::Origin::Create(chrome_url)));
}

class OriginTrialInitializationTestThread
    : public base::PlatformThread::Delegate {
 public:
  explicit OriginTrialInitializationTestThread(
      ChromeContentClient* chrome_client)
      : chrome_client_(chrome_client) {}

  OriginTrialInitializationTestThread(
      const OriginTrialInitializationTestThread&) = delete;
  OriginTrialInitializationTestThread& operator=(
      const OriginTrialInitializationTestThread&) = delete;

  void ThreadMain() override { AccessPolicy(chrome_client_, &policy_objects_); }

  // Static helper which can also be called from the main thread.
  static void AccessPolicy(
      ChromeContentClient* content_client,
      std::vector<raw_ptr<blink::OriginTrialPolicy, VectorExperimental>>*
          policy_objects) {
    // Repeatedly access the lazily-created origin trial policy
    for (int i = 0; i < 20; i++) {
      blink::OriginTrialPolicy* policy = content_client->GetOriginTrialPolicy();
      policy_objects->push_back(policy);
      base::PlatformThread::YieldCurrentThread();
    }
  }

  const std::vector<raw_ptr<blink::OriginTrialPolicy, VectorExperimental>>*
  policy_objects() const {
    return &policy_objects_;
  }

 private:
  raw_ptr<ChromeContentClient> chrome_client_;
  std::vector<raw_ptr<blink::OriginTrialPolicy, VectorExperimental>>
      policy_objects_;
};

// Test that the lazy initialization of Origin Trial policy is resistant to
// races with concurrent access. Failures (especially flaky) indicate that the
// race prevention is no longer sufficient.
TEST(ChromeContentClientTest, OriginTrialPolicyConcurrentInitialization) {
  ChromeContentClient content_client;
  std::vector<raw_ptr<blink::OriginTrialPolicy, VectorExperimental>>
      policy_objects;
  OriginTrialInitializationTestThread thread(&content_client);
  base::PlatformThreadHandle handle;

  ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle));

  // Repeatedly access the lazily-created origin trial policy
  OriginTrialInitializationTestThread::AccessPolicy(&content_client,
                                                    &policy_objects);

  base::PlatformThread::Join(handle);

  ASSERT_EQ(20UL, policy_objects.size());

  blink::OriginTrialPolicy* first_policy = policy_objects[0];

  const std::vector<raw_ptr<blink::OriginTrialPolicy, VectorExperimental>>*
      all_policy_objects[] = {
          &policy_objects,
          thread.policy_objects(),
      };

  for (const std::vector<raw_ptr<blink::OriginTrialPolicy, VectorExperimental>>*
           thread_policy_objects : all_policy_objects) {
    EXPECT_GE(20UL, thread_policy_objects->size());
    for (blink::OriginTrialPolicy* policy : *(thread_policy_objects)) {
      EXPECT_EQ(first_policy, policy);
    }
  }
}

}  // namespace chrome_common