chromium/android_webview/browser/network_service/aw_proxying_url_loader_factory.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ANDROID_WEBVIEW_BROWSER_NETWORK_SERVICE_AW_PROXYING_URL_LOADER_FACTORY_H_
#define ANDROID_WEBVIEW_BROWSER_NETWORK_SERVICE_AW_PROXYING_URL_LOADER_FACTORY_H_

#include <optional>

#include "android_webview/browser/aw_cookie_access_policy.h"
#include "android_webview/browser/network_service/aw_browser_context_io_thread_handle.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/embedder_support/android/util/android_stream_reader_url_loader.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/cookie_manager.mojom-forward.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/origin.h"

namespace net {
struct MutableNetworkTrafficAnnotationTag;
}

namespace network {
struct ResourceRequest;
}

namespace android_webview {

class AwContentsOriginMatcher;

// URL Loader Factory for Android WebView. This is the entry point for handling
// Android WebView callbacks (i.e. error, interception and other callbacks) and
// loading of android specific schemes and overridden responses.
//
// This class contains centralized logic for:
//  - request interception and blocking,
//  - setting load flags and headers,
//  - loading requests depending on the scheme (e.g. different delegates are
//    used for loading android assets/resources as compared to overridden
//    responses).
//  - handling errors (e.g. no input stream, redirect or safebrowsing related
//    errors).
//
// In particular handles the following Android WebView callbacks:
//  - shouldInterceptRequest
//  - onReceivedError
//  - onReceivedHttpError
//  - onReceivedLoginRequest
//
// Threading:
//  Currently the factory and the associated loader assume they live on the IO
//  thread. This is also required by the shouldInterceptRequest callback (which
//  should be called on a non-UI thread). The other callbacks (i.e.
//  onReceivedError, onReceivedHttpError and onReceivedLoginRequest) are posted
//  on the UI thread.
//
class AwProxyingURLLoaderFactory : public network::mojom::URLLoaderFactory {
 public:
  using SecurityOptions =
      embedder_support::AndroidStreamReaderURLLoader::SecurityOptions;

  // Create a factory that will create specialized URLLoaders for Android
  // WebView. If |intercept_only| parameter is true the loader created by
  // this factory will only execute the intercept callback
  // (shouldInterceptRequest), it will not propagate the request to the
  // target factory.
  AwProxyingURLLoaderFactory(
      std::optional<mojo::PendingRemote<network::mojom::CookieManager>>
          cookie_manager,
      AwCookieAccessPolicy* cookie_access_policy,
      std::optional<const net::IsolationInfo> isolation_info,
      int frame_tree_node_id,
      mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
      mojo::PendingRemote<network::mojom::URLLoaderFactory>
          target_factory_remote,
      bool intercept_only,
      std::optional<SecurityOptions> security_options,
      scoped_refptr<AwContentsOriginMatcher> xrw_allowlist_matcher,
      scoped_refptr<AwBrowserContextIoThreadHandle> browser_context_handle,
      std::optional<int64_t> navigation_id);

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

  ~AwProxyingURLLoaderFactory() override;

  // Allows telling the loader whether the XRW origin trial is enabled for a
  // navigation URL. This is an optimization that avoids hopping to the UI
  // thread before starting a request.
  static void SetXrwResultForNavigation(
      const GURL& url,
      blink::mojom::ResourceType resource_type,
      int frame_tree_node_id,
      int64_t navigation_id);
  static void ClearXrwResultForNavigation(int64_t navigation_id);

  // static
  static void CreateProxy(
      mojo::PendingRemote<network::mojom::CookieManager> cookie_manager,
      AwCookieAccessPolicy* cookie_access_policy,
      std::optional<const net::IsolationInfo> isolation_info,
      int frame_tree_node_id,
      mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader,
      mojo::PendingRemote<network::mojom::URLLoaderFactory>
          target_factory_remote,
      std::optional<SecurityOptions> security_options,
      scoped_refptr<AwContentsOriginMatcher> xrw_allowlist_matcher,
      scoped_refptr<AwBrowserContextIoThreadHandle> browser_context_handle,
      std::optional<int64_t> navigation_id);

  void CreateLoaderAndStart(
      mojo::PendingReceiver<network::mojom::URLLoader> loader,
      int32_t request_id,
      uint32_t options,
      const network::ResourceRequest& request,
      mojo::PendingRemote<network::mojom::URLLoaderClient> client,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
      override;

  void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory>
                 loader_receiver) override;

 private:
  void OnTargetFactoryError();
  void OnProxyBindingError();
  void GetCookieHeader(bool is_3pc_allowed,
                       const network::ResourceRequest& request,
                       base::OnceCallback<void(std::string)> callback);

  void SetCookieHeader(const network::ResourceRequest& request,
                       const std::string& value,
                       const std::optional<base::Time>& server_time);

  net::IsolationInfo GetIsolationInfo(const network::ResourceRequest& request);

  mojo::Remote<network::mojom::CookieManager> cookie_manager_;
  raw_ptr<AwCookieAccessPolicy> cookie_access_policy_;
  std::optional<const net::IsolationInfo> isolation_info_;
  const int frame_tree_node_id_;
  mojo::ReceiverSet<network::mojom::URLLoaderFactory> proxy_receivers_;
  mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;

  // When true the loader resulting from this factory will only execute
  // intercept callback (shouldInterceptRequest). If that returns without
  // a response, the loader will abort loading.
  bool intercept_only_;

  std::optional<SecurityOptions> security_options_;

  scoped_refptr<AwContentsOriginMatcher> xrw_allowlist_matcher_;

  scoped_refptr<AwBrowserContextIoThreadHandle> browser_context_handle_;

  std::optional<int64_t> navigation_id_;

  base::WeakPtrFactory<AwProxyingURLLoaderFactory> weak_factory_{this};
};

}  // namespace android_webview

#endif  // ANDROID_WEBVIEW_BROWSER_NETWORK_SERVICE_AW_PROXYING_URL_LOADER_FACTORY_H_