chromium/ios/components/security_interstitials/safe_browsing/pending_unsafe_resource_storage.h

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

#ifndef IOS_COMPONENTS_SECURITY_INTERSTITIALS_SAFE_BROWSING_PENDING_UNSAFE_RESOURCE_STORAGE_H_
#define IOS_COMPONENTS_SECURITY_INTERSTITIALS_SAFE_BROWSING_PENDING_UNSAFE_RESOURCE_STORAGE_H_

#include <optional>

#import "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/types/optional_util.h"
#import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h"
#include "components/security_interstitials/core/unsafe_resource.h"

// Storage object that holds a copy of an UnsafeResource while its allow list
// decision is pending.  Once the pending decision for a resource is committed
// or discarded, the UnsafeResource is reset.
class PendingUnsafeResourceStorage {
 public:
  // PendingUnsafeResourceStorage is copyable.
  PendingUnsafeResourceStorage();
  PendingUnsafeResourceStorage(const PendingUnsafeResourceStorage& other);
  PendingUnsafeResourceStorage& operator=(
      const PendingUnsafeResourceStorage& other);
  ~PendingUnsafeResourceStorage();

  // Constructs a storage holding `resource`.
  explicit PendingUnsafeResourceStorage(
      const security_interstitials::UnsafeResource& resource);

  // Returns the pending UnsafeResource, or null if the pending decision is
  // finished.
  const security_interstitials::UnsafeResource* resource() const {
    return base::OptionalToPtr(resource_);
  }

 private:
  // Observer that updates the storage when the pending decision for its
  // resource is completed.
  class ResourcePolicyObserver : public SafeBrowsingUrlAllowList::Observer {
   public:
    ResourcePolicyObserver(PendingUnsafeResourceStorage* storage);
    ResourcePolicyObserver(const ResourcePolicyObserver& other);
    ResourcePolicyObserver& operator=(const ResourcePolicyObserver& other);
    ~ResourcePolicyObserver() override;

   private:
    // SafeBrowsingUrlAllowList::Observer:
    void ThreatPolicyUpdated(SafeBrowsingUrlAllowList* allow_list,
                             const GURL& url,
                             safe_browsing::SBThreatType threat_type,
                             SafeBrowsingUrlAllowList::Policy policy) override;
    void ThreatPolicyBatchUpdated(
        SafeBrowsingUrlAllowList* allow_list,
        const GURL& url,
        const std::set<safe_browsing::SBThreatType>& threat_types,
        SafeBrowsingUrlAllowList::Policy policy) override;
    void SafeBrowsingAllowListDestroyed(
        SafeBrowsingUrlAllowList* allow_list) override;

    raw_ptr<PendingUnsafeResourceStorage> storage_ = nullptr;
    base::ScopedObservation<SafeBrowsingUrlAllowList,
                            SafeBrowsingUrlAllowList::Observer>
        scoped_observation_{this};
  };

  // Updates `policy_observer_` for the current value of `resource_`.
  void UpdatePolicyObserver();

  // Resets `resource_` and destroys `policy_observer_`.
  void ResetResource();

  // The resource being stored.  Contains no value after the pending decision
  // has been either allowed or disallowed.
  std::optional<security_interstitials::UnsafeResource> resource_;
  // The observer for `resource_`'s pending decision.
  std::optional<ResourcePolicyObserver> policy_observer_;
};

#endif  // IOS_COMPONENTS_SECURITY_INTERSTITIALS_SAFE_BROWSING_PENDING_UNSAFE_RESOURCE_STORAGE_H_