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