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

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

Issue 2672723003: Converted CRWSessionController to use NavigationItems. (Closed)
Patch Set: test fixes, 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 _useDesktopUserAgentForNextPendingEntry; 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;
81 std::unique_ptr<web::NavigationItemImpl> _pendingItem;
82 std::unique_ptr<web::NavigationItemImpl> _transientItem;
83 SessionEntryMap _sessionEntryMap;
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)clearForwardEntries; 111 - (void)clearForwardItems;
111 // Discards the transient entry, if any. 112 // Discards the transient item, if any.
112 - (void)discardTransientEntry; 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)isRedirectTransitionForEntryAtIndex:(NSInteger)index; 123 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index;
124 // Returns the CRWSessionEntry corresponding with |item|.
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
122 @end 130 @end
123 131
124 @implementation CRWSessionController 132 @implementation CRWSessionController
125 133
126 @synthesize tabId = _tabId; 134 @synthesize tabId = _tabId;
127 @synthesize currentNavigationIndex = _currentNavigationIndex; 135 @synthesize currentNavigationIndex = _currentNavigationIndex;
128 @synthesize previousNavigationIndex = _previousNavigationIndex; 136 @synthesize previousNavigationIndex = _previousNavigationIndex;
129 @synthesize pendingEntryIndex = _pendingEntryIndex; 137 @synthesize pendingItemIndex = _pendingItemIndex;
130 @synthesize entries = _entries; 138 @synthesize entries = _entries;
131 @synthesize windowName = _windowName; 139 @synthesize windowName = _windowName;
132 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp; 140 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp;
133 @synthesize openerId = _openerId; 141 @synthesize openerId = _openerId;
134 @synthesize openedByDOM = _openedByDOM; 142 @synthesize openedByDOM = _openedByDOM;
135 @synthesize openerNavigationIndex = _openerNavigationIndex; 143 @synthesize openerNavigationIndex = _openerNavigationIndex;
136 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager; 144 @synthesize sessionCertificatePolicyManager = _sessionCertificatePolicyManager;
137 145
138 - (id)initWithWindowName:(NSString*)windowName 146 - (id)initWithWindowName:(NSString*)windowName
139 openerId:(NSString*)openerId 147 openerId:(NSString*)openerId
140 openedByDOM:(BOOL)openedByDOM 148 openedByDOM:(BOOL)openedByDOM
141 openerNavigationIndex:(NSInteger)openerIndex 149 openerNavigationIndex:(NSInteger)openerIndex
142 browserState:(web::BrowserState*)browserState { 150 browserState:(web::BrowserState*)browserState {
143 self = [super init]; 151 self = [super init];
144 if (self) { 152 if (self) {
145 self.windowName = windowName; 153 self.windowName = windowName;
146 _tabId = [[self uniqueID] copy]; 154 _tabId = [[self uniqueID] copy];
147 _openerId = [openerId copy]; 155 _openerId = [openerId copy];
148 _openedByDOM = openedByDOM; 156 _openedByDOM = openedByDOM;
149 _openerNavigationIndex = openerIndex; 157 _openerNavigationIndex = openerIndex;
150 _browserState = browserState; 158 _browserState = browserState;
151 _entries = [NSMutableArray array]; 159 _entries = [NSMutableArray array];
152 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; 160 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
153 _currentNavigationIndex = -1; 161 _currentNavigationIndex = -1;
154 _previousNavigationIndex = -1; 162 _previousNavigationIndex = -1;
155 _pendingEntryIndex = -1; 163 _pendingItemIndex = -1;
156 _sessionCertificatePolicyManager = 164 _sessionCertificatePolicyManager =
157 [[CRWSessionCertificatePolicyManager alloc] init]; 165 [[CRWSessionCertificatePolicyManager alloc] init];
158 } 166 }
159 return self; 167 return self;
160 } 168 }
161 169
162 - (id)initWithNavigationItems: 170 - (id)initWithNavigationItems:(web::ScopedNavigationItemList)items
163 (std::vector<std::unique_ptr<web::NavigationItem>>)items
164 currentIndex:(NSUInteger)currentIndex 171 currentIndex:(NSUInteger)currentIndex
165 browserState:(web::BrowserState*)browserState { 172 browserState:(web::BrowserState*)browserState {
166 self = [super init]; 173 self = [super init];
167 if (self) { 174 if (self) {
168 _tabId = [[self uniqueID] copy]; 175 _tabId = [[self uniqueID] copy];
169 _openerId = nil; 176 _openerId = nil;
170 _browserState = browserState; 177 _browserState = browserState;
171 178 _items = web::CreateScopedNavigationItemImplList(std::move(items));
172 // Create entries array from list of navigations.
173 _entries = [[NSMutableArray alloc] initWithCapacity:items.size()]; 179 _entries = [[NSMutableArray alloc] initWithCapacity:items.size()];
174 180 for (auto& item : _items)
175 for (auto& item : items) { 181 [_entries addObject:[self entryForItem:item.get()]];
176 base::scoped_nsobject<CRWSessionEntry> entry(
177 [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]);
178 [_entries addObject:entry];
179 }
180 self.currentNavigationIndex = currentIndex; 182 self.currentNavigationIndex = currentIndex;
181 // Prior to M34, 0 was used as "no index" instead of -1; adjust for that. 183 if (_items.empty())
182 if (![_entries count])
183 self.currentNavigationIndex = -1; 184 self.currentNavigationIndex = -1;
184 if (_currentNavigationIndex >= static_cast<NSInteger>(items.size())) { 185 _currentNavigationIndex = std::min(
185 self.currentNavigationIndex = static_cast<NSInteger>(items.size()) - 1; 186 _currentNavigationIndex, static_cast<NSInteger>(_items.size() - 1));
186 }
187 _previousNavigationIndex = -1; 187 _previousNavigationIndex = -1;
188 _pendingEntryIndex = -1; 188 _pendingItemIndex = -1;
189 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970]; 189 _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
190 _sessionCertificatePolicyManager = 190 _sessionCertificatePolicyManager =
191 [[CRWSessionCertificatePolicyManager alloc] init]; 191 [[CRWSessionCertificatePolicyManager alloc] init];
192 } 192 }
193 return self; 193 return self;
194 } 194 }
195 195
196 - (id)copyWithZone:(NSZone*)zone { 196 #pragma mark - Accessors
197 CRWSessionController* copy = [[[self class] alloc] init];
198 copy->_tabId = [_tabId copy];
199 copy->_openerId = [_openerId copy];
200 copy->_openedByDOM = _openedByDOM;
201 copy->_openerNavigationIndex = _openerNavigationIndex;
202 copy.windowName = self.windowName;
203 copy->_currentNavigationIndex = _currentNavigationIndex;
204 copy->_previousNavigationIndex = _previousNavigationIndex;
205 copy->_pendingEntryIndex = _pendingEntryIndex;
206 copy->_lastVisitedTimestamp = _lastVisitedTimestamp;
207 copy->_entries =
208 [[NSMutableArray alloc] initWithArray:_entries copyItems:YES];
209 copy->_sessionCertificatePolicyManager =
210 [_sessionCertificatePolicyManager copy];
211 return copy;
212 }
213 197
214 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex { 198 - (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
215 if (_currentNavigationIndex != currentNavigationIndex) { 199 if (_currentNavigationIndex != currentNavigationIndex) {
216 _currentNavigationIndex = currentNavigationIndex; 200 _currentNavigationIndex = currentNavigationIndex;
217 if (_navigationManager) 201 if (_navigationManager)
218 _navigationManager->RemoveTransientURLRewriters(); 202 _navigationManager->RemoveTransientURLRewriters();
219 } 203 }
220 } 204 }
221 205
222 - (void)setPendingEntryIndex:(NSInteger)index { 206 - (void)setPendingItemIndex:(NSInteger)pendingItemIndex {
223 DCHECK_GE(index, -1); 207 DCHECK_GE(pendingItemIndex, -1);
224 DCHECK_LT(index, static_cast<NSInteger>(_entries.count)); 208 DCHECK_LT(pendingItemIndex, static_cast<NSInteger>(self.items.size()));
225 _pendingEntryIndex = index; 209 _pendingItemIndex = pendingItemIndex;
226 CRWSessionEntry* entry = index != -1 ? _entries[index] : nil; 210 DCHECK(_pendingItemIndex == -1 || self.pendingItem);
227 _pendingEntry.reset(entry); 211 }
228 DCHECK(_pendingEntryIndex == -1 || _pendingEntry); 212
229 } 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
230 381
231 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager { 382 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager {
232 _navigationManager = navigationManager; 383 _navigationManager = navigationManager;
233 if (_navigationManager) { 384 if (_navigationManager) {
234 // _browserState will be nullptr if CRWSessionController has been 385 // _browserState will be nullptr if CRWSessionController has been
235 // initialized with -initWithCoder: method. Take _browserState from 386 // initialized with -initWithCoder: method. Take _browserState from
236 // NavigationManagerImpl if that's the case. 387 // NavigationManagerImpl if that's the case.
237 if (!_browserState) { 388 if (!_browserState) {
238 _browserState = _navigationManager->GetBrowserState(); 389 _browserState = _navigationManager->GetBrowserState();
239 } 390 }
240 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState()); 391 DCHECK_EQ(_browserState, _navigationManager->GetBrowserState());
241 } 392 }
242 } 393 }
243 394
244 - (NSString*)description { 395 - (void)setBrowserState:(web::BrowserState*)browserState {
245 return [NSString 396 _browserState = browserState;
246 stringWithFormat: 397 DCHECK(!_navigationManager ||
247 @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS 398 _navigationManager->GetBrowserState() == _browserState);
248 @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS 399 }
249 @"\n%@\npending: %@\ntransient: %@\n", 400
250 _tabId, self.windowName, _lastVisitedTimestamp, 401 - (void)addPendingItem:(const GURL&)url
251 _currentNavigationIndex, _previousNavigationIndex, _pendingEntryIndex, 402 referrer:(const web::Referrer&)ref
252 _entries, _pendingEntry.get(), _transientEntry.get()]; 403 transition:(ui::PageTransition)trans
253 } 404 rendererInitiated:(BOOL)rendererInitiated {
254 405 [self discardTransientItem];
255 // Returns the current entry in the session list, or the pending entry if there 406 self.pendingItemIndex = -1;
256 // is a navigation in progress. 407
257 - (CRWSessionEntry*)currentEntry { 408 // Don't create a new item if it's already the same as the current item,
258 if (_transientEntry)
259 return _transientEntry.get();
260 if (_pendingEntry)
261 return _pendingEntry.get();
262 return [self lastCommittedEntry];
263 }
264
265 // See NavigationController::GetVisibleEntry for the motivation for this
266 // distinction.
267 - (CRWSessionEntry*)visibleEntry {
268 if (_transientEntry)
269 return _transientEntry.get();
270 // Only return the pending_entry for new (non-history), browser-initiated
271 // navigations in order to prevent URL spoof attacks.
272 web::NavigationItemImpl* pendingItem = [_pendingEntry navigationItemImpl];
273 bool safeToShowPending = pendingItem &&
274 !pendingItem->is_renderer_initiated() &&
275 _pendingEntryIndex == -1;
276 if (safeToShowPending) {
277 return _pendingEntry.get();
278 }
279 return [self lastCommittedEntry];
280 }
281
282 - (CRWSessionEntry*)pendingEntry {
283 return _pendingEntry.get();
284 }
285
286 - (CRWSessionEntry*)transientEntry {
287 return _transientEntry.get();
288 }
289
290 - (CRWSessionEntry*)lastCommittedEntry {
291 if (_currentNavigationIndex == -1)
292 return nil;
293 return [_entries objectAtIndex:_currentNavigationIndex];
294 }
295
296 // Returns the previous entry in the session list, or nil if there isn't any.
297 - (CRWSessionEntry*)previousEntry {
298 if ((_previousNavigationIndex < 0) || (![_entries count]))
299 return nil;
300 return [_entries objectAtIndex:_previousNavigationIndex];
301 }
302
303 - (void)addPendingEntry:(const GURL&)url
304 referrer:(const web::Referrer&)ref
305 transition:(ui::PageTransition)trans
306 rendererInitiated:(BOOL)rendererInitiated {
307 [self discardTransientEntry];
308 _pendingEntryIndex = -1;
309
310 // Don't create a new entry if it's already the same as the current entry,
311 // 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.
312 // Note: CRWSessionController currently has the responsibility to distinguish 410 // Note: CRWSessionController currently has the responsibility to distinguish
313 // between new navigations and history stack navigation, hence the inclusion 411 // between new navigations and history stack navigation, hence the inclusion
314 // 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
315 // real-world observed behavior. 413 // real-world observed behavior.
316 // 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
317 // in the web layer so that this hack can be removed. 415 // in the web layer so that this hack can be removed.
318 // Remove the workaround code from -presentSafeBrowsingWarningForResource:. 416 // Remove the workaround code from -presentSafeBrowsingWarningForResource:.
319 CRWSessionEntry* currentEntry = self.currentEntry; 417 web::NavigationItemImpl* currentItem = self.currentItem;
320 if (currentEntry) { 418 if (currentItem && currentItem->GetURL() == url &&
321 web::NavigationItem* item = [currentEntry navigationItem]; 419 (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
322 if (item->GetURL() == url && 420 PageTransitionCoreTypeIs(currentItem->GetTransitionType(),
323 (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) || 421 ui::PAGE_TRANSITION_FORM_SUBMIT))) {
324 PageTransitionCoreTypeIs(item->GetTransitionType(), 422 // Send the notification anyway, to preserve old behavior. It's unknown
325 ui::PAGE_TRANSITION_FORM_SUBMIT))) { 423 // whether anything currently relies on this, but since both this whole
326 // 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
327 // whether anything currently relies on this, but since both this whole 425 // trying to unwind.
328 // hack and the content facade will both be going away, it's not worth 426 if (_navigationManager && _navigationManager->GetFacadeDelegate())
329 // trying to unwind. 427 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
330 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 428 return;
331 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
332 }
333 return;
334 }
335 } 429 }
336 430
337 BOOL useDesktopUserAgent = 431 BOOL useDesktopUserAgent =
338 _useDesktopUserAgentForNextPendingEntry || 432 _useDesktopUserAgentForNextPendingItem ||
339 (self.currentEntry.navigationItem && 433 (currentItem && currentItem->IsOverridingUserAgent());
340 self.currentEntry.navigationItem->IsOverridingUserAgent()); 434 _useDesktopUserAgentForNextPendingItem = NO;
341 _useDesktopUserAgentForNextPendingEntry = NO; 435 _pendingItem = [self itemWithURL:url
342 _pendingEntry.reset([self sessionEntryWithURL:url 436 referrer:ref
343 referrer:ref 437 transition:trans
344 transition:trans 438 useDesktopUserAgent:useDesktopUserAgent
345 useDesktopUserAgent:useDesktopUserAgent 439 rendererInitiated:rendererInitiated];
346 rendererInitiated:rendererInitiated]);
347 440
348 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 441 if (_navigationManager && _navigationManager->GetFacadeDelegate())
349 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 442 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
350 }
351 } 443 }
352 444
353 - (void)updatePendingEntry:(const GURL&)url { 445 - (void)updatePendingItem:(const GURL&)url {
354 // 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
355 // session history. Don't modify the entry list. 447 // session history. Don't modify the item list.
356 if (!_pendingEntry) 448 web::NavigationItemImpl* item = self.pendingItem;
449 if (!item)
357 return; 450 return;
358 451
359 web::NavigationItemImpl* item = [_pendingEntry navigationItemImpl];
360 if (url != item->GetURL()) { 452 if (url != item->GetURL()) {
361 // Assume a redirection, and discard any transient entry. 453 // Assume a redirection, and discard any transient item.
362 // TODO(stuartmorgan): Once the current safe browsing code is gone, 454 // TODO(stuartmorgan): Once the current safe browsing code is gone,
363 // consider making this a DCHECK that there's no transient entry. 455 // consider making this a DCHECK that there's no transient item.
364 [self discardTransientEntry]; 456 [self discardTransientItem];
365 457
366 item->SetURL(url); 458 item->SetURL(url);
367 item->SetVirtualURL(url); 459 item->SetVirtualURL(url);
368 // Redirects (3xx response code), or client side navigation must change 460 // Redirects (3xx response code), or client side navigation must change
369 // POST requests to GETs. 461 // POST requests to GETs.
370 item->SetPostData(nil); 462 item->SetPostData(nil);
371 item->ResetHttpRequestHeaders(); 463 item->ResetHttpRequestHeaders();
372 } 464 }
373 465
374 // 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
375 // done before, so preserve behavior in case something relies on it. 467 // done before, so preserve behavior in case something relies on it.
376 if (_navigationManager && _navigationManager->GetFacadeDelegate()) { 468 if (_navigationManager && _navigationManager->GetFacadeDelegate())
377 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending(); 469 _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
378 }
379 } 470 }
380 471
381 - (void)clearForwardEntries { 472 - (void)clearForwardItems {
382 DCHECK_EQ(_pendingEntryIndex, -1); 473 DCHECK_EQ(self.pendingItemIndex, -1);
383 [self discardTransientEntry]; 474 [self discardTransientItem];
384 475
385 NSInteger forwardEntryStartIndex = _currentNavigationIndex + 1; 476 NSInteger forwardItemStartIndex = _currentNavigationIndex + 1;
386 DCHECK(forwardEntryStartIndex >= 0); 477 DCHECK(forwardItemStartIndex >= 0);
387 478
388 if (forwardEntryStartIndex >= static_cast<NSInteger>([_entries count])) 479 size_t itemCount = self.items.size();
480 if (forwardItemStartIndex >= static_cast<NSInteger>(itemCount))
389 return; 481 return;
390 482
391 NSRange remove = NSMakeRange(forwardEntryStartIndex, 483 // Remove the CRWSessionEntries from the map.
392 [_entries count] - forwardEntryStartIndex); 484 for (size_t index = forwardItemStartIndex; index < itemCount; ++index)
393 // Store removed items in temporary NSArray so they can be deallocated after 485 self.sessionEntryMap.erase(self.items[index].get());
394 // their facades. 486
395 base::scoped_nsobject<NSArray> removedItems( 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.
490 NSRange remove = NSMakeRange(forwardItemStartIndex,
491 [_entries count] - forwardItemStartIndex);
492 base::scoped_nsobject<NSArray> removedEntries(
396 [_entries subarrayWithRange:remove]); 493 [_entries subarrayWithRange:remove]);
397 [_entries removeObjectsInRange:remove]; 494 [_entries removeObjectsInRange:remove];
398 if (_previousNavigationIndex >= forwardEntryStartIndex) 495 if (_previousNavigationIndex >= forwardItemStartIndex)
399 _previousNavigationIndex = -1; 496 _previousNavigationIndex = -1;
400 if (_navigationManager) { 497 if (_navigationManager)
401 _navigationManager->OnNavigationItemsPruned(remove.length); 498 _navigationManager->OnNavigationItemsPruned(remove.length);
402 } 499
500 // Remove the NavigationItems.
501 _items.erase(_items.begin() + forwardItemStartIndex, _items.end());
403 } 502 }
404 503
405 - (void)commitPendingEntry { 504 - (void)commitPendingItem {
406 if (_pendingEntry) { 505 if (self.pendingItem) {
407 NSInteger newNavigationIndex = _pendingEntryIndex; 506 // Once an item is committed it's not renderer-initiated any more. (Matches
408 if (_pendingEntryIndex == -1) { 507 // the implementation in NavigationController.)
409 [self clearForwardEntries]; 508 self.pendingItem->ResetForCommit();
410 // Add the new entry at the end. 509
411 [_entries addObject:_pendingEntry]; 510 NSInteger newNavigationIndex = self.pendingItemIndex;
412 newNavigationIndex = [_entries count] - 1; 511 if (newNavigationIndex == -1) {
512 [self clearForwardItems];
513 // Add the new item at the end.
514 _items.push_back(std::move(_pendingItem));
515 [_entries addObject:[self entryForItem:self.items.back().get()]];
516 newNavigationIndex = self.items.size() - 1;
413 } 517 }
414 _previousNavigationIndex = _currentNavigationIndex; 518 _previousNavigationIndex = _currentNavigationIndex;
415 self.currentNavigationIndex = newNavigationIndex; 519 self.currentNavigationIndex = newNavigationIndex;
416 // Once an entry is committed it's not renderer-initiated any more. (Matches 520 self.pendingItemIndex = -1;
417 // the implementation in NavigationController.)
418 [_pendingEntry navigationItemImpl]->ResetForCommit();
419 _pendingEntry.reset();
420 _pendingEntryIndex = -1;
421 } 521 }
422 522
423 CRWSessionEntry* currentEntry = self.currentEntry; 523 web::NavigationItem* item = self.currentItem;
424 web::NavigationItem* item = currentEntry.navigationItem;
425 // Update the navigation timestamp now that it's actually happened. 524 // Update the navigation timestamp now that it's actually happened.
426 if (item) 525 if (item)
427 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now())); 526 item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now()));
428 527
429 if (_navigationManager && item) 528 if (_navigationManager && item)
430 _navigationManager->OnNavigationItemCommitted(); 529 _navigationManager->OnNavigationItemCommitted();
431 DCHECK_EQ(_pendingEntryIndex, -1); 530 DCHECK_EQ(self.pendingItemIndex, -1);
432 } 531 }
433 532
434 - (void)addTransientEntryWithURL:(const GURL&)URL { 533 - (void)addTransientItemWithURL:(const GURL&)URL {
435 _transientEntry.reset([self 534 _transientItem = [self itemWithURL:URL
436 sessionEntryWithURL:URL 535 referrer:web::Referrer()
437 referrer:web::Referrer() 536 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
438 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT 537 useDesktopUserAgent:NO
439 useDesktopUserAgent:NO 538 rendererInitiated:NO];
440 rendererInitiated:NO]); 539 _transientItem->SetTimestamp(
441
442 web::NavigationItem* navigationItem = [_transientEntry navigationItem];
443 DCHECK(navigationItem);
444 navigationItem->SetTimestamp(
445 _timeSmoother.GetSmoothedTime(base::Time::Now())); 540 _timeSmoother.GetSmoothedTime(base::Time::Now()));
446 } 541 }
447 542
448 - (void)pushNewEntryWithURL:(const GURL&)URL 543 - (void)pushNewItemWithURL:(const GURL&)URL
449 stateObject:(NSString*)stateObject 544 stateObject:(NSString*)stateObject
450 transition:(ui::PageTransition)transition { 545 transition:(ui::PageTransition)transition {
451 DCHECK(![self pendingEntry]); 546 DCHECK(!self.pendingItem);
452 DCHECK([self currentEntry]); 547 web::NavigationItem* item = self.currentItem;
453 web::NavigationItem* item = [self currentEntry].navigationItem; 548 DCHECK(item);
454 CHECK( 549 CHECK(
455 web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL)); 550 web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL));
456 web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault); 551 web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault);
457 bool overrideUserAgent = 552 bool overrideUserAgent = self.currentItem->IsOverridingUserAgent();
458 self.currentEntry.navigationItem->IsOverridingUserAgent(); 553 std::unique_ptr<web::NavigationItemImpl> pushedItem =
459 base::scoped_nsobject<CRWSessionEntry> pushedEntry([self 554 [self itemWithURL:URL
460 sessionEntryWithURL:URL 555 referrer:referrer
461 referrer:referrer 556 transition:transition
462 transition:transition 557 useDesktopUserAgent:overrideUserAgent
463 useDesktopUserAgent:overrideUserAgent 558 rendererInitiated:NO];
464 rendererInitiated:NO]);
465 web::NavigationItemImpl* pushedItem = [pushedEntry navigationItemImpl];
466 pushedItem->SetSerializedStateObject(stateObject); 559 pushedItem->SetSerializedStateObject(stateObject);
467 pushedItem->SetIsCreatedFromPushState(true); 560 pushedItem->SetIsCreatedFromPushState(true);
468 web::SSLStatus& sslStatus = [self currentEntry].navigationItem->GetSSL(); 561 web::SSLStatus& sslStatus = self.currentItem->GetSSL();
469 pushedEntry.get().navigationItem->GetSSL() = sslStatus; 562 pushedItem->GetSSL() = sslStatus;
470 563
471 [self clearForwardEntries]; 564 [self clearForwardItems];
472 // Add the new entry at the end. 565 // Add the new item at the end.
473 [_entries addObject:pushedEntry]; 566 _items.push_back(std::move(pushedItem));
567 [_entries addObject:[self entryForItem:self.items.back().get()]];
474 _previousNavigationIndex = _currentNavigationIndex; 568 _previousNavigationIndex = _currentNavigationIndex;
475 self.currentNavigationIndex = [_entries count] - 1; 569 self.currentNavigationIndex = self.items.size() - 1;
476 570
477 if (_navigationManager) 571 if (_navigationManager)
478 _navigationManager->OnNavigationItemCommitted(); 572 _navigationManager->OnNavigationItemCommitted();
479 } 573 }
480 574
481 - (void)updateCurrentEntryWithURL:(const GURL&)url 575 - (void)updateCurrentItemWithURL:(const GURL&)url
482 stateObject:(NSString*)stateObject { 576 stateObject:(NSString*)stateObject {
483 DCHECK(!_transientEntry); 577 DCHECK(!self.transientItem);
484 CRWSessionEntry* currentEntry = self.currentEntry; 578 web::NavigationItemImpl* currentItem = self.currentItem;
485 web::NavigationItemImpl* currentItem = self.currentEntry.navigationItemImpl;
486 currentItem->SetURL(url); 579 currentItem->SetURL(url);
487 currentItem->SetSerializedStateObject(stateObject); 580 currentItem->SetSerializedStateObject(stateObject);
488 currentItem->SetHasStateBeenReplaced(true); 581 currentItem->SetHasStateBeenReplaced(true);
489 currentItem->SetPostData(nil); 582 currentItem->SetPostData(nil);
490 currentEntry.navigationItem->SetURL(url); 583 // If the change is to a committed item, notify interested parties.
491 // If the change is to a committed entry, notify interested parties. 584 if (currentItem != self.pendingItem && _navigationManager)
492 if (currentEntry != self.pendingEntry && _navigationManager)
493 _navigationManager->OnNavigationItemChanged(); 585 _navigationManager->OnNavigationItemChanged();
494 } 586 }
495 587
496 - (void)discardNonCommittedEntries { 588 - (void)discardNonCommittedItems {
497 [self discardTransientEntry]; 589 [self discardTransientItem];
498 _pendingEntry.reset(); 590 self.sessionEntryMap.erase(self.pendingItem);
499 _pendingEntryIndex = -1; 591 _pendingItem.reset();
592 self.pendingItemIndex = -1;
500 } 593 }
501 594
502 - (void)discardTransientEntry { 595 - (void)discardTransientItem {
503 // Keep the entry alive temporarily. There are flows that get the current 596 self.sessionEntryMap.erase(self.transientItem);
504 // entry, do some navigation operation, and then try to use that old current 597 _transientItem.reset();
505 // entry; since navigations clear the transient entry, these flows might
506 // crash. (This should be removable once more session management is handled
507 // within this class and/or NavigationManager).
508 _transientEntry.reset();
509 }
510
511 - (BOOL)hasPendingEntry {
512 return _pendingEntry != nil;
513 } 598 }
514 599
515 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession { 600 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession {
516 DCHECK(sourceSession); 601 DCHECK(sourceSession);
517 self.windowName = sourceSession.windowName; 602 self.windowName = sourceSession.windowName;
518 603
519 // 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
520 // to insert. The other session's currentNavigationEntry will be bogus 605 // to insert. The other session's currentItem will be bogus
521 // in such cases, so ignore it and return early. 606 // in such cases, so ignore it and return early.
522 NSArray* sourceEntries = sourceSession.entries; 607 web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items;
523 if (!sourceEntries.count) 608 if (sourceItems.empty())
524 return; 609 return;
525 610
526 // 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
527 // 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
528 // session's current entry. 613 // session's current item.
529 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex; 614 NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex;
530 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) { 615 for (NSInteger i = 0; i <= lastIndexToCopy; ++i) {
531 [_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);
532 } 621 }
533 622
623 // Update state to reflect inserted NavigationItems.
534 _previousNavigationIndex = -1; 624 _previousNavigationIndex = -1;
535 _currentNavigationIndex += lastIndexToCopy + 1; 625 _currentNavigationIndex += lastIndexToCopy + 1;
536 if (_pendingEntryIndex != -1) 626 if (self.pendingItemIndex != -1)
537 _pendingEntryIndex += lastIndexToCopy + 1; 627 self.pendingItemIndex += lastIndexToCopy + 1;
538 628
539 DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), _entries.count); 629 // Update |sourceSession|'s state to reflect the ownership of its
540 DCHECK(_pendingEntryIndex == -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);
541 } 643 }
542 644
543 - (void)goToEntryAtIndex:(NSInteger)index { 645 - (void)goToItemAtIndex:(NSInteger)index {
544 if (index < 0 || static_cast<NSUInteger>(index) >= _entries.count) 646 if (index < 0 || static_cast<NSUInteger>(index) >= self.items.size())
545 return; 647 return;
546 648
547 if (index < _currentNavigationIndex) { 649 if (index < _currentNavigationIndex) {
548 // Going back. 650 // Going back.
549 [self discardNonCommittedEntries]; 651 [self discardNonCommittedItems];
550 } else if (_currentNavigationIndex < index) { 652 } else if (_currentNavigationIndex < index) {
551 // Going forward. 653 // Going forward.
552 [self discardTransientEntry]; 654 [self discardTransientItem];
553 } else { 655 } else {
554 // |delta| is 0, no need to change current navigation index. 656 // |delta| is 0, no need to change current navigation index.
555 return; 657 return;
556 } 658 }
557 659
558 _previousNavigationIndex = _currentNavigationIndex; 660 _previousNavigationIndex = _currentNavigationIndex;
559 _currentNavigationIndex = index; 661 _currentNavigationIndex = index;
560 } 662 }
561 663
562 - (void)removeEntryAtIndex:(NSInteger)index { 664 - (void)removeItemAtIndex:(NSInteger)index {
563 DCHECK(index < static_cast<NSInteger>([_entries count])); 665 DCHECK(index < static_cast<NSInteger>(self.items.size()));
564 DCHECK(index != _currentNavigationIndex); 666 DCHECK(index != _currentNavigationIndex);
565 DCHECK(index >= 0); 667 DCHECK(index >= 0);
566 668
567 [self discardNonCommittedEntries]; 669 [self discardNonCommittedItems];
568 670
569 [_entries removeObjectAtIndex:index]; 671 [_entries removeObjectAtIndex:index];
672 self.sessionEntryMap.erase(self.items[index].get());
673 _items.erase(_items.begin() + index);
570 if (_currentNavigationIndex > index) 674 if (_currentNavigationIndex > index)
571 _currentNavigationIndex--; 675 _currentNavigationIndex--;
572 if (_previousNavigationIndex >= index) 676 if (_previousNavigationIndex >= index)
573 _previousNavigationIndex--; 677 _previousNavigationIndex--;
574 } 678 }
575 679
576 - (NSArray*)backwardEntries { 680 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem
577 NSMutableArray* entries = [NSMutableArray array]; 681 andItem:(web::NavigationItem*)secondItem {
578 for (NSInteger index = _currentNavigationIndex; index > 0; --index) { 682 if (!firstItem || !secondItem || firstItem == secondItem)
579 if (![self isRedirectTransitionForEntryAtIndex:index])
580 [entries addObject:_entries[index - 1]];
581 }
582 return entries;
583 }
584
585 - (NSArray*)forwardEntries {
586 NSMutableArray* entries = [NSMutableArray array];
587 NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
588 while (lastNonRedirectedIndex < [_entries count]) {
589 CRWSessionEntry* entry = [_entries objectAtIndex:lastNonRedirectedIndex];
590 if (!ui::PageTransitionIsRedirect(
591 entry.navigationItem->GetTransitionType())) {
592 [entries addObject:entry];
593 }
594 ++lastNonRedirectedIndex;
595 }
596 return entries;
597 }
598
599 - (BOOL)isSameDocumentNavigationBetweenEntry:(CRWSessionEntry*)firstEntry
600 andEntry:(CRWSessionEntry*)secondEntry {
601 if (!firstEntry || !secondEntry || firstEntry == secondEntry)
602 return NO; 683 return NO;
603 NSUInteger firstIndex = [_entries indexOfObject:firstEntry]; 684 NSUInteger firstIndex = [self indexOfItem:firstItem];
604 NSUInteger secondIndex = [_entries indexOfObject:secondEntry]; 685 NSUInteger secondIndex = [self indexOfItem:secondItem];
605 if (firstIndex == NSNotFound || secondIndex == NSNotFound) 686 if (firstIndex == NSNotFound || secondIndex == NSNotFound)
606 return NO; 687 return NO;
607 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex; 688 NSUInteger startIndex = firstIndex < secondIndex ? firstIndex : secondIndex;
608 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex; 689 NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
609 690
610 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) { 691 for (NSUInteger i = startIndex + 1; i <= endIndex; i++) {
611 web::NavigationItemImpl* item = [_entries[i] navigationItemImpl]; 692 web::NavigationItemImpl* item = self.items[i].get();
612 // 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
613 // pushState() call. 694 // pushState() call.
614 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange()) 695 if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange())
615 return NO; 696 return NO;
616 // 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
617 // created from a pushState() call. 698 // created from a pushState() call.
618 if (!web::history_state_util::IsHistoryStateChangeValid( 699 if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(),
619 firstEntry.navigationItem->GetURL(), item->GetURL())) 700 item->GetURL()))
620 return NO; 701 return NO;
621 } 702 }
622 return YES; 703 return YES;
623 } 704 }
624 705
625 - (CRWSessionEntry*)lastUserEntry { 706 - (void)useDesktopUserAgentForNextPendingItem {
626 if (![_entries count]) 707 if (self.pendingItem)
627 return nil; 708 self.pendingItem->SetIsOverridingUserAgent(true);
628 709 else
629 NSInteger index = _currentNavigationIndex; 710 _useDesktopUserAgentForNextPendingItem = YES;
630 // This will return the first session entry if all other entries are
631 // redirects, regardless of the transition state of the first entry.
632 while (index > 0 && [self isRedirectTransitionForEntryAtIndex:index]) {
633 --index;
634 }
635 return [_entries objectAtIndex:index];
636 } 711 }
637 712
638 - (void)useDesktopUserAgentForNextPendingEntry { 713 - (NSInteger)indexOfItem:(web::NavigationItem*)item {
639 if (_pendingEntry) 714 DCHECK(item);
640 [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true); 715 for (size_t index = 0; index < self.items.size(); ++index) {
641 else 716 if (self.items[index].get() == item)
642 _useDesktopUserAgentForNextPendingEntry = YES; 717 return index;
718 }
719 return NSNotFound;
643 } 720 }
644 721
645 #pragma mark - 722 #pragma mark -
646 #pragma mark Private methods 723 #pragma mark Private methods
647 724
648 - (NSString*)uniqueID { 725 - (NSString*)uniqueID {
649 CFUUIDRef uuidRef = CFUUIDCreate(NULL); 726 CFUUIDRef uuidRef = CFUUIDCreate(NULL);
650 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef); 727 CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
651 CFRelease(uuidRef); 728 CFRelease(uuidRef);
652 729
653 NSString* uuid = 730 NSString* uuid =
654 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>( 731 [NSString stringWithString:base::mac::ObjCCastStrict<NSString>(
655 CFBridgingRelease(uuidStringRef))]; 732 CFBridgingRelease(uuidStringRef))];
656 return uuid; 733 return uuid;
657 } 734 }
658 735
659 - (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url 736 - (std::unique_ptr<web::NavigationItemImpl>)
660 referrer:(const web::Referrer&)referrer 737 itemWithURL:(const GURL&)url
661 transition:(ui::PageTransition)transition 738 referrer:(const web::Referrer&)referrer
662 useDesktopUserAgent:(BOOL)useDesktopUserAgent 739 transition:(ui::PageTransition)transition
663 rendererInitiated:(BOOL)rendererInitiated { 740 useDesktopUserAgent:(BOOL)useDesktopUserAgent
741 rendererInitiated:(BOOL)rendererInitiated {
664 GURL loaded_url(url); 742 GURL loaded_url(url);
665 BOOL urlWasRewritten = NO; 743 BOOL urlWasRewritten = NO;
666 if (_navigationManager) { 744 if (_navigationManager) {
667 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>> 745 std::unique_ptr<std::vector<web::BrowserURLRewriter::URLRewriter>>
668 transientRewriters = _navigationManager->GetTransientURLRewriters(); 746 transientRewriters = _navigationManager->GetTransientURLRewriters();
669 if (transientRewriters) { 747 if (transientRewriters) {
670 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters( 748 urlWasRewritten = web::BrowserURLRewriter::RewriteURLWithWriters(
671 &loaded_url, _browserState, *transientRewriters.get()); 749 &loaded_url, _browserState, *transientRewriters.get());
672 } 750 }
673 } 751 }
674 if (!urlWasRewritten) { 752 if (!urlWasRewritten) {
675 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary( 753 web::BrowserURLRewriter::GetInstance()->RewriteURLIfNecessary(
676 &loaded_url, _browserState); 754 &loaded_url, _browserState);
677 } 755 }
678 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl()); 756 std::unique_ptr<web::NavigationItemImpl> item(new web::NavigationItemImpl());
679 item->SetOriginalRequestURL(loaded_url); 757 item->SetOriginalRequestURL(loaded_url);
680 item->SetURL(loaded_url); 758 item->SetURL(loaded_url);
681 item->SetReferrer(referrer); 759 item->SetReferrer(referrer);
682 item->SetTransitionType(transition); 760 item->SetTransitionType(transition);
683 item->SetIsOverridingUserAgent(useDesktopUserAgent); 761 item->SetIsOverridingUserAgent(useDesktopUserAgent);
684 item->set_is_renderer_initiated(rendererInitiated); 762 item->set_is_renderer_initiated(rendererInitiated);
685 return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]; 763 return item;
686 } 764 }
687 765
688 - (BOOL)isRedirectTransitionForEntryAtIndex:(NSInteger)index { 766 - (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index {
689 ui::PageTransition transition = 767 DCHECK_LT(index, self.items.size());
690 [_entries[index] navigationItem]->GetTransitionType(); 768 ui::PageTransition transition = self.items[index]->GetTransitionType();
691 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO; 769 return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO;
692 } 770 }
693 771
772 - (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item {
773 if (!item)
774 return nil;
775 // CRWSessionEntries vended by a CRWSessionController should always correspond
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;
795 }
796
694 @end 797 @end
OLDNEW
« no previous file with comments | « ios/web/navigation/crw_session_controller.h ('k') | ios/web/navigation/crw_session_controller+private_constructors.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698