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

#ifndef SERVICES_NETWORK_LOCAL_NETWORK_ACCESS_CHECKER_H_
#define SERVICES_NETWORK_LOCAL_NETWORK_ACCESS_CHECKER_H_

#include <stdint.h>

#include <optional>

#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/transport_info.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/cpp/local_network_access_check_result.h"
#include "services/network/public/mojom/client_security_state.mojom.h"
#include "services/network/public/mojom/ip_address_space.mojom-forward.h"
#include "services/network/public/mojom/network_context.mojom-forward.h"
#include "services/network/public/mojom/url_loader_network_service_observer.mojom-shared.h"
#include "url/origin.h"

class GURL;

namespace net {

struct TransportInfo;

}  // namespace net

namespace network {

struct ResourceRequest;

mojom::TransportType MapTransportTypeToMojomTransportType(
    const net::TransportType type);

// Applies Local Network Access checks to a single fetch / URL load.
//
// Manages state used for the "Local Network Access check" algorithm from
// the Local Network Access spec:
// https://wicg.github.io/local-network-access/#local-network-access-check
//
// Helper class for `URLLoader`. Should be instantiated once per `URLLoader`.
//
// Thread-compatible.
class COMPONENT_EXPORT(NETWORK_SERVICE) LocalNetworkAccessChecker {
 public:
  // `resource_request` and `url_load_options` correspond to `URLLoader`
  // constructor arguments.
  //
  // `client_security_state` should point to the client security to use for the
  // request, and must outlive the LocalNetworkAccessChecker, if non-null. It
  // can be nullptr when the factory doesn't use a client security state.
  // `resource_request's` ClientSecurityState, if it has one, is ignored.
  LocalNetworkAccessChecker(
      const ResourceRequest& resource_request,
      const mojom::ClientSecurityState* client_security_state,
      int32_t url_load_options);
  LocalNetworkAccessChecker(
      const GURL& url,
      const std::optional<url::Origin>& request_initiator,
      mojom::IPAddressSpace required_ip_address_space,
      const mojom::ClientSecurityState* client_security_state,
      int32_t url_load_options);

  // Instances of this class are neither copyable nor movable.
  LocalNetworkAccessChecker(const LocalNetworkAccessChecker&) = delete;
  LocalNetworkAccessChecker& operator=(const LocalNetworkAccessChecker&) =
      delete;

  ~LocalNetworkAccessChecker();

  // Checks whether the client should be allowed to use the given transport.
  //
  // Implements the following "Local Network Access check" algorithm:
  //
  // https://wicg.github.io/local-network-access/#fetching
  LocalNetworkAccessCheckResult Check(const net::TransportInfo& transport_info);

  // Same as above, but on an IP EndPoint. Skips proxying checks that the
  // net::TransportInfo version does.
  LocalNetworkAccessCheckResult Check(const net::IPEndPoint& server_address);

  // Same as Check(), for the case where the `resource_address_space` is already
  // known.
  LocalNetworkAccessCheckResult CheckAddressSpace(
      mojom::IPAddressSpace resource_address_space);

  // Returns the IP address space derived from the `transport_info` argument
  // passed to the last call to `Check()`, if any.
  //
  // Spec:
  // https://wicg.github.io/local-network-access/#response-ip-address-space
  std::optional<mojom::IPAddressSpace> ResponseAddressSpace() const {
    return response_address_space_;
  }
  mojom::IPAddressSpace RequiredAddressSpace() const {
    return required_address_space_;
  }

  // Clears state from all checks this instance has performed, and sets the
  // request URL to `new_url`.
  //
  // This instance will behave as if newly constructed once more.
  //
  // This should be called upon following a redirect.
  void ResetForRedirect(const GURL& new_url);

  // Clears state from all checks this instance has performed.
  //
  // This instance will behave as if newly constructed once more.
  //
  // This should be called after a cache result was blocked without preflight,
  // because we'll try fetching from the network again.
  void ResetForRetry();

  // Returns the client security state that applies to the current request.
  // May return nullptr.
  //
  // Contains relevant state derived from the fetch client's policy container.
  const mojom::ClientSecurityState* client_security_state() const {
    return client_security_state_.get();
  }

  // Returns an owned clone of `client_security_state()`.
  mojom::ClientSecurityStatePtr CloneClientSecurityState() const;

  // Returns the IP address space in `client_security_state()`.
  // Returns `kUnknown` if `client_security_state()` is nullptr.
  mojom::IPAddressSpace ClientAddressSpace() const;

 private:
  // Sets the current request URL (it may change after redirects).
  void SetRequestUrl(const GURL& url);

  // The security state of the client of the fetch. May be nullptr.
  const raw_ptr<const mojom::ClientSecurityState> client_security_state_;

  // Whether to block all requests to non-public IP address spaces, regardless
  // of other considerations. Set based on URL load options.
  const bool should_block_local_request_;

  // Whether the request URL's scheme is `http:`.
  bool is_request_url_scheme_http_ = false;

  // The IP address space derived from the `transport_info` argument passed to
  // the last call to `Check()`.
  //
  // Set by `Check()`, reset by `ResetForRedirect()`.
  std::optional<mojom::IPAddressSpace> response_address_space_;

  // The request initiator origin.
  std::optional<url::Origin> request_initiator_;

  // The request is from/to a potentially trustworthy and same origin.
  bool is_potentially_trustworthy_same_origin_;

  // IP address space required for permission prompt.
  mojom::IPAddressSpace required_address_space_;
};

}  // namespace network

#endif  // SERVICES_NETWORK_LOCAL_NETWORK_ACCESS_CHECKER_H_
