Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(517)

Side by Side Diff: ios/web/navigation/crw_session_controller.mm

Issue 2672953005: Updated ownership of NavigationItems within CRWSessionController. (Closed)
Patch Set: fix unittests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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>
10 #include <utility> 11 #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
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;
67 52
68 // The window name associated with the session. 53 // The window name associated with the session.
69 NSString* _windowName; 54 NSString* _windowName;
70 55
71 // Stores the certificate policies decided by the user. 56 // Stores the certificate policies decided by the user.
72 CRWSessionCertificatePolicyManager* _sessionCertificatePolicyManager; 57 CRWSessionCertificatePolicyManager* _sessionCertificatePolicyManager;
73 58
74 // The timestamp of the last time this tab is visited, represented in time 59 // The timestamp of the last time this tab is visited, represented in time
75 // interval since 1970. 60 // interval since 1970.
76 NSTimeInterval _lastVisitedTimestamp; 61 NSTimeInterval _lastVisitedTimestamp;
77 62
78 // If |YES|, override |currentEntry.useDesktopUserAgent| and create the 63 // If |YES|, override |currentEntry.useDesktopUserAgent| and create the
79 // pending entry using the desktop user agent. 64 // pending item using the desktop user agent.
80 BOOL _useDesktopUserAgentForNextPendingItem; 65 BOOL _useDesktopUserAgentForNextPendingItem;
81 66
82 // The browser state associated with this CRWSessionController; 67 // The browser state associated with this CRWSessionController;
83 web::BrowserState* _browserState; // weak 68 web::BrowserState* _browserState; // weak
84 69
85 // Time smoother for navigation entry timestamps; see comment in 70 // Time smoother for navigation item timestamps; see comment in
86 // navigation_controller_impl.h 71 // navigation_controller_impl.h
87 web::TimeSmoother _timeSmoother; 72 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;
88 } 82 }
89 83
90 // Redefine as readwrite. 84 // Redefine as readwrite.
91 @property(nonatomic, readwrite, assign) NSInteger currentNavigationIndex; 85 @property(nonatomic, readwrite, assign) NSInteger currentNavigationIndex;
92 86
93 // TODO(rohitrao): These properties must be redefined readwrite to work around a 87 // TODO(rohitrao): These properties must be redefined readwrite to work around a
94 // clang bug. crbug.com/228650 88 // clang bug. crbug.com/228650
95 @property(nonatomic, readwrite, copy) NSString* tabId; 89 @property(nonatomic, readwrite, copy) NSString* tabId;
96 @property(nonatomic, readwrite, strong) NSArray* entries;
97 @property(nonatomic, readwrite, strong) 90 @property(nonatomic, readwrite, strong)
98 CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager; 91 CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager;
99 92
100 // Expose setters for serialization properties. These are exposed in a category 93 // Expose setters for serialization properties. These are exposed in a category
101 // in NavigationManagerStorageBuilder, and will be removed as ownership of 94 // in NavigationManagerStorageBuilder, and will be removed as ownership of
102 // their backing ivars moves to NavigationManagerImpl. 95 // their backing ivars moves to NavigationManagerImpl.
103 @property(nonatomic, readwrite, copy) NSString* openerId; 96 @property(nonatomic, readwrite, copy) NSString* openerId;
104 @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM; 97 @property(nonatomic, readwrite, getter=isOpenedByDOM) BOOL openedByDOM;
105 @property(nonatomic, readwrite, assign) NSInteger openerNavigationIndex; 98 @property(nonatomic, readwrite, assign) NSInteger openerNavigationIndex;
106 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex; 99 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex;
107 100
108 - (NSString*)uniqueID; 101 - (NSString*)uniqueID;
109 // Removes all entries after currentNavigationIndex_. 102 // Removes all items after currentNavigationIndex_.
110 - (void)clearForwardItems; 103 - (void)clearForwardItems;
111 // Discards the transient entry, if any. 104 // Discards the transient item, if any.
112 - (void)discardTransientItem; 105 - (void)discardTransientItem;
113 // Create a new autoreleased session entry. 106 // Creates a NavigationItemImpl with the specified properties.
114 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url 107 - (std::unique_ptr<web::NavigationItemImpl>)
115 referrer:(const web::Referrer&)referrer 108 itemWithURL:(const GURL&)url
116 transition:(ui::PageTransition)transition 109 referrer:(const web::Referrer&)referrer
117 useDesktopUserAgent:(BOOL)useDesktopUserAgent 110 transition:(ui::PageTransition)transition
118 rendererInitiated:(BOOL)rendererInitiated; 111 useDesktopUserAgent:(BOOL)useDesktopUserAgent
112 rendererInitiated:(BOOL)rendererInitiated;
119 // Returns YES if the PageTransition for the underlying navigationItem at 113 // Returns YES if the PageTransition for the underlying navigationItem at
120 // |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK. 114 // |index| in |items| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
121 - (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index; 115 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index;
122 // Returns a NavigationItemList containing the NavigationItems from |entries|. 116 // Returns the CRWSessionEntry corresponding with |item|.
123 - (web::NavigationItemList)itemListForEntryList:(NSArray*)entries; 117 - (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item;
118 // Returns an autoreleased NSArray containing CRWSessionEntries corresponding
119 // with the NavigationItems in |itemList|.
120 - (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList;
121
124 @end 122 @end
125 123
126 @implementation CRWSessionController 124 @implementation CRWSessionController
127 125
128 @synthesize tabId = _tabId; 126 @synthesize tabId = _tabId;
129 @synthesize currentNavigationIndex = _currentNavigationIndex; 127 @synthesize currentNavigationIndex = _currentNavigationIndex;
130 @synthesize previousNavigationIndex = _previousNavigationIndex; 128 @synthesize previousNavigationIndex = _previousNavigationIndex;
131 @synthesize pendingItemIndex = _pendingItemIndex; 129 @synthesize pendingItemIndex = _pendingItemIndex;
132 @synthesize entries = _entries;
133 @synthesize windowName = _windowName; 130 @synthesize windowName = _windowName;
134 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp; 131 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp;
135 @synthesize openerId = _openerId; 132 @synthesize openerId = _openerId;
136 @synthesize openedByDOM = _openedByDOM; 133 @synthesize openedByDOM = _openedByDOM;
137 @synthesize openerNavigationIndex = _openerNavigationIndex; 134 @synthesize openerNavigationIndex = _openerNavigationIndex;
138 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager; 135 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager;
139 136
140 - (id)initWithWindowName:(NSString*)windowName 137 - (id)initWithWindowName:(NSString*)windowName
141 openerId:(NSString*)openerId 138 openerId:(NSString*)openerId
142 openedByDOM:(BOOL)openedByDOM 139 openedByDOM:(BOOL)openedByDOM
143 openerNavigationIndex:(NSInteger)openerIndex 140 openerNavigationIndex:(NSInteger)openerIndex
144 browserState:(web::BrowserState*)browserState { 141 browserState:(web::BrowserState*)browserState {
145 self = [super init]; 142 self = [super init];
146 if (self) { 143 if (self) {
147 self.windowName = windowName; 144 self.windowName = windowName;
148 _tabId = [[self uniqueID] copy]; 145 _tabId = [[self uniqueID] copy];
149 _openerId = [openerId copy]; 146 _openerId = [openerId copy];
150 _openedByDOM = openedByDOM; 147 _openedByDOM = openedByDOM;
151 _openerNavigationIndex = openerIndex; 148 _openerNavigationIndex = openerIndex;
152 _browserState = browserState; 149 _browserState = browserState;
153 _entries = [NSMutableArray array];
154 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; 150 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
155 _currentNavigationIndex = -1; 151 _currentNavigationIndex = -1;
156 _previousNavigationIndex = -1; 152 _previousNavigationIndex = -1;
157 _pendingItemIndex = -1; 153 _pendingItemIndex = -1;
158 _sessionCertificatePolicyManager = 154 _sessionCertificatePolicyManager =
159 [[CRWSessionCertificatePolicyManager alloc] init]; 155 [[CRWSessionCertificatePolicyManager alloc] init];
160 } 156 }
161 return self; 157 return self;
162 } 158 }
163 159
164 - (id)initWithNavigationItems: 160 - (id)initWithNavigationItems:(web::ScopedNavigationItemList)items
165 (std::vector<std::unique_ptr<web::NavigationItem>>)items
166 currentIndex:(NSUInteger)currentIndex 161 currentIndex:(NSUInteger)currentIndex
167 browserState:(web::BrowserState*)browserState { 162 browserState:(web::BrowserState*)browserState {
168 self = [super init]; 163 self = [super init];
169 if (self) { 164 if (self) {
170 _tabId = [[self uniqueID] copy]; 165 _tabId = [[self uniqueID] copy];
171 _openerId = nil; 166 _openerId = nil;
172 _browserState = browserState; 167 _browserState = browserState;
173 168 _items = web::CreateScopedNavigationItemImplList(std::move(items));
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 }
182 self.currentNavigationIndex = currentIndex; 169 self.currentNavigationIndex = currentIndex;
183 // Prior to M34, 0 was used as "no index" instead of -1; adjust for that. 170 if (_items.empty())
184 if (![_entries count])
185 self.currentNavigationIndex = -1; 171 self.currentNavigationIndex = -1;
186 if (_currentNavigationIndex >= static_cast<NSInteger>(items.size())) { 172 _currentNavigationIndex = std::min(
187 self.currentNavigationIndex = static_cast<NSInteger>(items.size()) - 1; 173 _currentNavigationIndex, static_cast<NSInteger>(_items.size() - 1));
188 }
189 _previousNavigationIndex = -1; 174 _previousNavigationIndex = -1;
190 _pendingItemIndex = -1; 175 _pendingItemIndex = -1;
191 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; 176 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
192 _sessionCertificatePolicyManager = 177 _sessionCertificatePolicyManager =
193 [[CRWSessionCertificatePolicyManager alloc] init]; 178 [[CRWSessionCertificatePolicyManager alloc] init];
194 } 179 }
195 return self; 180 return self;
196 } 181 }
197 182
198 - (id)copyWithZone:(NSZone*)zone { 183 #pragma mark - Accessors
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 }
215 184
216 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex { 185 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
217 if (_currentNavigationIndex != currentNavigationIndex) { 186 if (_currentNavigationIndex != currentNavigationIndex) {
218 _currentNavigationIndex = currentNavigationIndex; 187 _currentNavigationIndex = currentNavigationIndex;
219 if (_navigationManager) 188 if (_navigationManager)
220 _navigationManager->RemoveTransientURLRewriters(); 189 _navigationManager->RemoveTransientURLRewriters();
221 } 190 }
222 } 191 }
223 192
224 - (void)setPendingItemIndex:(NSInteger)index { 193 - (void)setPendingItemIndex:(NSInteger)pendingItemIndex {
225 DCHECK_GE(index, -1); 194 DCHECK_GE(pendingItemIndex, -1);
226 DCHECK_LT(index, static_cast<NSInteger>(_entries.count)); 195 DCHECK_LT(pendingItemIndex, static_cast<NSInteger>(self.items.size()));
227 _pendingItemIndex = index; 196 _pendingItemIndex = pendingItemIndex;
228 CRWSessionEntry* entry = index != -1 ? _entries[index] : nil; 197 DCHECK(_pendingItemIndex == -1 || self.pendingItem);
229 _pendingEntry.reset(entry);
230 DCHECK(_pendingItemIndex == -1 || _pendingEntry);
231 } 198 }
232 199
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
233 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager { 368 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager {
234 _navigationManager = navigationManager; 369 _navigationManager = navigationManager;
235 if (_navigationManager) { 370 if (_navigationManager) {
236 // _browserState will be nullptr if CRWSessionController has been 371 // _browserState will be nullptr if CRWSessionController has been
237 // initialized with -initWithCoder: method. Take _browserState from 372 // initialized with -initWithCoder: method. Take _browserState from
238 // NavigationManagerImpl if that's the case. 373 // NavigationManagerImpl if that's the case.
239 if (!_browserState) { 374 if (!_browserState) {
240 _browserState = _navigationManager->GetBrowserState(); 375 _browserState = _navigationManager->GetBrowserState();
241 } 376 }
242 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState()); 377 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState());
243 } 378 }
244 } 379 }
245 380
246 - (void)setBrowserState:(web::BrowserState*)browserState { 381 - (void)setBrowserState:(web::BrowserState*)browserState {
247 _browserState = browserState; 382 _browserState = browserState;
248 DCHECK(!_navigationManager || 383 DCHECK(!_navigationManager ||
249 _navigationManager->GetBrowserState() == _browserState); 384 _navigationManager->GetBrowserState() == _browserState);
250 } 385 }
251 386
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
351 - (void)addPendingItem:(const GURL&)url 387 - (void)addPendingItem:(const GURL&)url
352 referrer:(const web::Referrer&)ref 388 referrer:(const web::Referrer&)ref
353 transition:(ui::PageTransition)trans 389 transition:(ui::PageTransition)trans
354 rendererInitiated:(BOOL)rendererInitiated { 390 rendererInitiated:(BOOL)rendererInitiated {
355 [self discardTransientItem]; 391 [self discardTransientItem];
356 _pendingItemIndex = -1; 392 self.pendingItemIndex = -1;
357 393
358 // Don't create a new entry if it's already the same as the current entry, 394 // Don't create a new item if it's already the same as the current item,
359 // allowing this routine to be called multiple times in a row without issue. 395 // allowing this routine to be called multiple times in a row without issue.
360 // Note: CRWSessionController currently has the responsibility to distinguish 396 // Note: CRWSessionController currently has the responsibility to distinguish
361 // between new navigations and history stack navigation, hence the inclusion 397 // between new navigations and history stack navigation, hence the inclusion
362 // of specific transiton type logic here, in order to make it reliable with 398 // of specific transiton type logic here, in order to make it reliable with
363 // real-world observed behavior. 399 // real-world observed behavior.
364 // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere 400 // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere
365 // in the web layer so that this hack can be removed. 401 // in the web layer so that this hack can be removed.
366 // Remove the workaround code from -presentSafeBrowsingWarningForResource:. 402 // Remove the workaround code from -presentSafeBrowsingWarningForResource:.
367 CRWSessionEntry* currentEntry = self.currentEntry; 403 web::NavigationItemImpl* currentItem = self.currentItem;
368 if (currentEntry) { 404 if (currentItem && currentItem->GetURL() == url &&
369 web::NavigationItem* item = [currentEntry navigationItem]; 405 (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
370 if (item->GetURL() == url && 406 PageTransitionCoreTypeIs(currentItem->GetTransitionType(),
371 (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) || 407 ui::PAGE_TRANSITION_FORM_SUBMIT))) {
372 PageTransitionCoreTypeIs(item->GetTransitionType(), 408 // Send the notification anyway, to preserve old behavior. It's unknown
373 ui::PAGE_TRANSITION_FORM_SUBMIT))) { 409 // whether anything currently relies on this, but since both this whole
374 // Send the notification anyway, to preserve old behavior. It's unknown 410 // hack and the content facade will both be going away, it's not worth
375 // whether anything currently relies on this, but since both this whole 411 // trying to unwind.
376 // hack and the content facade will both be going away, it's not worth 412 if (_navigationManager && _navigationManager->GetFacadeDelegate())
377 // trying to unwind. 413 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
378 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 414 return;
379 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
380 }
381 return;
382 }
383 } 415 }
384 416
385 BOOL useDesktopUserAgent = 417 BOOL useDesktopUserAgent =
386 _useDesktopUserAgentForNextPendingItem || 418 _useDesktopUserAgentForNextPendingItem ||
387 (self.currentEntry.navigationItem && 419 (currentItem && currentItem->IsOverridingUserAgent());
388 self.currentEntry.navigationItem->IsOverridingUserAgent());
389 _useDesktopUserAgentForNextPendingItem = NO; 420 _useDesktopUserAgentForNextPendingItem = NO;
390 _pendingEntry.reset([self sessionEntryWithURL:url 421 _pendingItem = [self itemWithURL:url
391 referrer:ref 422 referrer:ref
392 transition:trans 423 transition:trans
393 useDesktopUserAgent:useDesktopUserAgent 424 useDesktopUserAgent:useDesktopUserAgent
394 rendererInitiated:rendererInitiated]); 425 rendererInitiated:rendererInitiated];
395 426
396 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 427 if (_navigationManager && _navigationManager->GetFacadeDelegate())
397 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 428 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
398 }
399 } 429 }
400 430
401 - (void)updatePendingItem:(const GURL&)url { 431 - (void)updatePendingItem:(const GURL&)url {
402 // If there is no pending entry, navigation is probably happening within the 432 // If there is no pending item, navigation is probably happening within the
403 // session history. Don't modify the entry list. 433 // session history. Don't modify the item list.
404 if (!_pendingEntry) 434 web::NavigationItemImpl* item = self.pendingItem;
435 if (!item)
405 return; 436 return;
406 437
407 web::NavigationItemImpl* item = [_pendingEntry navigationItemImpl];
408 if (url != item->GetURL()) { 438 if (url != item->GetURL()) {
409 // Assume a redirection, and discard any transient entry. 439 // Assume a redirection, and discard any transient item.
410 // TODO(stuartmorgan): Once the current safe browsing code is gone, 440 // TODO(stuartmorgan): Once the current safe browsing code is gone,
411 // consider making this a DCHECK that there's no transient entry. 441 // consider making this a DCHECK that there's no transient item.
412 [self discardTransientItem]; 442 [self discardTransientItem];
413 443
414 item->SetURL(url); 444 item->SetURL(url);
415 item->SetVirtualURL(url); 445 item->SetVirtualURL(url);
416 // Redirects (3xx response code), or client side navigation must change 446 // Redirects (3xx response code), or client side navigation must change
417 // POST requests to GETs. 447 // POST requests to GETs.
418 item->SetPostData(nil); 448 item->SetPostData(nil);
419 item->ResetHttpRequestHeaders(); 449 item->ResetHttpRequestHeaders();
420 } 450 }
421 451
422 // This should probably not be sent if the URLs matched, but that's what was 452 // This should probably not be sent if the URLs matched, but that's what was
423 // done before, so preserve behavior in case something relies on it. 453 // done before, so preserve behavior in case something relies on it.
424 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 454 if (_navigationManager && _navigationManager->GetFacadeDelegate())
425 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 455 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
426 }
427 } 456 }
428 457
429 - (void)clearForwardItems { 458 - (void)clearForwardItems {
430 DCHECK_EQ(_pendingItemIndex, -1); 459 DCHECK_EQ(self.pendingItemIndex, -1);
431 [self discardTransientItem]; 460 [self discardTransientItem];
432 461
433 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1; 462 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1;
434 DCHECK(forwardItemStartIndex >= 0); 463 DCHECK(forwardItemStartIndex >= 0);
435 464
436 if (forwardItemStartIndex >= static_cast<NSInteger>([_entries count])) 465 size_t itemCount = self.items.size();
466 if (forwardItemStartIndex >= static_cast<NSInteger>(itemCount))
437 return; 467 return;
438 468
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];
446 if (_previousNavigationIndex >= forwardItemStartIndex) 469 if (_previousNavigationIndex >= forwardItemStartIndex)
447 _previousNavigationIndex = -1; 470 _previousNavigationIndex = -1;
448 if (_navigationManager) { 471 if (_navigationManager)
449 _navigationManager->OnNavigationItemsPruned(remove.length); 472 _navigationManager->OnNavigationItemsPruned(self.items.size() -
450 } 473 forwardItemStartIndex);
474
475 // Remove the NavigationItems.
476 _items.erase(_items.begin() + forwardItemStartIndex, _items.end());
451 } 477 }
452 478
453 - (void)commitPendingItem { 479 - (void)commitPendingItem {
454 if (_pendingEntry) { 480 if (self.pendingItem) {
455 NSInteger newNavigationIndex = _pendingItemIndex; 481 // Once an item is committed it's not renderer-initiated any more. (Matches
456 if (_pendingItemIndex == -1) { 482 // the implementation in NavigationController.)
483 self.pendingItem->ResetForCommit();
484
485 NSInteger newNavigationIndex = self.pendingItemIndex;
486 if (newNavigationIndex == -1) {
457 [self clearForwardItems]; 487 [self clearForwardItems];
458 // Add the new entry at the end. 488 // Add the new item at the end.
459 [_entries addObject:_pendingEntry]; 489 _items.push_back(std::move(_pendingItem));
460 newNavigationIndex = [_entries count] - 1; 490 newNavigationIndex = self.items.size() - 1;
461 } 491 }
462 _previousNavigationIndex = _currentNavigationIndex; 492 _previousNavigationIndex = _currentNavigationIndex;
463 self.currentNavigationIndex = newNavigationIndex; 493 self.currentNavigationIndex = newNavigationIndex;
464 // Once an entry is committed it's not renderer-initiated any more. (Matches 494 self.pendingItemIndex = -1;
465 // the implementation in NavigationController.)
466 [_pendingEntry navigationItemImpl]->ResetForCommit();
467 _pendingEntry.reset();
468 _pendingItemIndex = -1;
469 } 495 }
470 496
471 CRWSessionEntry* currentEntry = self.currentEntry; 497 web::NavigationItem* item = self.currentItem;
472 web::NavigationItem* item = currentEntry.navigationItem;
473 // Update the navigation timestamp now that it's actually happened. 498 // Update the navigation timestamp now that it's actually happened.
474 if (item) 499 if (item)
475 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now())); 500 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now()));
476 501
477 if (_navigationManager && item) 502 if (_navigationManager && item)
478 _navigationManager->OnNavigationItemCommitted(); 503 _navigationManager->OnNavigationItemCommitted();
479 DCHECK_EQ(_pendingItemIndex, -1); 504 DCHECK_EQ(self.pendingItemIndex, -1);
480 } 505 }
481 506
482 - (void)addTransientItemWithURL:(const GURL&)URL { 507 - (void)addTransientItemWithURL:(const GURL&)URL {
483 _transientEntry.reset([self 508 _transientItem = [self itemWithURL:URL
484 sessionEntryWithURL:URL 509 referrer:web::Referrer()
485 referrer:web::Referrer() 510 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
486 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT 511 useDesktopUserAgent:NO
487 useDesktopUserAgent:NO 512 rendererInitiated:NO];
488 rendererInitiated:NO]); 513 _transientItem->SetTimestamp(
489
490 web::NavigationItem* navigationItem = [_transientEntry navigationItem];
491 DCHECK(navigationItem);
492 navigationItem->SetTimestamp(
493 _timeSmoother.GetSmoothedTime(base::Time::Now())); 514 _timeSmoother.GetSmoothedTime(base::Time::Now()));
494 } 515 }
495 516
496 - (void)pushNewItemWithURL:(const GURL&)URL 517 - (void)pushNewItemWithURL:(const GURL&)URL
497 stateObject:(NSString*)stateObject 518 stateObject:(NSString*)stateObject
498 transition:(ui::PageTransition)transition { 519 transition:(ui::PageTransition)transition {
499 DCHECK(![self pendingEntry]); 520 DCHECK(!self.pendingItem);
500 DCHECK([self currentEntry]); 521 web::NavigationItem* item = self.currentItem;
501 web::NavigationItem* item = [self currentEntry].navigationItem; 522 DCHECK(item);
502 CHECK( 523 CHECK(
503 web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL)); 524 web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL));
504 web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault); 525 web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault);
505 bool overrideUserAgent = 526 bool overrideUserAgent = self.currentItem->IsOverridingUserAgent();
506 self.currentEntry.navigationItem->IsOverridingUserAgent(); 527 std::unique_ptr<web::NavigationItemImpl> pushedItem =
507 base::scoped_nsobject<CRWSessionEntry> pushedEntry([self 528 [self itemWithURL:URL
508 sessionEntryWithURL:URL 529 referrer:referrer
509 referrer:referrer 530 transition:transition
510 transition:transition 531 useDesktopUserAgent:overrideUserAgent
511 useDesktopUserAgent:overrideUserAgent 532 rendererInitiated:NO];
512 rendererInitiated:NO]);
513 web::NavigationItemImpl* pushedItem = [pushedEntry navigationItemImpl];
514 pushedItem->SetSerializedStateObject(stateObject); 533 pushedItem->SetSerializedStateObject(stateObject);
515 pushedItem->SetIsCreatedFromPushState(true); 534 pushedItem->SetIsCreatedFromPushState(true);
516 web::SSLStatus& sslStatus = [self currentEntry].navigationItem->GetSSL(); 535 web::SSLStatus& sslStatus = self.currentItem->GetSSL();
517 pushedEntry.get().navigationItem->GetSSL() = sslStatus; 536 pushedItem->GetSSL() = sslStatus;
518 537
519 [self clearForwardItems]; 538 [self clearForwardItems];
520 // Add the new entry at the end. 539 // Add the new item at the end.
521 [_entries addObject:pushedEntry]; 540 _items.push_back(std::move(pushedItem));
522 _previousNavigationIndex = _currentNavigationIndex; 541 _previousNavigationIndex = _currentNavigationIndex;
523 self.currentNavigationIndex = [_entries count] - 1; 542 self.currentNavigationIndex = self.items.size() - 1;
524 543
525 if (_navigationManager) 544 if (_navigationManager)
526 _navigationManager->OnNavigationItemCommitted(); 545 _navigationManager->OnNavigationItemCommitted();
527 } 546 }
528 547
529 - (void)updateCurrentItemWithURL:(const GURL&)url 548 - (void)updateCurrentItemWithURL:(const GURL&)url
530 stateObject:(NSString*)stateObject { 549 stateObject:(NSString*)stateObject {
531 DCHECK(!_transientEntry); 550 DCHECK(!self.transientItem);
532 CRWSessionEntry* currentEntry = self.currentEntry; 551 web::NavigationItemImpl* currentItem = self.currentItem;
533 web::NavigationItemImpl* currentItem = self.currentEntry.navigationItemImpl;
534 currentItem->SetURL(url); 552 currentItem->SetURL(url);
535 currentItem->SetSerializedStateObject(stateObject); 553 currentItem->SetSerializedStateObject(stateObject);
536 currentItem->SetHasStateBeenReplaced(true); 554 currentItem->SetHasStateBeenReplaced(true);
537 currentItem->SetPostData(nil); 555 currentItem->SetPostData(nil);
538 currentEntry.navigationItem->SetURL(url); 556 // If the change is to a committed item, notify interested parties.
539 // If the change is to a committed entry, notify interested parties. 557 if (currentItem != self.pendingItem && _navigationManager)
540 if (currentEntry != self.pendingEntry && _navigationManager)
541 _navigationManager->OnNavigationItemChanged(); 558 _navigationManager->OnNavigationItemChanged();
542 } 559 }
543 560
544 - (void)discardNonCommittedItems { 561 - (void)discardNonCommittedItems {
545 [self discardTransientItem]; 562 [self discardTransientItem];
546 _pendingEntry.reset(); 563 _pendingItem.reset();
547 _pendingItemIndex = -1; 564 self.pendingItemIndex = -1;
548 } 565 }
549 566
550 - (void)discardTransientItem { 567 - (void)discardTransientItem {
551 // Keep the entry alive temporarily. There are flows that get the current 568 _transientItem.reset();
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();
557 } 569 }
558 570
559 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession { 571 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession {
560 DCHECK(sourceSession); 572 DCHECK(sourceSession);
561 self.windowName = sourceSession.windowName; 573 self.windowName = sourceSession.windowName;
562 574
563 // The other session may not have any entries, in which case there is nothing 575 // The other session may not have any items, in which case there is nothing
564 // to insert. The other session's currentNavigationEntry will be bogus 576 // to insert. The other session's currentItem will be bogus
565 // in such cases, so ignore it and return early. 577 // in such cases, so ignore it and return early.
566 NSArray* sourceEntries = sourceSession.entries; 578 web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items;
567 if (!sourceEntries.count) 579 if (sourceItems.empty())
568 return; 580 return;
569 581
570 // Cycle through the entries from the other session and insert them before any 582 // Cycle through the items from the other session and insert them before any
571 // entries from this session. Do not copy anything that comes after the other 583 // items from this session. Do not copy anything that comes after the other
572 // session's current entry. 584 // session's current item.
573 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex; 585 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex;
574 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) { 586 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) {
575 [_entries insertObject:sourceEntries[i] atIndex:i]; 587 std::unique_ptr<web::NavigationItemImpl> sourceItemCopy(
588 new web::NavigationItemImpl(*sourceItems[i].get()));
589 _items.insert(_items.begin() + i, std::move(sourceItemCopy));
576 } 590 }
577 591
592 // Update state to reflect inserted NavigationItems.
578 _previousNavigationIndex = -1; 593 _previousNavigationIndex = -1;
579 _currentNavigationIndex += lastIndexToCopy + 1; 594 _currentNavigationIndex += lastIndexToCopy + 1;
580 if (_pendingItemIndex != -1) 595 if (self.pendingItemIndex != -1)
581 _pendingItemIndex += lastIndexToCopy + 1; 596 self.pendingItemIndex += lastIndexToCopy + 1;
582 597
583 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), _entries.count); 598 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex),
584 DCHECK(_pendingItemIndex == -1 || _pendingEntry); 599 self.items.size());
600 DCHECK(self.pendingItemIndex == -1 || self.pendingItem);
585 } 601 }
586 602
587 - (void)goToItemAtIndex:(NSInteger)index { 603 - (void)goToItemAtIndex:(NSInteger)index {
588 if (index < 0 || static_cast<NSUInteger>(index) >= _entries.count) 604 if (index < 0 || static_cast<NSUInteger>(index) >= self.items.size())
589 return; 605 return;
590 606
591 if (index < _currentNavigationIndex) { 607 if (index < _currentNavigationIndex) {
592 // Going back. 608 // Going back.
593 [self discardNonCommittedItems]; 609 [self discardNonCommittedItems];
594 } else if (_currentNavigationIndex < index) { 610 } else if (_currentNavigationIndex < index) {
595 // Going forward. 611 // Going forward.
596 [self discardTransientItem]; 612 [self discardTransientItem];
597 } else { 613 } else {
598 // |delta| is 0, no need to change current navigation index. 614 // |delta| is 0, no need to change current navigation index.
599 return; 615 return;
600 } 616 }
601 617
602 _previousNavigationIndex = _currentNavigationIndex; 618 _previousNavigationIndex = _currentNavigationIndex;
603 _currentNavigationIndex = index; 619 _currentNavigationIndex = index;
604 } 620 }
605 621
606 - (void)removeItemAtIndex:(NSInteger)index { 622 - (void)removeItemAtIndex:(NSInteger)index {
607 DCHECK(index < static_cast<NSInteger>([_entries count])); 623 DCHECK(index < static_cast<NSInteger>(self.items.size()));
608 DCHECK(index != _currentNavigationIndex); 624 DCHECK(index != _currentNavigationIndex);
609 DCHECK(index >= 0); 625 DCHECK(index >= 0);
610 626
611 [self discardNonCommittedItems]; 627 [self discardNonCommittedItems];
612 628
613 [_entries removeObjectAtIndex:index]; 629 _items.erase(_items.begin() + index);
614 if (_currentNavigationIndex > index) 630 if (_currentNavigationIndex > index)
615 _currentNavigationIndex--; 631 _currentNavigationIndex--;
616 if (_previousNavigationIndex >= index) 632 if (_previousNavigationIndex >= index)
617 _previousNavigationIndex--; 633 _previousNavigationIndex--;
618 } 634 }
619 635
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
643 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem 636 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem
644 andItem:(web::NavigationItem*)secondItem { 637 andItem:(web::NavigationItem*)secondItem {
645 if (!firstItem || !secondItem || firstItem == secondItem) 638 if (!firstItem || !secondItem || firstItem == secondItem)
646 return NO; 639 return NO;
647 NSUInteger firstIndex = [self indexOfItem:firstItem]; 640 NSUInteger firstIndex = [self indexOfItem:firstItem];
648 NSUInteger secondIndex = [self indexOfItem:secondItem]; 641 NSUInteger secondIndex = [self indexOfItem:secondItem];
649 if (firstIndex == NSNotFound || secondIndex == NSNotFound) 642 if (firstIndex == NSNotFound || secondIndex == NSNotFound)
650 return NO; 643 return NO;
651 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex; 644 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex;
652 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex; 645 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
653 646
654 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) { 647 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) {
655 web::NavigationItemImpl* item = [_entries[i] navigationItemImpl]; 648 web::NavigationItemImpl* item = self.items[i].get();
656 // Every entry in the sequence has to be created from a hash change or 649 // Every item in the sequence has to be created from a hash change or
657 // pushState() call. 650 // pushState() call.
658 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange()) 651 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange())
659 return NO; 652 return NO;
660 // Every entry in the sequence has to have a URL that could have been 653 // Every item in the sequence has to have a URL that could have been
661 // created from a pushState() call. 654 // created from a pushState() call.
662 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(), 655 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(),
663 item->GetURL())) 656 item->GetURL()))
664 return NO; 657 return NO;
665 } 658 }
666 return YES; 659 return YES;
667 } 660 }
668 661
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
682 - (void)useDesktopUserAgentForNextPendingItem { 662 - (void)useDesktopUserAgentForNextPendingItem {
683 if (_pendingEntry) 663 if (self.pendingItem)
684 [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true); 664 self.pendingItem->SetIsOverridingUserAgent(true);
685 else 665 else
686 _useDesktopUserAgentForNextPendingItem = YES; 666 _useDesktopUserAgentForNextPendingItem = YES;
687 } 667 }
688 668
689 - (NSInteger)indexOfItem:(web::NavigationItem*)item { 669 - (NSInteger)indexOfItem:(web::NavigationItem*)item {
690 web::NavigationItemList items = self.items; 670 DCHECK(item);
691 for (NSInteger i = 0; i < static_cast<NSInteger>(items.size()); ++i) { 671 for (size_t index = 0; index < self.items.size(); ++index) {
692 if (items[i] == item) 672 if (self.items[index].get() == item)
693 return i; 673 return index;
694 } 674 }
695 return NSNotFound; 675 return NSNotFound;
696 } 676 }
697 677
698 #pragma mark - 678 #pragma mark -
699 #pragma mark Private methods 679 #pragma mark Private methods
700 680
701 - (NSString*)uniqueID { 681 - (NSString*)uniqueID {
702 CFUUIDRef uuidRef = CFUUIDCreate(NULL); 682 CFUUIDRef uuidRef = CFUUIDCreate(NULL);
703 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); 683 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
704 CFRelease(uuidRef); 684 CFRelease(uuidRef);
705 685
706 NSString* uuid = 686 NSString* uuid =
707 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>( 687 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>(
708 CFBridgingRelease(uuidStringRef))]; 688 CFBridgingRelease(uuidStringRef))];
709 return uuid; 689 return uuid;
710 } 690 }
711 691
712 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url 692 - (std::unique_ptr<web::NavigationItemImpl>)
713 referrer:(const web::Referrer&)referrer 693 itemWithURL:(const GURL&)url
714 transition:(ui::PageTransition)transition 694 referrer:(const web::Referrer&)referrer
715 useDesktopUserAgent:(BOOL)useDesktopUserAgent 695 transition:(ui::PageTransition)transition
716 rendererInitiated:(BOOL)rendererInitiated { 696 useDesktopUserAgent:(BOOL)useDesktopUserAgent
697 rendererInitiated:(BOOL)rendererInitiated {
717 GURL loaded_url(url); 698 GURL loaded_url(url);
718 BOOL urlWasRewritten = NO; 699 BOOL urlWasRewritten = NO;
719 if (_navigationManager) { 700 if (_navigationManager) {
720 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>> 701 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>>
721 transientRewriters = _navigationManager->GetTransientURLRewriters(); 702 transientRewriters = _navigationManager->GetTransientURLRewriters();
722 if (transientRewriters) { 703 if (transientRewriters) {
723 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters( 704 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters(
724 &loaded_url, _browserState, *transientRewriters.get()); 705 &loaded_url, _browserState, *transientRewriters.get());
725 } 706 }
726 } 707 }
727 if (!urlWasRewritten) { 708 if (!urlWasRewritten) {
728 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary( 709 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary(
729 &loaded_url, _browserState); 710 &loaded_url, _browserState);
730 } 711 }
731 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); 712 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl());
732 item->SetOriginalRequestURL(loaded_url); 713 item->SetOriginalRequestURL(loaded_url);
733 item->SetURL(loaded_url); 714 item->SetURL(loaded_url);
734 item->SetReferrer(referrer); 715 item->SetReferrer(referrer);
735 item->SetTransitionType(transition); 716 item->SetTransitionType(transition);
736 item->SetIsOverridingUserAgent(useDesktopUserAgent); 717 item->SetIsOverridingUserAgent(useDesktopUserAgent);
737 item->set_is_renderer_initiated(rendererInitiated); 718 item->set_is_renderer_initiated(rendererInitiated);
738 return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]; 719 return item;
739 } 720 }
740 721
741 - (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index { 722 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index {
742 ui::PageTransition transition = 723 DCHECK_LT(index, self.items.size());
743 [_entries[index] navigationItem]->GetTransitionType(); 724 ui::PageTransition transition = self.items[index]->GetTransitionType();
744 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO; 725 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO;
745 } 726 }
746 727
747 - (web::NavigationItemList)itemListForEntryList:(NSArray*)entries { 728 - (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item {
748 web::NavigationItemList list(entries.count); 729 if (!item)
749 for (size_t index = 0; index < entries.count; ++index) 730 return nil;
750 list[index] = [entries[index] navigationItem]; 731 // CRWSessionEntries vended by a CRWSessionController should always correspond
751 return list; 732 // with a NavigationItem that is owned by that CRWSessionController.
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;
752 } 747 }
753 748
754 @end 749 @end
OLDNEW
« no previous file with comments | « ios/web/navigation/crw_session_controller.h ('k') | ios/web/navigation/crw_session_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698