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