| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/web/navigation/crw_session_controller.h" | 5 #import "ios/web/navigation/crw_session_controller.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <map> | |
| 11 #include <utility> | 10 #include <utility> |
| 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/format_macros.h" | 13 #include "base/format_macros.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #import "base/mac/foundation_util.h" | 15 #import "base/mac/foundation_util.h" |
| 16 #import "base/mac/scoped_nsobject.h" | 16 #import "base/mac/scoped_nsobject.h" |
| 17 #include "base/strings/sys_string_conversions.h" | 17 #include "base/strings/sys_string_conversions.h" |
| 18 #include "ios/web/history_state_util.h" | 18 #include "ios/web/history_state_util.h" |
| 19 #import "ios/web/navigation/crw_session_certificate_policy_manager.h" | 19 #import "ios/web/navigation/crw_session_certificate_policy_manager.h" |
| 20 #import "ios/web/navigation/crw_session_controller+private_constructors.h" | 20 #import "ios/web/navigation/crw_session_controller+private_constructors.h" |
| 21 #import "ios/web/navigation/crw_session_entry.h" | 21 #import "ios/web/navigation/crw_session_entry.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 42 // Navigation index of the tab which opened this tab. Do not rely on the | 42 // Navigation index of the tab which opened this tab. Do not rely on the |
| 43 // value of this member variable to indicate whether or not this tab has | 43 // value of this member variable to indicate whether or not this tab has |
| 44 // an opener, as both 0 and -1 are used as navigationIndex values. | 44 // an opener, as both 0 and -1 are used as navigationIndex values. |
| 45 NSInteger _openerNavigationIndex; | 45 NSInteger _openerNavigationIndex; |
| 46 // Identifies the index of the current navigation in the CRWSessionEntry | 46 // Identifies the index of the current navigation in the CRWSessionEntry |
| 47 // array. | 47 // array. |
| 48 NSInteger _currentNavigationIndex; | 48 NSInteger _currentNavigationIndex; |
| 49 // Identifies the index of the previous navigation in the CRWSessionEntry | 49 // Identifies the index of the previous navigation in the CRWSessionEntry |
| 50 // array. | 50 // array. |
| 51 NSInteger _previousNavigationIndex; | 51 NSInteger _previousNavigationIndex; |
| 52 // Ordered array of |CRWSessionEntry| objects, one for each site in session |
| 53 // history. End of the list is the most recent load. |
| 54 NSMutableArray* _entries; |
| 55 |
| 56 // An entry we haven't gotten a response for yet. This will be discarded |
| 57 // when we navigate again. It's used only so we know what the currently |
| 58 // displayed tab is. It backs the property of the same name and should only |
| 59 // be set through its setter. |
| 60 base::scoped_nsobject<CRWSessionEntry> _pendingEntry; |
| 61 |
| 62 // The transient entry, if any. A transient entry is discarded on any |
| 63 // navigation, and is used for representing interstitials that need to be |
| 64 // represented in the session. It backs the property of the same name and |
| 65 // should only be set through its setter. |
| 66 base::scoped_nsobject<CRWSessionEntry> _transientEntry; |
| 52 | 67 |
| 53 // The window name associated with the session. | 68 // The window name associated with the session. |
| 54 NSString* _windowName; | 69 NSString* _windowName; |
| 55 | 70 |
| 56 // Stores the certificate policies decided by the user. | 71 // Stores the certificate policies decided by the user. |
| 57 CRWSessionCertificatePolicyManager* _sessionCertificatePolicyManager; | 72 CRWSessionCertificatePolicyManager* _sessionCertificatePolicyManager; |
| 58 | 73 |
| 59 // The timestamp of the last time this tab is visited, represented in time | 74 // The timestamp of the last time this tab is visited, represented in time |
| 60 // interval since 1970. | 75 // interval since 1970. |
| 61 NSTimeInterval _lastVisitedTimestamp; | 76 NSTimeInterval _lastVisitedTimestamp; |
| 62 | 77 |
| 63 // If |YES|, override |currentEntry.useDesktopUserAgent| and create the | 78 // If |YES|, override |currentEntry.useDesktopUserAgent| and create the |
| 64 // pending item using the desktop user agent. | 79 // pending entry using the desktop user agent. |
| 65 BOOL _useDesktopUserAgentForNextPendingItem; | 80 BOOL _useDesktopUserAgentForNextPendingItem; |
| 66 | 81 |
| 67 // The browser state associated with this CRWSessionController; | 82 // The browser state associated with this CRWSessionController; |
| 68 web::BrowserState* _browserState; // weak | 83 web::BrowserState* _browserState; // weak |
| 69 | 84 |
| 70 // Time smoother for navigation item timestamps; see comment in | 85 // Time smoother for navigation entry timestamps; see comment in |
| 71 // navigation_controller_impl.h | 86 // navigation_controller_impl.h |
| 72 web::TimeSmoother _timeSmoother; | 87 web::TimeSmoother _timeSmoother; |
| 73 | |
| 74 // Backing objects for properties of the same name. | |
| 75 web::ScopedNavigationItemImplList _items; | |
| 76 // |_pendingItem| only contains a NavigationItem for non-history navigations. | |
| 77 // For back/forward navigations within session history, _pendingItemIndex will | |
| 78 // be equal to -1, and self.pendingItem will return an item contained within | |
| 79 // |_items|. | |
| 80 std::unique_ptr<web::NavigationItemImpl> _pendingItem; | |
| 81 std::unique_ptr<web::NavigationItemImpl> _transientItem; | |
| 82 } | 88 } |
| 83 | 89 |
| 84 // Redefine as readwrite. | 90 // Redefine as readwrite. |
| 85 @property(nonatomic, readwrite, assign) NSInteger currentNavigationIndex; | 91 @property(nonatomic, readwrite, assign) NSInteger currentNavigationIndex; |
| 86 | 92 |
| 87 // TODO(rohitrao): These properties must be redefined readwrite to work around a | 93 // TODO(rohitrao): These properties must be redefined readwrite to work around a |
| 88 // clang bug. crbug.com/228650 | 94 // clang bug. crbug.com/228650 |
| 89 @property(nonatomic, readwrite, copy) NSString* tabId; | 95 @property(nonatomic, readwrite, copy) NSString* tabId; |
| 96 @property(nonatomic, readwrite, strong) NSArray* entries; |
| 90 @property(nonatomic, readwrite, strong) | 97 @property(nonatomic, readwrite, strong) |
| 91 CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; | 98 CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; |
| 92 | 99 |
| 93 // Expose setters for serialization properties. These are exposed in a category | 100 // Expose setters for serialization properties. These are exposed in a category |
| 94 // in SessionStorageBuilder, and will be removed as ownership of | 101 // in SessionStorageBuilder, and will be removed as ownership of |
| 95 // their backing ivars moves to NavigationManagerImpl. | 102 // their backing ivars moves to NavigationManagerImpl. |
| 96 @property(nonatomic, readwrite, copy) NSString* openerId; | 103 @property(nonatomic, readwrite, copy) NSString* openerId; |
| 97 @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM; | 104 @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM; |
| 98 @property(nonatomic, readwrite, assign) NSInteger openerNavigationIndex; | 105 @property(nonatomic, readwrite, assign) NSInteger openerNavigationIndex; |
| 99 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex; | 106 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex; |
| 100 | 107 |
| 101 - (NSString*)uniqueID; | 108 - (NSString*)uniqueID; |
| 102 // Removes all items after currentNavigationIndex_. | 109 // Removes all entries after currentNavigationIndex_. |
| 103 - (void)clearForwardItems; | 110 - (void)clearForwardItems; |
| 104 // Discards the transient item, if any. | 111 // Discards the transient entry, if any. |
| 105 - (void)discardTransientItem; | 112 - (void)discardTransientItem; |
| 106 // Creates a NavigationItemImpl with the specified properties. | 113 // Create a new autoreleased session entry. |
| 107 - (std::unique_ptr<web::NavigationItemImpl>) | 114 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url |
| 108 itemWithURL:(const GURL&)url | 115 referrer:(const web::Referrer&)referrer |
| 109 referrer:(const web::Referrer&)referrer | 116 transition:(ui::PageTransition)transition |
| 110 transition:(ui::PageTransition)transition | 117 useDesktopUserAgent:(BOOL)useDesktopUserAgent |
| 111 useDesktopUserAgent:(BOOL)useDesktopUserAgent | 118 rendererInitiated:(BOOL)rendererInitiated; |
| 112 rendererInitiated:(BOOL)rendererInitiated; | |
| 113 // Returns YES if the PageTransition for the underlying navigationItem at | 119 // Returns YES if the PageTransition for the underlying navigationItem at |
| 114 // |index| in |items| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK. | 120 // |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK. |
| 115 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index; | 121 - (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index; |
| 116 // Returns the CRWSessionEntry corresponding with |item|. | 122 // Returns a NavigationItemList containing the NavigationItems from |entries|. |
| 117 - (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item; | 123 - (web::NavigationItemList)itemListForEntryList:(NSArray*)entries; |
| 118 // Returns an autoreleased NSArray containing CRWSessionEntries corresponding | |
| 119 // with the NavigationItems in |itemList|. | |
| 120 - (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList; | |
| 121 | |
| 122 @end | 124 @end |
| 123 | 125 |
| 124 @implementation CRWSessionController | 126 @implementation CRWSessionController |
| 125 | 127 |
| 126 @synthesize tabId = _tabId; | 128 @synthesize tabId = _tabId; |
| 127 @synthesize currentNavigationIndex = _currentNavigationIndex; | 129 @synthesize currentNavigationIndex = _currentNavigationIndex; |
| 128 @synthesize previousNavigationIndex = _previousNavigationIndex; | 130 @synthesize previousNavigationIndex = _previousNavigationIndex; |
| 129 @synthesize pendingItemIndex = _pendingItemIndex; | 131 @synthesize pendingItemIndex = _pendingItemIndex; |
| 132 @synthesize entries = _entries; |
| 130 @synthesize windowName = _windowName; | 133 @synthesize windowName = _windowName; |
| 131 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp; | 134 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp; |
| 132 @synthesize openerId = _openerId; | 135 @synthesize openerId = _openerId; |
| 133 @synthesize openedByDOM = _openedByDOM; | 136 @synthesize openedByDOM = _openedByDOM; |
| 134 @synthesize openerNavigationIndex = _openerNavigationIndex; | 137 @synthesize openerNavigationIndex = _openerNavigationIndex; |
| 135 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager; | 138 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager; |
| 136 | 139 |
| 137 - (id)initWithWindowName:(NSString*)windowName | 140 - (id)initWithWindowName:(NSString*)windowName |
| 138 openerId:(NSString*)openerId | 141 openerId:(NSString*)openerId |
| 139 openedByDOM:(BOOL)openedByDOM | 142 openedByDOM:(BOOL)openedByDOM |
| 140 openerNavigationIndex:(NSInteger)openerIndex | 143 openerNavigationIndex:(NSInteger)openerIndex |
| 141 browserState:(web::BrowserState*)browserState { | 144 browserState:(web::BrowserState*)browserState { |
| 142 self = [super init]; | 145 self = [super init]; |
| 143 if (self) { | 146 if (self) { |
| 144 self.windowName = windowName; | 147 self.windowName = windowName; |
| 145 _tabId = [[self uniqueID] copy]; | 148 _tabId = [[self uniqueID] copy]; |
| 146 _openerId = [openerId copy]; | 149 _openerId = [openerId copy]; |
| 147 _openedByDOM = openedByDOM; | 150 _openedByDOM = openedByDOM; |
| 148 _openerNavigationIndex = openerIndex; | 151 _openerNavigationIndex = openerIndex; |
| 149 _browserState = browserState; | 152 _browserState = browserState; |
| 153 _entries = [NSMutableArray array]; |
| 150 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; | 154 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; |
| 151 _currentNavigationIndex = -1; | 155 _currentNavigationIndex = -1; |
| 152 _previousNavigationIndex = -1; | 156 _previousNavigationIndex = -1; |
| 153 _pendingItemIndex = -1; | 157 _pendingItemIndex = -1; |
| 154 _sessionCertificatePolicyManager = | 158 _sessionCertificatePolicyManager = |
| 155 [[CRWSessionCertificatePolicyManager alloc] init]; | 159 [[CRWSessionCertificatePolicyManager alloc] init]; |
| 156 } | 160 } |
| 157 return self; | 161 return self; |
| 158 } | 162 } |
| 159 | 163 |
| 160 - (id)initWithNavigationItems:(web::ScopedNavigationItemList)items | 164 - (id)initWithNavigationItems: |
| 165 (std::vector<std::unique_ptr<web::NavigationItem>>)items |
| 161 currentIndex:(NSUInteger)currentIndex | 166 currentIndex:(NSUInteger)currentIndex |
| 162 browserState:(web::BrowserState*)browserState { | 167 browserState:(web::BrowserState*)browserState { |
| 163 self = [super init]; | 168 self = [super init]; |
| 164 if (self) { | 169 if (self) { |
| 165 _tabId = [[self uniqueID] copy]; | 170 _tabId = [[self uniqueID] copy]; |
| 166 _openerId = nil; | 171 _openerId = nil; |
| 167 _browserState = browserState; | 172 _browserState = browserState; |
| 168 _items = web::CreateScopedNavigationItemImplList(std::move(items)); | 173 |
| 174 // Create entries array from list of navigations. |
| 175 _entries = [[NSMutableArray alloc] initWithCapacity:items.size()]; |
| 176 |
| 177 for (auto& item : items) { |
| 178 base::scoped_nsobject<CRWSessionEntry> entry( |
| 179 [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]); |
| 180 [_entries addObject:entry]; |
| 181 } |
| 169 self.currentNavigationIndex = currentIndex; | 182 self.currentNavigationIndex = currentIndex; |
| 170 if (_items.empty()) | 183 // Prior to M34, 0 was used as "no index" instead of -1; adjust for that. |
| 184 if (![_entries count]) |
| 171 self.currentNavigationIndex = -1; | 185 self.currentNavigationIndex = -1; |
| 172 _currentNavigationIndex = std::min( | 186 if (_currentNavigationIndex >= static_cast<NSInteger>(items.size())) { |
| 173 _currentNavigationIndex, static_cast<NSInteger>(_items.size() - 1)); | 187 self.currentNavigationIndex = static_cast<NSInteger>(items.size()) - 1; |
| 188 } |
| 174 _previousNavigationIndex = -1; | 189 _previousNavigationIndex = -1; |
| 175 _pendingItemIndex = -1; | 190 _pendingItemIndex = -1; |
| 176 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; | 191 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; |
| 177 _sessionCertificatePolicyManager = | 192 _sessionCertificatePolicyManager = |
| 178 [[CRWSessionCertificatePolicyManager alloc] init]; | 193 [[CRWSessionCertificatePolicyManager alloc] init]; |
| 179 } | 194 } |
| 180 return self; | 195 return self; |
| 181 } | 196 } |
| 182 | 197 |
| 183 #pragma mark - Accessors | 198 - (id)copyWithZone:(NSZone*)zone { |
| 199 CRWSessionController* copy = [[[self class] alloc] init]; |
| 200 copy->_tabId = [_tabId copy]; |
| 201 copy->_openerId = [_openerId copy]; |
| 202 copy->_openedByDOM = _openedByDOM; |
| 203 copy->_openerNavigationIndex = _openerNavigationIndex; |
| 204 copy.windowName = self.windowName; |
| 205 copy->_currentNavigationIndex = _currentNavigationIndex; |
| 206 copy->_previousNavigationIndex = _previousNavigationIndex; |
| 207 copy->_pendingItemIndex = _pendingItemIndex; |
| 208 copy->_lastVisitedTimestamp = _lastVisitedTimestamp; |
| 209 copy->_entries = |
| 210 [[NSMutableArray alloc] initWithArray:_entries copyItems:YES]; |
| 211 copy->_sessionCertificatePolicyManager = |
| 212 [_sessionCertificatePolicyManager copy]; |
| 213 return copy; |
| 214 } |
| 184 | 215 |
| 185 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex { | 216 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex { |
| 186 if (_currentNavigationIndex != currentNavigationIndex) { | 217 if (_currentNavigationIndex != currentNavigationIndex) { |
| 187 _currentNavigationIndex = currentNavigationIndex; | 218 _currentNavigationIndex = currentNavigationIndex; |
| 188 if (_navigationManager) | 219 if (_navigationManager) |
| 189 _navigationManager->RemoveTransientURLRewriters(); | 220 _navigationManager->RemoveTransientURLRewriters(); |
| 190 } | 221 } |
| 191 } | 222 } |
| 192 | 223 |
| 193 - (void)setPendingItemIndex:(NSInteger)pendingItemIndex { | 224 - (void)setPendingItemIndex:(NSInteger)index { |
| 194 DCHECK_GE(pendingItemIndex, -1); | 225 DCHECK_GE(index, -1); |
| 195 DCHECK_LT(pendingItemIndex, static_cast<NSInteger>(self.items.size())); | 226 DCHECK_LT(index, static_cast<NSInteger>(_entries.count)); |
| 196 _pendingItemIndex = pendingItemIndex; | 227 _pendingItemIndex = index; |
| 197 DCHECK(_pendingItemIndex == -1 || self.pendingItem); | 228 CRWSessionEntry* entry = index != -1 ? _entries[index] : nil; |
| 229 _pendingEntry.reset(entry); |
| 230 DCHECK(_pendingItemIndex == -1 || _pendingEntry); |
| 198 } | 231 } |
| 199 | 232 |
| 200 - (const web::ScopedNavigationItemImplList&)items { | |
| 201 return _items; | |
| 202 } | |
| 203 | |
| 204 - (web::NavigationItemImpl*)currentItem { | |
| 205 if (self.transientItem) | |
| 206 return self.transientItem; | |
| 207 if (self.pendingItem) | |
| 208 return self.pendingItem; | |
| 209 return self.lastCommittedItem; | |
| 210 } | |
| 211 | |
| 212 - (web::NavigationItemImpl*)visibleItem { | |
| 213 if (self.transientItem) | |
| 214 return self.transientItem; | |
| 215 // Only return the |pendingItem| for new (non-history), browser-initiated | |
| 216 // navigations in order to prevent URL spoof attacks. | |
| 217 web::NavigationItemImpl* pendingItem = self.pendingItem; | |
| 218 bool safeToShowPending = pendingItem && | |
| 219 !pendingItem->is_renderer_initiated() && | |
| 220 _pendingItemIndex == -1; | |
| 221 if (safeToShowPending) | |
| 222 return pendingItem; | |
| 223 return self.lastCommittedItem; | |
| 224 } | |
| 225 | |
| 226 - (web::NavigationItemImpl*)pendingItem { | |
| 227 if (self.pendingItemIndex == -1) | |
| 228 return _pendingItem.get(); | |
| 229 return self.items[self.pendingItemIndex].get(); | |
| 230 } | |
| 231 | |
| 232 - (web::NavigationItemImpl*)transientItem { | |
| 233 return _transientItem.get(); | |
| 234 } | |
| 235 | |
| 236 - (web::NavigationItemImpl*)lastCommittedItem { | |
| 237 NSInteger index = self.currentNavigationIndex; | |
| 238 return index == -1 ? nullptr : self.items[index].get(); | |
| 239 } | |
| 240 | |
| 241 - (web::NavigationItemImpl*)previousItem { | |
| 242 NSInteger index = self.previousNavigationIndex; | |
| 243 return index == -1 || self.items.empty() ? nullptr : self.items[index].get(); | |
| 244 } | |
| 245 | |
| 246 - (web::NavigationItemImpl*)lastUserItem { | |
| 247 if (self.items.empty()) | |
| 248 return nil; | |
| 249 | |
| 250 NSInteger index = self.currentNavigationIndex; | |
| 251 // This will return the first NavigationItem if all other items are | |
| 252 // redirects, regardless of the transition state of the first item. | |
| 253 while (index > 0 && [self isRedirectTransitionForItemAtIndex:index]) | |
| 254 --index; | |
| 255 | |
| 256 return self.items[index].get(); | |
| 257 } | |
| 258 | |
| 259 - (web::NavigationItemList)backwardItems { | |
| 260 web::NavigationItemList items; | |
| 261 for (size_t index = _currentNavigationIndex; index > 0; --index) { | |
| 262 if (![self isRedirectTransitionForItemAtIndex:index]) | |
| 263 items.push_back(self.items[index - 1].get()); | |
| 264 } | |
| 265 return items; | |
| 266 } | |
| 267 | |
| 268 - (web::NavigationItemList)forwardItems { | |
| 269 web::NavigationItemList items; | |
| 270 NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1; | |
| 271 while (lastNonRedirectedIndex < self.items.size()) { | |
| 272 web::NavigationItem* item = self.items[lastNonRedirectedIndex].get(); | |
| 273 if (!ui::PageTransitionIsRedirect(item->GetTransitionType())) | |
| 274 items.push_back(item); | |
| 275 ++lastNonRedirectedIndex; | |
| 276 } | |
| 277 return items; | |
| 278 } | |
| 279 | |
| 280 // DEPRECATED | |
| 281 - (NSArray*)entries { | |
| 282 return [self entryListForItemList:web::CreateNavigationItemList(_items)]; | |
| 283 } | |
| 284 | |
| 285 // DEPRECATED | |
| 286 - (CRWSessionEntry*)currentEntry { | |
| 287 return [self entryForItem:self.currentItem]; | |
| 288 } | |
| 289 | |
| 290 // DEPRECATED | |
| 291 - (CRWSessionEntry*)visibleEntry { | |
| 292 return [self entryForItem:self.visibleItem]; | |
| 293 } | |
| 294 | |
| 295 // DEPRECATED | |
| 296 - (CRWSessionEntry*)pendingEntry { | |
| 297 return [self entryForItem:self.pendingItem]; | |
| 298 } | |
| 299 | |
| 300 // DEPRECATED | |
| 301 - (CRWSessionEntry*)transientEntry { | |
| 302 return [self entryForItem:self.transientItem]; | |
| 303 } | |
| 304 | |
| 305 // DEPRECATED | |
| 306 - (CRWSessionEntry*)lastCommittedEntry { | |
| 307 return [self entryForItem:self.lastCommittedItem]; | |
| 308 } | |
| 309 | |
| 310 // DEPRECATED | |
| 311 - (CRWSessionEntry*)previousEntry { | |
| 312 return [self entryForItem:self.previousItem]; | |
| 313 } | |
| 314 | |
| 315 // DEPRECATED | |
| 316 - (CRWSessionEntry*)lastUserEntry { | |
| 317 return [self entryForItem:self.lastUserItem]; | |
| 318 } | |
| 319 | |
| 320 // DEPRECATED | |
| 321 - (NSArray*)backwardEntries { | |
| 322 return [self entryListForItemList:self.backwardItems]; | |
| 323 } | |
| 324 | |
| 325 // DEPRECATED | |
| 326 - (NSArray*)forwardEntries { | |
| 327 return [self entryListForItemList:self.forwardItems]; | |
| 328 } | |
| 329 | |
| 330 #pragma mark - NSObject | |
| 331 | |
| 332 - (NSString*)description { | |
| 333 return [NSString | |
| 334 stringWithFormat: | |
| 335 @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS | |
| 336 @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS | |
| 337 @"\n%@\npending: %@\ntransient: %@\n", | |
| 338 _tabId, self.windowName, _lastVisitedTimestamp, | |
| 339 _currentNavigationIndex, _previousNavigationIndex, _pendingItemIndex, | |
| 340 self.entries, self.pendingEntry, self.transientEntry]; | |
| 341 } | |
| 342 | |
| 343 #pragma mark - NSCopying | |
| 344 | |
| 345 - (id)copyWithZone:(NSZone*)zone { | |
| 346 CRWSessionController* copy = [[[self class] alloc] init]; | |
| 347 copy->_tabId = [_tabId copy]; | |
| 348 copy->_openerId = [_openerId copy]; | |
| 349 copy->_openedByDOM = _openedByDOM; | |
| 350 copy->_openerNavigationIndex = _openerNavigationIndex; | |
| 351 copy.windowName = self.windowName; | |
| 352 copy->_currentNavigationIndex = _currentNavigationIndex; | |
| 353 copy->_previousNavigationIndex = _previousNavigationIndex; | |
| 354 copy->_pendingItemIndex = _pendingItemIndex; | |
| 355 copy->_lastVisitedTimestamp = _lastVisitedTimestamp; | |
| 356 copy->_sessionCertificatePolicyManager = | |
| 357 [_sessionCertificatePolicyManager copy]; | |
| 358 for (size_t index = 0; index < self.items.size(); ++index) { | |
| 359 std::unique_ptr<web::NavigationItemImpl> itemCopy( | |
| 360 new web::NavigationItemImpl(*self.items[index].get())); | |
| 361 copy->_items.push_back(std::move(itemCopy)); | |
| 362 } | |
| 363 return copy; | |
| 364 } | |
| 365 | |
| 366 #pragma mark - Public | |
| 367 | |
| 368 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager { | 233 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager { |
| 369 _navigationManager = navigationManager; | 234 _navigationManager = navigationManager; |
| 370 if (_navigationManager) { | 235 if (_navigationManager) { |
| 371 // _browserState will be nullptr if CRWSessionController has been | 236 // _browserState will be nullptr if CRWSessionController has been |
| 372 // initialized with -initWithCoder: method. Take _browserState from | 237 // initialized with -initWithCoder: method. Take _browserState from |
| 373 // NavigationManagerImpl if that's the case. | 238 // NavigationManagerImpl if that's the case. |
| 374 if (!_browserState) { | 239 if (!_browserState) { |
| 375 _browserState = _navigationManager->GetBrowserState(); | 240 _browserState = _navigationManager->GetBrowserState(); |
| 376 } | 241 } |
| 377 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState()); | 242 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState()); |
| 378 } | 243 } |
| 379 } | 244 } |
| 380 | 245 |
| 381 - (void)setBrowserState:(web::BrowserState*)browserState { | 246 - (void)setBrowserState:(web::BrowserState*)browserState { |
| 382 _browserState = browserState; | 247 _browserState = browserState; |
| 383 DCHECK(!_navigationManager || | 248 DCHECK(!_navigationManager || |
| 384 _navigationManager->GetBrowserState() == _browserState); | 249 _navigationManager->GetBrowserState() == _browserState); |
| 385 } | 250 } |
| 386 | 251 |
| 252 - (NSString*)description { |
| 253 return [NSString |
| 254 stringWithFormat: |
| 255 @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS |
| 256 @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS |
| 257 @"\n%@\npending: %@\ntransient: %@\n", |
| 258 _tabId, self.windowName, _lastVisitedTimestamp, |
| 259 _currentNavigationIndex, _previousNavigationIndex, _pendingItemIndex, |
| 260 _entries, _pendingEntry.get(), _transientEntry.get()]; |
| 261 } |
| 262 |
| 263 - (web::NavigationItemList)items { |
| 264 return [self itemListForEntryList:self.entries]; |
| 265 } |
| 266 |
| 267 - (web::NavigationItemImpl*)currentItem { |
| 268 return self.currentEntry.navigationItemImpl; |
| 269 } |
| 270 |
| 271 - (web::NavigationItemImpl*)visibleItem { |
| 272 return self.visibleEntry.navigationItemImpl; |
| 273 } |
| 274 |
| 275 - (web::NavigationItemImpl*)pendingItem { |
| 276 return self.pendingEntry.navigationItemImpl; |
| 277 } |
| 278 |
| 279 - (web::NavigationItemImpl*)transientItem { |
| 280 return self.transientEntry.navigationItemImpl; |
| 281 } |
| 282 |
| 283 - (web::NavigationItemImpl*)lastCommittedItem { |
| 284 return self.lastCommittedEntry.navigationItemImpl; |
| 285 } |
| 286 |
| 287 - (web::NavigationItemImpl*)previousItem { |
| 288 return self.previousEntry.navigationItemImpl; |
| 289 } |
| 290 |
| 291 - (web::NavigationItemImpl*)lastUserItem { |
| 292 return self.lastUserEntry.navigationItemImpl; |
| 293 } |
| 294 |
| 295 - (web::NavigationItemList)backwardItems { |
| 296 return [self itemListForEntryList:self.backwardEntries]; |
| 297 } |
| 298 |
| 299 - (web::NavigationItemList)forwardItems { |
| 300 return [self itemListForEntryList:self.forwardEntries]; |
| 301 } |
| 302 |
| 303 // Returns the current entry in the session list, or the pending entry if there |
| 304 // is a navigation in progress. |
| 305 - (CRWSessionEntry*)currentEntry { |
| 306 if (_transientEntry) |
| 307 return _transientEntry.get(); |
| 308 if (_pendingEntry) |
| 309 return _pendingEntry.get(); |
| 310 return [self lastCommittedEntry]; |
| 311 } |
| 312 |
| 313 // See NavigationController::GetVisibleEntry for the motivation for this |
| 314 // distinction. |
| 315 - (CRWSessionEntry*)visibleEntry { |
| 316 if (_transientEntry) |
| 317 return _transientEntry.get(); |
| 318 // Only return the pending_entry for new (non-history), browser-initiated |
| 319 // navigations in order to prevent URL spoof attacks. |
| 320 web::NavigationItemImpl* pendingItem = [_pendingEntry navigationItemImpl]; |
| 321 bool safeToShowPending = pendingItem && |
| 322 !pendingItem->is_renderer_initiated() && |
| 323 _pendingItemIndex == -1; |
| 324 if (safeToShowPending) { |
| 325 return _pendingEntry.get(); |
| 326 } |
| 327 return [self lastCommittedEntry]; |
| 328 } |
| 329 |
| 330 - (CRWSessionEntry*)pendingEntry { |
| 331 return _pendingEntry.get(); |
| 332 } |
| 333 |
| 334 - (CRWSessionEntry*)transientEntry { |
| 335 return _transientEntry.get(); |
| 336 } |
| 337 |
| 338 - (CRWSessionEntry*)lastCommittedEntry { |
| 339 if (_currentNavigationIndex == -1) |
| 340 return nil; |
| 341 return [_entries objectAtIndex:_currentNavigationIndex]; |
| 342 } |
| 343 |
| 344 // Returns the previous entry in the session list, or nil if there isn't any. |
| 345 - (CRWSessionEntry*)previousEntry { |
| 346 if ((_previousNavigationIndex < 0) || (![_entries count])) |
| 347 return nil; |
| 348 return [_entries objectAtIndex:_previousNavigationIndex]; |
| 349 } |
| 350 |
| 387 - (void)addPendingItem:(const GURL&)url | 351 - (void)addPendingItem:(const GURL&)url |
| 388 referrer:(const web::Referrer&)ref | 352 referrer:(const web::Referrer&)ref |
| 389 transition:(ui::PageTransition)trans | 353 transition:(ui::PageTransition)trans |
| 390 rendererInitiated:(BOOL)rendererInitiated { | 354 rendererInitiated:(BOOL)rendererInitiated { |
| 391 [self discardTransientItem]; | 355 [self discardTransientItem]; |
| 392 self.pendingItemIndex = -1; | 356 _pendingItemIndex = -1; |
| 393 | 357 |
| 394 // Don't create a new item if it's already the same as the current item, | 358 // Don't create a new entry if it's already the same as the current entry, |
| 395 // allowing this routine to be called multiple times in a row without issue. | 359 // allowing this routine to be called multiple times in a row without issue. |
| 396 // Note: CRWSessionController currently has the responsibility to distinguish | 360 // Note: CRWSessionController currently has the responsibility to distinguish |
| 397 // between new navigations and history stack navigation, hence the inclusion | 361 // between new navigations and history stack navigation, hence the inclusion |
| 398 // of specific transiton type logic here, in order to make it reliable with | 362 // of specific transiton type logic here, in order to make it reliable with |
| 399 // real-world observed behavior. | 363 // real-world observed behavior. |
| 400 // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere | 364 // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere |
| 401 // in the web layer so that this hack can be removed. | 365 // in the web layer so that this hack can be removed. |
| 402 // Remove the workaround code from -presentSafeBrowsingWarningForResource:. | 366 // Remove the workaround code from -presentSafeBrowsingWarningForResource:. |
| 403 web::NavigationItemImpl* currentItem = self.currentItem; | 367 CRWSessionEntry* currentEntry = self.currentEntry; |
| 404 if (currentItem && currentItem->GetURL() == url && | 368 if (currentEntry) { |
| 405 (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) || | 369 web::NavigationItem* item = [currentEntry navigationItem]; |
| 406 PageTransitionCoreTypeIs(currentItem->GetTransitionType(), | 370 if (item->GetURL() == url && |
| 407 ui::PAGE_TRANSITION_FORM_SUBMIT))) { | 371 (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) || |
| 408 // Send the notification anyway, to preserve old behavior. It's unknown | 372 PageTransitionCoreTypeIs(item->GetTransitionType(), |
| 409 // whether anything currently relies on this, but since both this whole | 373 ui::PAGE_TRANSITION_FORM_SUBMIT))) { |
| 410 // hack and the content facade will both be going away, it's not worth | 374 // Send the notification anyway, to preserve old behavior. It's unknown |
| 411 // trying to unwind. | 375 // whether anything currently relies on this, but since both this whole |
| 412 if (_navigationManager && _navigationManager->GetFacadeDelegate()) | 376 // hack and the content facade will both be going away, it's not worth |
| 413 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); | 377 // trying to unwind. |
| 414 return; | 378 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { |
| 379 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); |
| 380 } |
| 381 return; |
| 382 } |
| 415 } | 383 } |
| 416 | 384 |
| 417 BOOL useDesktopUserAgent = | 385 BOOL useDesktopUserAgent = |
| 418 _useDesktopUserAgentForNextPendingItem || | 386 _useDesktopUserAgentForNextPendingItem || |
| 419 (currentItem && currentItem->IsOverridingUserAgent()); | 387 (self.currentEntry.navigationItem && |
| 388 self.currentEntry.navigationItem->IsOverridingUserAgent()); |
| 420 _useDesktopUserAgentForNextPendingItem = NO; | 389 _useDesktopUserAgentForNextPendingItem = NO; |
| 421 _pendingItem = [self itemWithURL:url | 390 _pendingEntry.reset([self sessionEntryWithURL:url |
| 422 referrer:ref | 391 referrer:ref |
| 423 transition:trans | 392 transition:trans |
| 424 useDesktopUserAgent:useDesktopUserAgent | 393 useDesktopUserAgent:useDesktopUserAgent |
| 425 rendererInitiated:rendererInitiated]; | 394 rendererInitiated:rendererInitiated]); |
| 426 | 395 |
| 427 if (_navigationManager && _navigationManager->GetFacadeDelegate()) | 396 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { |
| 428 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); | 397 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); |
| 398 } |
| 429 } | 399 } |
| 430 | 400 |
| 431 - (void)updatePendingItem:(const GURL&)url { | 401 - (void)updatePendingItem:(const GURL&)url { |
| 432 // If there is no pending item, navigation is probably happening within the | 402 // If there is no pending entry, navigation is probably happening within the |
| 433 // session history. Don't modify the item list. | 403 // session history. Don't modify the entry list. |
| 434 web::NavigationItemImpl* item = self.pendingItem; | 404 if (!_pendingEntry) |
| 435 if (!item) | |
| 436 return; | 405 return; |
| 437 | 406 |
| 407 web::NavigationItemImpl* item = [_pendingEntry navigationItemImpl]; |
| 438 if (url != item->GetURL()) { | 408 if (url != item->GetURL()) { |
| 439 // Assume a redirection, and discard any transient item. | 409 // Assume a redirection, and discard any transient entry. |
| 440 // TODO(stuartmorgan): Once the current safe browsing code is gone, | 410 // TODO(stuartmorgan): Once the current safe browsing code is gone, |
| 441 // consider making this a DCHECK that there's no transient item. | 411 // consider making this a DCHECK that there's no transient entry. |
| 442 [self discardTransientItem]; | 412 [self discardTransientItem]; |
| 443 | 413 |
| 444 item->SetURL(url); | 414 item->SetURL(url); |
| 445 item->SetVirtualURL(url); | 415 item->SetVirtualURL(url); |
| 446 // Redirects (3xx response code), or client side navigation must change | 416 // Redirects (3xx response code), or client side navigation must change |
| 447 // POST requests to GETs. | 417 // POST requests to GETs. |
| 448 item->SetPostData(nil); | 418 item->SetPostData(nil); |
| 449 item->ResetHttpRequestHeaders(); | 419 item->ResetHttpRequestHeaders(); |
| 450 } | 420 } |
| 451 | 421 |
| 452 // This should probably not be sent if the URLs matched, but that's what was | 422 // This should probably not be sent if the URLs matched, but that's what was |
| 453 // done before, so preserve behavior in case something relies on it. | 423 // done before, so preserve behavior in case something relies on it. |
| 454 if (_navigationManager && _navigationManager->GetFacadeDelegate()) | 424 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { |
| 455 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); | 425 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); |
| 426 } |
| 456 } | 427 } |
| 457 | 428 |
| 458 - (void)clearForwardItems { | 429 - (void)clearForwardItems { |
| 459 DCHECK_EQ(self.pendingItemIndex, -1); | 430 DCHECK_EQ(_pendingItemIndex, -1); |
| 460 [self discardTransientItem]; | 431 [self discardTransientItem]; |
| 461 | 432 |
| 462 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1; | 433 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1; |
| 463 DCHECK(forwardItemStartIndex >= 0); | 434 DCHECK(forwardItemStartIndex >= 0); |
| 464 | 435 |
| 465 size_t itemCount = self.items.size(); | 436 if (forwardItemStartIndex >= static_cast<NSInteger>([_entries count])) |
| 466 if (forwardItemStartIndex >= static_cast<NSInteger>(itemCount)) | |
| 467 return; | 437 return; |
| 468 | 438 |
| 439 NSRange remove = NSMakeRange(forwardItemStartIndex, |
| 440 [_entries count] - forwardItemStartIndex); |
| 441 // Store removed items in temporary NSArray so they can be deallocated after |
| 442 // their facades. |
| 443 base::scoped_nsobject<NSArray> removedItems( |
| 444 [_entries subarrayWithRange:remove]); |
| 445 [_entries removeObjectsInRange:remove]; |
| 469 if (_previousNavigationIndex >= forwardItemStartIndex) | 446 if (_previousNavigationIndex >= forwardItemStartIndex) |
| 470 _previousNavigationIndex = -1; | 447 _previousNavigationIndex = -1; |
| 471 if (_navigationManager) | 448 if (_navigationManager) { |
| 472 _navigationManager->OnNavigationItemsPruned(self.items.size() - | 449 _navigationManager->OnNavigationItemsPruned(remove.length); |
| 473 forwardItemStartIndex); | 450 } |
| 474 | |
| 475 // Remove the NavigationItems. | |
| 476 _items.erase(_items.begin() + forwardItemStartIndex, _items.end()); | |
| 477 } | 451 } |
| 478 | 452 |
| 479 - (void)commitPendingItem { | 453 - (void)commitPendingItem { |
| 480 if (self.pendingItem) { | 454 if (_pendingEntry) { |
| 481 // Once an item is committed it's not renderer-initiated any more. (Matches | 455 NSInteger newNavigationIndex = _pendingItemIndex; |
| 482 // the implementation in NavigationController.) | 456 if (_pendingItemIndex == -1) { |
| 483 self.pendingItem->ResetForCommit(); | |
| 484 | |
| 485 NSInteger newNavigationIndex = self.pendingItemIndex; | |
| 486 if (newNavigationIndex == -1) { | |
| 487 [self clearForwardItems]; | 457 [self clearForwardItems]; |
| 488 // Add the new item at the end. | 458 // Add the new entry at the end. |
| 489 _items.push_back(std::move(_pendingItem)); | 459 [_entries addObject:_pendingEntry]; |
| 490 newNavigationIndex = self.items.size() - 1; | 460 newNavigationIndex = [_entries count] - 1; |
| 491 } | 461 } |
| 492 _previousNavigationIndex = _currentNavigationIndex; | 462 _previousNavigationIndex = _currentNavigationIndex; |
| 493 self.currentNavigationIndex = newNavigationIndex; | 463 self.currentNavigationIndex = newNavigationIndex; |
| 494 self.pendingItemIndex = -1; | 464 // Once an entry is committed it's not renderer-initiated any more. (Matches |
| 465 // the implementation in NavigationController.) |
| 466 [_pendingEntry navigationItemImpl]->ResetForCommit(); |
| 467 _pendingEntry.reset(); |
| 468 _pendingItemIndex = -1; |
| 495 } | 469 } |
| 496 | 470 |
| 497 web::NavigationItem* item = self.currentItem; | 471 CRWSessionEntry* currentEntry = self.currentEntry; |
| 472 web::NavigationItem* item = currentEntry.navigationItem; |
| 498 // Update the navigation timestamp now that it's actually happened. | 473 // Update the navigation timestamp now that it's actually happened. |
| 499 if (item) | 474 if (item) |
| 500 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now())); | 475 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now())); |
| 501 | 476 |
| 502 if (_navigationManager && item) | 477 if (_navigationManager && item) |
| 503 _navigationManager->OnNavigationItemCommitted(); | 478 _navigationManager->OnNavigationItemCommitted(); |
| 504 DCHECK_EQ(self.pendingItemIndex, -1); | 479 DCHECK_EQ(_pendingItemIndex, -1); |
| 505 } | 480 } |
| 506 | 481 |
| 507 - (void)addTransientItemWithURL:(const GURL&)URL { | 482 - (void)addTransientItemWithURL:(const GURL&)URL { |
| 508 _transientItem = [self itemWithURL:URL | 483 _transientEntry.reset([self |
| 509 referrer:web::Referrer() | 484 sessionEntryWithURL:URL |
| 510 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT | 485 referrer:web::Referrer() |
| 511 useDesktopUserAgent:NO | 486 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT |
| 512 rendererInitiated:NO]; | 487 useDesktopUserAgent:NO |
| 513 _transientItem->SetTimestamp( | 488 rendererInitiated:NO]); |
| 489 |
| 490 web::NavigationItem* navigationItem = [_transientEntry navigationItem]; |
| 491 DCHECK(navigationItem); |
| 492 navigationItem->SetTimestamp( |
| 514 _timeSmoother.GetSmoothedTime(base::Time::Now())); | 493 _timeSmoother.GetSmoothedTime(base::Time::Now())); |
| 515 } | 494 } |
| 516 | 495 |
| 517 - (void)pushNewItemWithURL:(const GURL&)URL | 496 - (void)pushNewItemWithURL:(const GURL&)URL |
| 518 stateObject:(NSString*)stateObject | 497 stateObject:(NSString*)stateObject |
| 519 transition:(ui::PageTransition)transition { | 498 transition:(ui::PageTransition)transition { |
| 520 DCHECK(!self.pendingItem); | 499 DCHECK(![self pendingEntry]); |
| 521 web::NavigationItem* item = self.currentItem; | 500 DCHECK([self currentEntry]); |
| 522 DCHECK(item); | 501 web::NavigationItem* item = [self currentEntry].navigationItem; |
| 523 CHECK( | 502 CHECK( |
| 524 web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL)); | 503 web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL)); |
| 525 web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault); | 504 web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault); |
| 526 bool overrideUserAgent = self.currentItem->IsOverridingUserAgent(); | 505 bool overrideUserAgent = |
| 527 std::unique_ptr<web::NavigationItemImpl> pushedItem = | 506 self.currentEntry.navigationItem->IsOverridingUserAgent(); |
| 528 [self itemWithURL:URL | 507 base::scoped_nsobject<CRWSessionEntry> pushedEntry([self |
| 529 referrer:referrer | 508 sessionEntryWithURL:URL |
| 530 transition:transition | 509 referrer:referrer |
| 531 useDesktopUserAgent:overrideUserAgent | 510 transition:transition |
| 532 rendererInitiated:NO]; | 511 useDesktopUserAgent:overrideUserAgent |
| 512 rendererInitiated:NO]); |
| 513 web::NavigationItemImpl* pushedItem = [pushedEntry navigationItemImpl]; |
| 533 pushedItem->SetSerializedStateObject(stateObject); | 514 pushedItem->SetSerializedStateObject(stateObject); |
| 534 pushedItem->SetIsCreatedFromPushState(true); | 515 pushedItem->SetIsCreatedFromPushState(true); |
| 535 web::SSLStatus& sslStatus = self.currentItem->GetSSL(); | 516 web::SSLStatus& sslStatus = [self currentEntry].navigationItem->GetSSL(); |
| 536 pushedItem->GetSSL() = sslStatus; | 517 pushedEntry.get().navigationItem->GetSSL() = sslStatus; |
| 537 | 518 |
| 538 [self clearForwardItems]; | 519 [self clearForwardItems]; |
| 539 // Add the new item at the end. | 520 // Add the new entry at the end. |
| 540 _items.push_back(std::move(pushedItem)); | 521 [_entries addObject:pushedEntry]; |
| 541 _previousNavigationIndex = _currentNavigationIndex; | 522 _previousNavigationIndex = _currentNavigationIndex; |
| 542 self.currentNavigationIndex = self.items.size() - 1; | 523 self.currentNavigationIndex = [_entries count] - 1; |
| 543 | 524 |
| 544 if (_navigationManager) | 525 if (_navigationManager) |
| 545 _navigationManager->OnNavigationItemCommitted(); | 526 _navigationManager->OnNavigationItemCommitted(); |
| 546 } | 527 } |
| 547 | 528 |
| 548 - (void)updateCurrentItemWithURL:(const GURL&)url | 529 - (void)updateCurrentItemWithURL:(const GURL&)url |
| 549 stateObject:(NSString*)stateObject { | 530 stateObject:(NSString*)stateObject { |
| 550 DCHECK(!self.transientItem); | 531 DCHECK(!_transientEntry); |
| 551 web::NavigationItemImpl* currentItem = self.currentItem; | 532 CRWSessionEntry* currentEntry = self.currentEntry; |
| 533 web::NavigationItemImpl* currentItem = self.currentEntry.navigationItemImpl; |
| 552 currentItem->SetURL(url); | 534 currentItem->SetURL(url); |
| 553 currentItem->SetSerializedStateObject(stateObject); | 535 currentItem->SetSerializedStateObject(stateObject); |
| 554 currentItem->SetHasStateBeenReplaced(true); | 536 currentItem->SetHasStateBeenReplaced(true); |
| 555 currentItem->SetPostData(nil); | 537 currentItem->SetPostData(nil); |
| 556 // If the change is to a committed item, notify interested parties. | 538 currentEntry.navigationItem->SetURL(url); |
| 557 if (currentItem != self.pendingItem && _navigationManager) | 539 // If the change is to a committed entry, notify interested parties. |
| 540 if (currentEntry != self.pendingEntry && _navigationManager) |
| 558 _navigationManager->OnNavigationItemChanged(); | 541 _navigationManager->OnNavigationItemChanged(); |
| 559 } | 542 } |
| 560 | 543 |
| 561 - (void)discardNonCommittedItems { | 544 - (void)discardNonCommittedItems { |
| 562 [self discardTransientItem]; | 545 [self discardTransientItem]; |
| 563 _pendingItem.reset(); | 546 _pendingEntry.reset(); |
| 564 self.pendingItemIndex = -1; | 547 _pendingItemIndex = -1; |
| 565 } | 548 } |
| 566 | 549 |
| 567 - (void)discardTransientItem { | 550 - (void)discardTransientItem { |
| 568 _transientItem.reset(); | 551 // Keep the entry alive temporarily. There are flows that get the current |
| 552 // entry, do some navigation operation, and then try to use that old current |
| 553 // entry; since navigations clear the transient entry, these flows might |
| 554 // crash. (This should be removable once more session management is handled |
| 555 // within this class and/or NavigationManager). |
| 556 _transientEntry.reset(); |
| 569 } | 557 } |
| 570 | 558 |
| 571 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession { | 559 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession { |
| 572 DCHECK(sourceSession); | 560 DCHECK(sourceSession); |
| 573 self.windowName = sourceSession.windowName; | 561 self.windowName = sourceSession.windowName; |
| 574 | 562 |
| 575 // The other session may not have any items, in which case there is nothing | 563 // The other session may not have any entries, in which case there is nothing |
| 576 // to insert. The other session's currentItem will be bogus | 564 // to insert. The other session's currentNavigationEntry will be bogus |
| 577 // in such cases, so ignore it and return early. | 565 // in such cases, so ignore it and return early. |
| 578 web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items; | 566 NSArray* sourceEntries = sourceSession.entries; |
| 579 if (sourceItems.empty()) | 567 if (!sourceEntries.count) |
| 580 return; | 568 return; |
| 581 | 569 |
| 582 // Cycle through the items from the other session and insert them before any | 570 // Cycle through the entries from the other session and insert them before any |
| 583 // items from this session. Do not copy anything that comes after the other | 571 // entries from this session. Do not copy anything that comes after the other |
| 584 // session's current item. | 572 // session's current entry. |
| 585 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex; | 573 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex; |
| 586 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) { | 574 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) { |
| 587 std::unique_ptr<web::NavigationItemImpl> sourceItemCopy( | 575 [_entries insertObject:sourceEntries[i] atIndex:i]; |
| 588 new web::NavigationItemImpl(*sourceItems[i].get())); | |
| 589 _items.insert(_items.begin() + i, std::move(sourceItemCopy)); | |
| 590 } | 576 } |
| 591 | 577 |
| 592 // Update state to reflect inserted NavigationItems. | |
| 593 _previousNavigationIndex = -1; | 578 _previousNavigationIndex = -1; |
| 594 _currentNavigationIndex += lastIndexToCopy + 1; | 579 _currentNavigationIndex += lastIndexToCopy + 1; |
| 595 if (self.pendingItemIndex != -1) | 580 if (_pendingItemIndex != -1) |
| 596 self.pendingItemIndex += lastIndexToCopy + 1; | 581 _pendingItemIndex += lastIndexToCopy + 1; |
| 597 | 582 |
| 598 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), | 583 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), _entries.count); |
| 599 self.items.size()); | 584 DCHECK(_pendingItemIndex == -1 || _pendingEntry); |
| 600 DCHECK(self.pendingItemIndex == -1 || self.pendingItem); | |
| 601 } | 585 } |
| 602 | 586 |
| 603 - (void)goToItemAtIndex:(NSInteger)index { | 587 - (void)goToItemAtIndex:(NSInteger)index { |
| 604 if (index < 0 || static_cast<NSUInteger>(index) >= self.items.size()) | 588 if (index < 0 || static_cast<NSUInteger>(index) >= _entries.count) |
| 605 return; | 589 return; |
| 606 | 590 |
| 607 if (index < _currentNavigationIndex) { | 591 if (index < _currentNavigationIndex) { |
| 608 // Going back. | 592 // Going back. |
| 609 [self discardNonCommittedItems]; | 593 [self discardNonCommittedItems]; |
| 610 } else if (_currentNavigationIndex < index) { | 594 } else if (_currentNavigationIndex < index) { |
| 611 // Going forward. | 595 // Going forward. |
| 612 [self discardTransientItem]; | 596 [self discardTransientItem]; |
| 613 } else { | 597 } else { |
| 614 // |delta| is 0, no need to change current navigation index. | 598 // |delta| is 0, no need to change current navigation index. |
| 615 return; | 599 return; |
| 616 } | 600 } |
| 617 | 601 |
| 618 _previousNavigationIndex = _currentNavigationIndex; | 602 _previousNavigationIndex = _currentNavigationIndex; |
| 619 _currentNavigationIndex = index; | 603 _currentNavigationIndex = index; |
| 620 } | 604 } |
| 621 | 605 |
| 622 - (void)removeItemAtIndex:(NSInteger)index { | 606 - (void)removeItemAtIndex:(NSInteger)index { |
| 623 DCHECK(index < static_cast<NSInteger>(self.items.size())); | 607 DCHECK(index < static_cast<NSInteger>([_entries count])); |
| 624 DCHECK(index != _currentNavigationIndex); | 608 DCHECK(index != _currentNavigationIndex); |
| 625 DCHECK(index >= 0); | 609 DCHECK(index >= 0); |
| 626 | 610 |
| 627 [self discardNonCommittedItems]; | 611 [self discardNonCommittedItems]; |
| 628 | 612 |
| 629 _items.erase(_items.begin() + index); | 613 [_entries removeObjectAtIndex:index]; |
| 630 if (_currentNavigationIndex > index) | 614 if (_currentNavigationIndex > index) |
| 631 _currentNavigationIndex--; | 615 _currentNavigationIndex--; |
| 632 if (_previousNavigationIndex >= index) | 616 if (_previousNavigationIndex >= index) |
| 633 _previousNavigationIndex--; | 617 _previousNavigationIndex--; |
| 634 } | 618 } |
| 635 | 619 |
| 620 - (NSArray*)backwardEntries { |
| 621 NSMutableArray* entries = [NSMutableArray array]; |
| 622 for (NSInteger index = _currentNavigationIndex; index > 0; --index) { |
| 623 if (![self isRedirectTransitionForItemAtIndex:index]) |
| 624 [entries addObject:_entries[index - 1]]; |
| 625 } |
| 626 return entries; |
| 627 } |
| 628 |
| 629 - (NSArray*)forwardEntries { |
| 630 NSMutableArray* entries = [NSMutableArray array]; |
| 631 NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1; |
| 632 while (lastNonRedirectedIndex < [_entries count]) { |
| 633 CRWSessionEntry* entry = [_entries objectAtIndex:lastNonRedirectedIndex]; |
| 634 if (!ui::PageTransitionIsRedirect( |
| 635 entry.navigationItem->GetTransitionType())) { |
| 636 [entries addObject:entry]; |
| 637 } |
| 638 ++lastNonRedirectedIndex; |
| 639 } |
| 640 return entries; |
| 641 } |
| 642 |
| 636 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem | 643 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem |
| 637 andItem:(web::NavigationItem*)secondItem { | 644 andItem:(web::NavigationItem*)secondItem { |
| 638 if (!firstItem || !secondItem || firstItem == secondItem) | 645 if (!firstItem || !secondItem || firstItem == secondItem) |
| 639 return NO; | 646 return NO; |
| 640 NSUInteger firstIndex = [self indexOfItem:firstItem]; | 647 NSUInteger firstIndex = [self indexOfItem:firstItem]; |
| 641 NSUInteger secondIndex = [self indexOfItem:secondItem]; | 648 NSUInteger secondIndex = [self indexOfItem:secondItem]; |
| 642 if (firstIndex == NSNotFound || secondIndex == NSNotFound) | 649 if (firstIndex == NSNotFound || secondIndex == NSNotFound) |
| 643 return NO; | 650 return NO; |
| 644 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex; | 651 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex; |
| 645 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex; | 652 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex; |
| 646 | 653 |
| 647 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) { | 654 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) { |
| 648 web::NavigationItemImpl* item = self.items[i].get(); | 655 web::NavigationItemImpl* item = [_entries[i] navigationItemImpl]; |
| 649 // Every item in the sequence has to be created from a hash change or | 656 // Every entry in the sequence has to be created from a hash change or |
| 650 // pushState() call. | 657 // pushState() call. |
| 651 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange()) | 658 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange()) |
| 652 return NO; | 659 return NO; |
| 653 // Every item in the sequence has to have a URL that could have been | 660 // Every entry in the sequence has to have a URL that could have been |
| 654 // created from a pushState() call. | 661 // created from a pushState() call. |
| 655 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(), | 662 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(), |
| 656 item->GetURL())) | 663 item->GetURL())) |
| 657 return NO; | 664 return NO; |
| 658 } | 665 } |
| 659 return YES; | 666 return YES; |
| 660 } | 667 } |
| 661 | 668 |
| 669 - (CRWSessionEntry*)lastUserEntry { |
| 670 if (![_entries count]) |
| 671 return nil; |
| 672 |
| 673 NSInteger index = _currentNavigationIndex; |
| 674 // This will return the first session entry if all other entries are |
| 675 // redirects, regardless of the transition state of the first entry. |
| 676 while (index > 0 && [self isRedirectTransitionForItemAtIndex:index]) { |
| 677 --index; |
| 678 } |
| 679 return [_entries objectAtIndex:index]; |
| 680 } |
| 681 |
| 662 - (void)useDesktopUserAgentForNextPendingItem { | 682 - (void)useDesktopUserAgentForNextPendingItem { |
| 663 if (self.pendingItem) | 683 if (_pendingEntry) |
| 664 self.pendingItem->SetIsOverridingUserAgent(true); | 684 [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true); |
| 665 else | 685 else |
| 666 _useDesktopUserAgentForNextPendingItem = YES; | 686 _useDesktopUserAgentForNextPendingItem = YES; |
| 667 } | 687 } |
| 668 | 688 |
| 669 - (NSInteger)indexOfItem:(web::NavigationItem*)item { | 689 - (NSInteger)indexOfItem:(web::NavigationItem*)item { |
| 670 DCHECK(item); | 690 web::NavigationItemList items = self.items; |
| 671 for (size_t index = 0; index < self.items.size(); ++index) { | 691 for (NSInteger i = 0; i < static_cast<NSInteger>(items.size()); ++i) { |
| 672 if (self.items[index].get() == item) | 692 if (items[i] == item) |
| 673 return index; | 693 return i; |
| 674 } | 694 } |
| 675 return NSNotFound; | 695 return NSNotFound; |
| 676 } | 696 } |
| 677 | 697 |
| 678 #pragma mark - | 698 #pragma mark - |
| 679 #pragma mark Private methods | 699 #pragma mark Private methods |
| 680 | 700 |
| 681 - (NSString*)uniqueID { | 701 - (NSString*)uniqueID { |
| 682 CFUUIDRef uuidRef = CFUUIDCreate(NULL); | 702 CFUUIDRef uuidRef = CFUUIDCreate(NULL); |
| 683 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); | 703 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); |
| 684 CFRelease(uuidRef); | 704 CFRelease(uuidRef); |
| 685 | 705 |
| 686 NSString* uuid = | 706 NSString* uuid = |
| 687 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>( | 707 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>( |
| 688 CFBridgingRelease(uuidStringRef))]; | 708 CFBridgingRelease(uuidStringRef))]; |
| 689 return uuid; | 709 return uuid; |
| 690 } | 710 } |
| 691 | 711 |
| 692 - (std::unique_ptr<web::NavigationItemImpl>) | 712 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url |
| 693 itemWithURL:(const GURL&)url | 713 referrer:(const web::Referrer&)referrer |
| 694 referrer:(const web::Referrer&)referrer | 714 transition:(ui::PageTransition)transition |
| 695 transition:(ui::PageTransition)transition | 715 useDesktopUserAgent:(BOOL)useDesktopUserAgent |
| 696 useDesktopUserAgent:(BOOL)useDesktopUserAgent | 716 rendererInitiated:(BOOL)rendererInitiated { |
| 697 rendererInitiated:(BOOL)rendererInitiated { | |
| 698 GURL loaded_url(url); | 717 GURL loaded_url(url); |
| 699 BOOL urlWasRewritten = NO; | 718 BOOL urlWasRewritten = NO; |
| 700 if (_navigationManager) { | 719 if (_navigationManager) { |
| 701 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>> | 720 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>> |
| 702 transientRewriters = _navigationManager->GetTransientURLRewriters(); | 721 transientRewriters = _navigationManager->GetTransientURLRewriters(); |
| 703 if (transientRewriters) { | 722 if (transientRewriters) { |
| 704 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters( | 723 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters( |
| 705 &loaded_url, _browserState, *transientRewriters.get()); | 724 &loaded_url, _browserState, *transientRewriters.get()); |
| 706 } | 725 } |
| 707 } | 726 } |
| 708 if (!urlWasRewritten) { | 727 if (!urlWasRewritten) { |
| 709 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary( | 728 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary( |
| 710 &loaded_url, _browserState); | 729 &loaded_url, _browserState); |
| 711 } | 730 } |
| 712 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); | 731 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); |
| 713 item->SetOriginalRequestURL(loaded_url); | 732 item->SetOriginalRequestURL(loaded_url); |
| 714 item->SetURL(loaded_url); | 733 item->SetURL(loaded_url); |
| 715 item->SetReferrer(referrer); | 734 item->SetReferrer(referrer); |
| 716 item->SetTransitionType(transition); | 735 item->SetTransitionType(transition); |
| 717 item->SetIsOverridingUserAgent(useDesktopUserAgent); | 736 item->SetIsOverridingUserAgent(useDesktopUserAgent); |
| 718 item->set_is_renderer_initiated(rendererInitiated); | 737 item->set_is_renderer_initiated(rendererInitiated); |
| 719 return item; | 738 return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]; |
| 720 } | 739 } |
| 721 | 740 |
| 722 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index { | 741 - (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index { |
| 723 DCHECK_LT(index, self.items.size()); | 742 ui::PageTransition transition = |
| 724 ui::PageTransition transition = self.items[index]->GetTransitionType(); | 743 [_entries[index] navigationItem]->GetTransitionType(); |
| 725 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO; | 744 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO; |
| 726 } | 745 } |
| 727 | 746 |
| 728 - (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item { | 747 - (web::NavigationItemList)itemListForEntryList:(NSArray*)entries { |
| 729 if (!item) | 748 web::NavigationItemList list(entries.count); |
| 730 return nil; | 749 for (size_t index = 0; index < entries.count; ++index) |
| 731 // CRWSessionEntries vended by a CRWSessionController should always correspond | 750 list[index] = [entries[index] navigationItem]; |
| 732 // with a NavigationItem that is owned by that CRWSessionController. | 751 return list; |
| 733 DCHECK([self indexOfItem:item] != NSNotFound || item == _pendingItem.get() || | |
| 734 item == _transientItem.get()); | |
| 735 return [[CRWSessionEntry alloc] initWithNavigationItem:item]; | |
| 736 } | |
| 737 | |
| 738 - (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList { | |
| 739 NSMutableArray* entryList = | |
| 740 [[NSMutableArray alloc] initWithCapacity:itemList.size()]; | |
| 741 for (web::NavigationItem* item : itemList) { | |
| 742 CRWSessionEntry* entry = | |
| 743 [self entryForItem:static_cast<web::NavigationItemImpl*>(item)]; | |
| 744 [entryList addObject:entry]; | |
| 745 } | |
| 746 return entryList; | |
| 747 } | 752 } |
| 748 | 753 |
| 749 @end | 754 @end |
| OLD | NEW |