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

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

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

Powered by Google App Engine
This is Rietveld 408576698