| // Copyright 2015 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_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_H_ |
| #define IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_H_ |
| |
| #import <Foundation/Foundation.h> |
| |
| #include "base/functional/callback.h" |
| #import "base/memory/raw_ptr.h" |
| #include "base/observer_list_types.h" |
| #include "ui/base/page_transition_types.h" |
| #include "url/gurl.h" |
| |
| namespace web { |
| |
| class WebState; |
| class FakeWebState; |
| |
| // Decides the navigation policy for a web state. |
| class WebStatePolicyDecider : public base::CheckedObserver { |
| public: |
| // Specifies a navigation decision. Used as a return value by |
| // WebStatePolicyDecider::ShouldAllowRequest(), and used by |
| // WebStatePolicyDecider::ShouldAllowResponse() when sending its decision to |
| // its callback. |
| struct PolicyDecision { |
| // A policy decision which allows the navigation. |
| static PolicyDecision Allow(); |
| |
| // A policy decision which cancels the navigation. |
| static PolicyDecision Cancel(); |
| |
| // A policy decision which cancels the navigation and displays `error`. |
| // NOTE: The `error` will only be displayed if the associated navigation is |
| // being loaded in the main frame. |
| static PolicyDecision CancelAndDisplayError(NSError* error); |
| |
| // Whether or not the navigation will continue. |
| bool ShouldAllowNavigation() const; |
| |
| // Whether or not the navigation will be cancelled. |
| bool ShouldCancelNavigation() const; |
| |
| // Whether or not an error should be displayed. Always returns false if |
| // `ShouldAllowNavigation` is true. |
| // NOTE: Will return true when the receiver is created with |
| // `CancelAndDisplayError` even though an error will only end up being |
| // displayed if the associated navigation is occurring in the main frame. |
| bool ShouldDisplayError() const; |
| |
| // The error to display when `ShouldDisplayError` is true. |
| NSError* GetDisplayError() const; |
| |
| private: |
| // The decisions which can be taken for a given navigation. |
| enum class Decision { |
| // Allow the navigation to proceed. |
| kAllow, |
| |
| // Cancel the navigation. |
| kCancel, |
| |
| // Cancel the navigation and display an error. |
| kCancelAndDisplayError, |
| }; |
| |
| PolicyDecision(Decision decision, NSError* error) |
| : decision(decision), error(error) {} |
| |
| // The decision to be taken for a given navigation. |
| Decision decision = Decision::kAllow; |
| |
| // An error associated with the navigation. This error will be displayed if |
| // `decision` is `kCancelAndDisplayError`. |
| NSError* error = nil; |
| }; |
| |
| // Callback used to provide asynchronous policy decisions. |
| typedef base::OnceCallback<void(PolicyDecision)> PolicyDecisionCallback; |
| |
| // Data Transfer Object for the additional information about navigation |
| // request passed to WebStatePolicyDecider::ShouldAllowRequest(). |
| struct RequestInfo { |
| RequestInfo(ui::PageTransition transition_type, |
| bool target_frame_is_main, |
| bool target_frame_is_cross_origin, |
| bool target_window_is_cross_origin, |
| bool is_user_initiated, |
| bool user_tapped_recently) |
| : transition_type(transition_type), |
| target_frame_is_main(target_frame_is_main), |
| target_frame_is_cross_origin(target_frame_is_cross_origin), |
| target_window_is_cross_origin(target_window_is_cross_origin), |
| is_user_initiated(is_user_initiated), |
| user_tapped_recently(user_tapped_recently) {} |
| // The navigation page transition type. |
| ui::PageTransition transition_type = |
| ui::PageTransition::PAGE_TRANSITION_FIRST; |
| // Indicates whether the navigation target frame is the main frame. |
| bool target_frame_is_main = false; |
| // Indicates whether the navigation target frame is cross-origin with |
| // respect to the the navigation source frame. |
| bool target_frame_is_cross_origin = false; |
| // Indicates whether the navigation target frame is in another window and is |
| // cross-origin with respect to the the navigation source frame. |
| bool target_window_is_cross_origin = false; |
| // Indicates if the request is user initiated (to the best of our |
| // knowledge). |
| bool is_user_initiated = false; |
| // Indicates if there was a recent user interaction with the web view (not |
| // necessarily on the page). |
| bool user_tapped_recently = false; |
| }; |
| |
| // Data Transfer Object for the additional information about response |
| // request passed to WebStatePolicyDecider::ShouldAllowResponse(). |
| struct ResponseInfo { |
| explicit ResponseInfo(bool for_main_frame) |
| : for_main_frame(for_main_frame) {} |
| // Indicates whether the response target frame is the main frame. |
| bool for_main_frame = false; |
| }; |
| |
| WebStatePolicyDecider(const WebStatePolicyDecider&) = delete; |
| WebStatePolicyDecider& operator=(const WebStatePolicyDecider&) = delete; |
| |
| // Removes self as a policy decider of `web_state_`. |
| ~WebStatePolicyDecider() override; |
| |
| // Asks the decider whether the navigation corresponding to `request` should |
| // be allowed to continue. Defaults to PolicyDecision::Allow() if not |
| // overridden. Called before WebStateObserver::DidStartNavigation. Calls |
| // `callback` with the decision. Never called in the following cases: |
| // - same-document back-forward and state change navigations |
| virtual void ShouldAllowRequest(NSURLRequest* request, |
| RequestInfo request_info, |
| PolicyDecisionCallback callback); |
| |
| // Asks the decider whether the navigation corresponding to `response` should |
| // be allowed to continue. Defaults to PolicyDecision::Allow() if not |
| // overridden. Called before WebStateObserver::DidFinishNavigation. Calls |
| // `callback` with the decision. |
| // Never called in the following cases: |
| // - same-document navigations (unless initiated via LoadURLWithParams) |
| // - going back after form submission navigation |
| // - user-initiated POST navigation on iOS 10 |
| virtual void ShouldAllowResponse(NSURLResponse* response, |
| ResponseInfo response_info, |
| PolicyDecisionCallback callback); |
| |
| // Notifies the policy decider that the web state is being destroyed. |
| // Gives subclasses a chance to cleanup. |
| // The policy decider must not be destroyed while in this call, as removing |
| // while iterating is not supported. |
| virtual void WebStateDestroyed() {} |
| |
| WebState* web_state() const { return web_state_; } |
| |
| protected: |
| // Designated constructor. Subscribes to `web_state`. |
| explicit WebStatePolicyDecider(WebState* web_state); |
| |
| private: |
| friend class ContentWebState; |
| friend class FakeWebState; |
| friend class WebStateImpl; |
| |
| // Resets the current web state. |
| void ResetWebState(); |
| |
| // The web state to decide navigation policy for. |
| raw_ptr<WebState> web_state_; |
| }; |
| } // namespace web |
| |
| #endif // IOS_WEB_PUBLIC_NAVIGATION_WEB_STATE_POLICY_DECIDER_H_ |