OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/web/navigation/crw_session_controller.h" | 5 #import "ios/web/navigation/crw_session_controller.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <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 |
OLD | NEW |