1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef IOS_WEB_NAVIGATION_NAVIGATION_MANAGER_IMPL_H_ 6 #define IOS_WEB_NAVIGATION_NAVIGATION_MANAGER_IMPL_H_ 7 8 #include <stddef.h> 9 10 #include <memory> 11 #include <vector> 12 13 #include "base/callback.h" 14 #include "base/macros.h" 15 #import "ios/web/navigation/navigation_item_impl.h" 16 #import "ios/web/public/deprecated/navigation_item_list.h" 17 #import "ios/web/public/navigation/navigation_manager.h" 18 #include "ios/web/public/navigation/reload_type.h" 19 #include "ui/base/page_transition_types.h" 20 #include "url/gurl.h" 21 22 namespace web { 23 class BrowserState; 24 class NavigationItem; 25 class NavigationManagerDelegate; 26 class SessionStorageBuilder; 27 28 // Name of UMA histogram to log the number of items Navigation Manager was 29 // requested to restore. 100 is logged when the number of navigation items is 30 // greater than 100. This is just a requested count and actual number of 31 // restored items can be smaller. 32 extern const char kRestoreNavigationItemCount[]; 33 34 // Defines the ways how a pending navigation can be initiated. 35 enum class NavigationInitiationType { 36 // Navigation initiation type is only valid for pending navigations, use NONE 37 // if a navigation is already committed. 38 NONE = 0, 39 40 // Navigation was initiated by the browser by calling NavigationManager 41 // methods. Examples of methods which cause browser-initiated navigations 42 // include: 43 // * NavigationManager::Reload() 44 // * NavigationManager::GoBack() 45 // * NavigationManager::GoForward() 46 BROWSER_INITIATED, 47 48 // Navigation was initiated by renderer. Examples of renderer-initiated 49 // navigations include: 50 // * <a> link click 51 // * changing window.location.href 52 // * redirect via the <meta http-equiv="refresh"> tag 53 // * using window.history.pushState 54 RENDERER_INITIATED, 55 }; 56 57 // Implementation of NavigationManager. 58 // Generally mirrors upstream's NavigationController. 59 class NavigationManagerImpl : public NavigationManager { 60 public: 61 NavigationManagerImpl(); 62 ~NavigationManagerImpl() override; 63 64 // Returns the most recent Committed Item that is not the result of a client 65 // or server-side redirect from the given Navigation Manager. Returns nullptr 66 // if there's an error condition on the input |nav_manager|, such as nullptr 67 // or no non-redirect items. 68 static NavigationItem* GetLastCommittedNonRedirectedItem( 69 const NavigationManager* nav_manager); 70 71 // Setters for NavigationManagerDelegate and BrowserState. 72 virtual void SetDelegate(NavigationManagerDelegate* delegate); 73 virtual void SetBrowserState(BrowserState* browser_state); 74 75 // Initializes a new session history. 76 virtual void InitializeSession() = 0; 77 78 // Helper functions for notifying WebStateObservers of changes. 79 // TODO(stuartmorgan): Make these private once the logic triggering them moves 80 // into this layer. 81 virtual void OnNavigationItemCommitted() = 0; 82 83 // Called when a navigation has started. 84 virtual void OnNavigationStarted(const GURL& url) = 0; 85 86 // Prepares for the deletion of WKWebView such as caching necessary data. 87 virtual void DetachFromWebView(); 88 89 // Adds a transient item with the given URL. A transient item will be 90 // discarded on any navigation. 91 virtual void AddTransientItem(const GURL& url) = 0; 92 93 // Adds a new item with the given url, referrer, navigation type, initiation 94 // type and user agent override option, making it the pending item. If pending 95 // item is the same as the current item, this does nothing. |referrer| may be 96 // nil if there isn't one. The item starts out as pending, and will be lost 97 // unless |-commitPendingItem| is called. 98 virtual void AddPendingItem(const GURL& url, 99 const web::Referrer& referrer, 100 ui::PageTransition navigation_type, 101 NavigationInitiationType initiation_type) = 0; 102 103 // Commits the pending item, if any. 104 // TODO(crbug.com/936933): Remove this method. 105 virtual void CommitPendingItem() = 0; 106 107 // Commits given pending |item| stored outside of navigation manager 108 // (normally in NavigationContext). It is possible to have additional pending 109 // items owned by navigation manager and/or outside of navigation manager. 110 virtual void CommitPendingItem(std::unique_ptr<NavigationItemImpl> item) = 0; 111 112 // Removes pending item, so it can be stored in NavigationContext. 113 // Pending item is stored in this object when NavigationContext object does 114 // not yet exist (e.g. when navigation was just requested, or when navigation 115 // has aborted). 116 virtual std::unique_ptr<NavigationItemImpl> ReleasePendingItem() = 0; 117 118 // Allows transferring pending item from NavigationContext to this object. 119 // Pending item can be moved from NavigationContext to this object when 120 // navigation is aborted, but pending item should be retained. 121 virtual void SetPendingItem( 122 std::unique_ptr<web::NavigationItemImpl> item) = 0; 123 124 // Returns the navigation index that differs from the current item (or pending 125 // item if it exists) by the specified |offset|, skipping redirect navigation 126 // items. The index returned is not guaranteed to be valid. 127 // TODO(crbug.com/661316): Make this method private once navigation code is 128 // moved from CRWWebController to NavigationManagerImpl. 129 virtual int GetIndexForOffset(int offset) const = 0; 130 131 // Updates navigation history (if applicable) after pushState. 132 // TODO(crbug.com/783382): This is a legacy method to maintain backward 133 // compatibility for PageLoad stat. Remove this method once PageLoad no longer 134 // depend on WebStateObserver::DidStartLoading. 135 virtual void AddPushStateItemIfNecessary(const GURL& url, 136 NSString* state_object, 137 ui::PageTransition transition) = 0; 138 139 // Sets the index of the pending navigation item. -1 means no navigation or a 140 // new navigation. 141 virtual void SetPendingItemIndex(int index) = 0; 142 143 // Applies the workaround for crbug.com/887497. 144 virtual void ApplyWKWebViewForwardHistoryClobberWorkaround(); 145 146 // Set ShouldSkipSerialization to true for the next pending item, provided it 147 // matches |url|. Applies the workaround for crbug.com/997182 148 virtual void SetWKWebViewNextPendingUrlNotSerializable(const GURL& url); 149 150 // Returns true if specific URL is blocked from session restore. 151 virtual bool ShouldBlockUrlDuringRestore(const GURL& url) = 0; 152 153 // Resets the transient url rewriter list. 154 void RemoveTransientURLRewriters(); 155 156 // Updates the URL of the yet to be committed pending item. Useful for page 157 // redirects. Does nothing if there is no pending item. 158 void UpdatePendingItemUrl(const GURL& url) const; 159 160 // The current NavigationItem. During a pending navigation, returns the 161 // NavigationItem for that navigation. If a transient NavigationItem exists, 162 // this NavigationItem will be returned. 163 // TODO(crbug.com/661316): Make this private once all navigation code is moved 164 // out of CRWWebController. 165 NavigationItemImpl* GetCurrentItemImpl() const; 166 167 // Returns the last committed NavigationItem, which may be null if there 168 // are no committed entries or session restoration is in-progress. 169 NavigationItemImpl* GetLastCommittedItemImpl() const; 170 171 // Updates the pending or last committed navigation item after replaceState. 172 // TODO(crbug.com/783382): This is a legacy method to maintain backward 173 // compatibility for PageLoad stat. Remove this method once PageLoad no longer 174 // depend on WebStateObserver::DidStartLoading. 175 void UpdateCurrentItemForReplaceState(const GURL& url, 176 NSString* state_object); 177 178 // Same as GoToIndex(int), but allows renderer-initiated navigations and 179 // specifying whether or not the navigation is caused by the user gesture. 180 void GoToIndex(int index, 181 NavigationInitiationType initiation_type, 182 bool has_user_gesture); 183 184 // NavigationManager: 185 NavigationItem* GetLastCommittedItem() const final; 186 int GetLastCommittedItemIndex() const final; 187 NavigationItem* GetPendingItem() const final; 188 NavigationItem* GetTransientItem() const final; 189 void LoadURLWithParams(const NavigationManager::WebLoadParams&) override; 190 void AddTransientURLRewriter(BrowserURLRewriter::URLRewriter rewriter) final; 191 void GoToIndex(int index) final; 192 void Reload(ReloadType reload_type, bool check_for_reposts) final; 193 void ReloadWithUserAgentType(UserAgentType user_agent_type) final; 194 void LoadIfNecessary() override; 195 void AddRestoreCompletionCallback(base::OnceClosure callback) override; 196 197 // Implementation for corresponding NavigationManager getters. 198 virtual NavigationItemImpl* GetPendingItemInCurrentOrRestoredSession() 199 const = 0; 200 virtual NavigationItemImpl* GetTransientItemImpl() const = 0; 201 // Unlike GetLastCommittedItem(), this method does not return null during 202 // session restoration (and returns last known committed item instead). 203 virtual NavigationItemImpl* GetLastCommittedItemInCurrentOrRestoredSession() 204 const = 0; 205 // Unlike GetLastCommittedItemIndex(), this method does not return -1 during 206 // session restoration (and returns last known committed item index instead). 207 virtual int GetLastCommittedItemIndexInCurrentOrRestoredSession() const = 0; 208 209 // Identical to GetItemAtIndex() but returns the underlying NavigationItemImpl 210 // instead of the public NavigationItem interface. 211 virtual NavigationItemImpl* GetNavigationItemImplAtIndex( 212 size_t index) const = 0; 213 214 protected: 215 // The SessionStorageBuilder functions require access to private variables of 216 // NavigationManagerImpl. 217 friend SessionStorageBuilder; 218 219 // TODO(crbug.com/738020): Remove legacy code and merge 220 // WKBasedNavigationManager into this class after the navigation experiment. 221 222 // Must be called by subclasses before restoring |item_count| navigation 223 // items. 224 void WillRestore(size_t item_count); 225 226 // Some app-specific URLs need to be rewritten to about: scheme. 227 void RewriteItemURLIfNecessary(NavigationItem* item) const; 228 229 // Creates a NavigationItem using the given properties, where |previous_url| 230 // is the URL of the navigation just prior to the current one. If 231 // |url_rewriters| is not nullptr, apply them before applying the permanent 232 // URL rewriters from BrowserState. 233 // TODO(crbug.com/738020): Make this private when WKBasedNavigationManagerImpl 234 // is merged into this class. 235 std::unique_ptr<NavigationItemImpl> CreateNavigationItemWithRewriters( 236 const GURL& url, 237 const Referrer& referrer, 238 ui::PageTransition transition, 239 NavigationInitiationType initiation_type, 240 const GURL& previous_url, 241 const std::vector<BrowserURLRewriter::URLRewriter>* url_rewriters) const; 242 243 // Returns the most recent NavigationItem with an URL that generates an HTTP 244 // request. 245 NavigationItem* GetLastCommittedItemWithUserAgentType() const; 246 247 // Subclass specific implementation to update session state. 248 virtual void FinishGoToIndex(int index, 249 NavigationInitiationType type, 250 bool has_user_gesture) = 0; 251 virtual void FinishReload(); 252 virtual void FinishLoadURLWithParams( 253 NavigationInitiationType initiation_type); 254 255 // Returns true if the subclass uses placeholder URLs and this is such a URL. 256 virtual bool IsPlaceholderUrl(const GURL& url) const; 257 258 // The primary delegate for this manager. 259 NavigationManagerDelegate* delegate_; 260 261 // The BrowserState that is associated with this instance. 262 BrowserState* browser_state_; 263 264 // List of transient url rewriters added by |AddTransientURLRewriter()|. 265 std::vector<BrowserURLRewriter::URLRewriter> transient_url_rewriters_; 266 }; 267 268 } // namespace web 269 270 #endif // IOS_WEB_NAVIGATION_NAVIGATION_MANAGER_IMPL_H_ 271