chromium/android_webview/browser/aw_cookie_access_policy.cc

// 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 "android_webview/browser/aw_cookie_access_policy.h"

#include <memory>

#include "android_webview/browser/aw_contents_io_thread_client.h"
#include "base/check_op.h"
#include "base/no_destructor.h"
#include "base/trace_event/base_tracing.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/websocket_handshake_request_info.h"
#include "net/base/net_errors.h"
#include "net/cookies/site_for_cookies.h"
#include "net/cookies/static_cookie_policy.h"
#include "net/storage_access_api/status.h"
#include "url/gurl.h"

using base::AutoLock;
using content::BrowserThread;
using content::WebSocketHandshakeRequestInfo;

namespace android_webview {

namespace {

using PrivacySetting = net::NetworkDelegate::PrivacySetting;

}  // namespace

AwCookieAccessPolicy::~AwCookieAccessPolicy() = default;

AwCookieAccessPolicy::AwCookieAccessPolicy() = default;

bool AwCookieAccessPolicy::GetShouldAcceptCookies() {
  AutoLock lock(lock_);
  return accept_cookies_;
}

void AwCookieAccessPolicy::SetShouldAcceptCookies(bool allow) {
  AutoLock lock(lock_);
  accept_cookies_ = allow;
}

bool AwCookieAccessPolicy::GetShouldAcceptThirdPartyCookies(
    base::optional_ref<const content::GlobalRenderFrameHostToken>
        global_frame_token,
    int frame_tree_node_id) {
  TRACE_EVENT0("android_webview",
               "AwCookieAccessPolicy::GetShouldAcceptThirdPartyCookies");
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  std::unique_ptr<AwContentsIoThreadClient> io_thread_client;
  if (frame_tree_node_id != content::RenderFrameHost::kNoFrameTreeNodeId) {
    io_thread_client = AwContentsIoThreadClient::FromID(frame_tree_node_id);
  } else if (global_frame_token.has_value()) {
    io_thread_client =
        AwContentsIoThreadClient::FromToken(global_frame_token.value());
  }

  if (!io_thread_client) {
    return false;
  }
  return io_thread_client->ShouldAcceptThirdPartyCookies();
}

PrivacySetting AwCookieAccessPolicy::AllowCookies(
    const GURL& url,
    const net::SiteForCookies& site_for_cookies,
    base::optional_ref<const content::GlobalRenderFrameHostToken>
        global_frame_token,
    net::StorageAccessApiStatus storage_access_api_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  bool third_party = GetShouldAcceptThirdPartyCookies(
      global_frame_token, content::RenderFrameHost::kNoFrameTreeNodeId);
  return CanAccessCookies(url, site_for_cookies, third_party,
                          storage_access_api_status);
}

PrivacySetting AwCookieAccessPolicy::CanAccessCookies(
    const GURL& url,
    const net::SiteForCookies& site_for_cookies,
    bool accept_third_party_cookies,
    net::StorageAccessApiStatus storage_access_api_status) {
  if (!accept_cookies_)
    return PrivacySetting::kStateDisallowed;

  if (accept_third_party_cookies)
    return PrivacySetting::kStateAllowed;

  // File URLs are a special case. We want file URLs to be able to set cookies
  // but (for the purpose of cookies) Chrome considers different file URLs to
  // come from different origins so we use the 'allow all' cookie policy for
  // file URLs.
  if (url.SchemeIsFile())
    return PrivacySetting::kStateAllowed;

  switch (storage_access_api_status) {
    case net::StorageAccessApiStatus::kNone:
      break;
    case net::StorageAccessApiStatus::kAccessViaAPI:
      return PrivacySetting::kStateAllowed;
  }

  // Otherwise, block third-party cookies.
  bool should_allow_3pcs =
      net::StaticCookiePolicy(
          net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES)
          .CanAccessCookies(url, site_for_cookies) == net::OK;

  return should_allow_3pcs ? PrivacySetting::kStateAllowed
                           : PrivacySetting::kPartitionedStateAllowedOnly;
}

}  // namespace android_webview