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

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

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