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

Side by Side Diff: content/renderer/history_controller.cc

Issue 2648053002: Remove old session history logic. (Closed)
Patch Set: Remove comment. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /*
6 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/)
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
21 * its contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include "content/renderer/history_controller.h"
37
38 #include <utility>
39
40 #include "base/memory/ptr_util.h"
41 #include "content/common/navigation_params.h"
42 #include "content/common/site_isolation_policy.h"
43 #include "content/renderer/render_frame_impl.h"
44 #include "content/renderer/render_view_impl.h"
45 #include "third_party/WebKit/public/web/WebFrameLoadType.h"
46 #include "third_party/WebKit/public/web/WebLocalFrame.h"
47
48 using blink::WebCachePolicy;
49 using blink::WebFrame;
50 using blink::WebHistoryCommitType;
51 using blink::WebHistoryItem;
52 using blink::WebURLRequest;
53
54 namespace content {
55
56 HistoryController::HistoryController(RenderViewImpl* render_view)
57 : render_view_(render_view) {
58 // We don't use HistoryController in OOPIF enabled modes.
59 DCHECK(!SiteIsolationPolicy::UseSubframeNavigationEntries());
60 }
61
62 HistoryController::~HistoryController() {
63 }
64
65 bool HistoryController::GoToEntry(
66 blink::WebLocalFrame* main_frame,
67 std::unique_ptr<HistoryEntry> target_entry,
68 std::unique_ptr<NavigationParams> navigation_params,
69 WebCachePolicy cache_policy) {
70 DCHECK(!main_frame->parent());
71 HistoryFrameLoadVector same_document_loads;
72 HistoryFrameLoadVector different_document_loads;
73
74 set_provisional_entry(std::move(target_entry));
75 navigation_params_ = std::move(navigation_params);
76
77 if (current_entry_) {
78 RecursiveGoToEntry(
79 main_frame, same_document_loads, different_document_loads);
80 }
81
82 if (same_document_loads.empty() && different_document_loads.empty()) {
83 // If we don't have any frames to navigate at this point, either
84 // (1) there is no previous history entry to compare against, or
85 // (2) we were unable to match any frames by name. In the first case,
86 // doing a different document navigation to the root item is the only valid
87 // thing to do. In the second case, we should have been able to find a
88 // frame to navigate based on names if this were a same document
89 // navigation, so we can safely assume this is the different document case.
90 different_document_loads.push_back(
91 std::make_pair(main_frame, provisional_entry_->root()));
92 }
93
94 bool has_main_frame_request = false;
95 for (const auto& item : same_document_loads) {
96 WebFrame* frame = item.first;
97 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
98 if (!render_frame)
99 continue;
100 render_frame->SetPendingNavigationParams(
101 base::MakeUnique<NavigationParams>(*navigation_params_.get()));
102 WebURLRequest request = frame->toWebLocalFrame()->requestFromHistoryItem(
103 item.second, cache_policy);
104 frame->toWebLocalFrame()->load(
105 request, blink::WebFrameLoadType::BackForward, item.second,
106 blink::WebHistorySameDocumentLoad);
107 if (frame == main_frame)
108 has_main_frame_request = true;
109 }
110 for (const auto& item : different_document_loads) {
111 WebFrame* frame = item.first;
112 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
113 if (!render_frame)
114 continue;
115 render_frame->SetPendingNavigationParams(
116 base::MakeUnique<NavigationParams>(*navigation_params_.get()));
117 WebURLRequest request = frame->toWebLocalFrame()->requestFromHistoryItem(
118 item.second, cache_policy);
119 frame->toWebLocalFrame()->load(
120 request, blink::WebFrameLoadType::BackForward, item.second,
121 blink::WebHistoryDifferentDocumentLoad);
122 if (frame == main_frame)
123 has_main_frame_request = true;
124 }
125
126 return has_main_frame_request;
127 }
128
129 void HistoryController::RecursiveGoToEntry(
130 WebFrame* frame,
131 HistoryFrameLoadVector& same_document_loads,
132 HistoryFrameLoadVector& different_document_loads) {
133 DCHECK(provisional_entry_);
134 DCHECK(current_entry_);
135 RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
136 const WebHistoryItem& new_item =
137 provisional_entry_->GetItemForFrame(render_frame);
138
139 // Use the last committed history item for the frame rather than
140 // current_entry_, since the latter may not accurately reflect which URL is
141 // currently committed in the frame. See https://crbug.com/612713#c12.
142 const WebHistoryItem& old_item = render_frame->current_history_item();
143
144 if (new_item.isNull())
145 return;
146
147 if (old_item.isNull() ||
148 new_item.itemSequenceNumber() != old_item.itemSequenceNumber()) {
149 if (!old_item.isNull() &&
150 new_item.documentSequenceNumber() ==
151 old_item.documentSequenceNumber()) {
152 same_document_loads.push_back(std::make_pair(frame, new_item));
153
154 // Returning here (and omitting child frames which have also changed) is
155 // wrong, but not returning here is worse. See the discussion in
156 // NavigationControllerImpl::FindFramesToNavigate for more information.
157 return;
158 } else {
159 different_document_loads.push_back(std::make_pair(frame, new_item));
160 // For a different document, the subframes will be destroyed, so there's
161 // no need to consider them.
162 return;
163 }
164 }
165
166 for (WebFrame* child = frame->firstChild(); child;
167 child = child->nextSibling()) {
168 RecursiveGoToEntry(child, same_document_loads, different_document_loads);
169 }
170 }
171
172 void HistoryController::UpdateForInitialLoadInChildFrame(
173 RenderFrameImpl* frame,
174 const WebHistoryItem& item) {
175 DCHECK_NE(frame->GetWebFrame()->top(), frame->GetWebFrame());
176 if (!current_entry_)
177 return;
178 if (HistoryEntry::HistoryNode* existing_node =
179 current_entry_->GetHistoryNodeForFrame(frame)) {
180 // Clear the children and any NavigationParams if this commit isn't for
181 // the same item. Otherwise we might have stale data after a redirect.
182 if (existing_node->item().itemSequenceNumber() !=
183 item.itemSequenceNumber()) {
184 existing_node->RemoveChildren();
185 navigation_params_.reset();
186 }
187 existing_node->set_item(item);
188 return;
189 }
190 RenderFrameImpl* parent =
191 RenderFrameImpl::FromWebFrame(frame->GetWebFrame()->parent());
192 if (!parent)
193 return;
194 if (HistoryEntry::HistoryNode* parent_history_node =
195 current_entry_->GetHistoryNodeForFrame(parent)) {
196 parent_history_node->AddChild(item);
197 }
198 }
199
200 void HistoryController::UpdateForCommit(RenderFrameImpl* frame,
201 const WebHistoryItem& item,
202 WebHistoryCommitType commit_type,
203 bool navigation_within_page) {
204 switch (commit_type) {
205 case blink::WebBackForwardCommit:
206 if (!provisional_entry_) {
207 // The provisional entry may have been discarded due to a navigation in
208 // a different frame. For main frames, it is not safe to leave the
209 // current_entry_ in place, which may have a cross-site page and will be
210 // included in the PageState for this commit. Replace it with a new
211 // HistoryEntry corresponding to the commit, and clear any stale
212 // NavigationParams which might point to the wrong entry.
213 //
214 // This will lack any subframe history items that were in the original
215 // provisional entry, but we don't know what those were after discarding
216 // it. We'll load the default URL in those subframes instead.
217 //
218 // TODO(creis): It's also possible to get here for subframe commits.
219 // We'll leave a stale current_entry_ in that case, but that only causes
220 // an earlier URL to load in the subframe when leaving and coming back,
221 // and only in rare cases. It does not risk a URL spoof, unlike the
222 // main frame case. Since this bug is not present in the new
223 // FrameNavigationEntry-based navigation path (https://crbug.com/236848)
224 // we'll wait for that to fix the subframe case.
225 if (frame->IsMainFrame()) {
226 current_entry_.reset(new HistoryEntry(item));
227 navigation_params_.reset();
228 }
229
230 return;
231 }
232
233 // If the current entry is null, this must be a main frame commit.
234 DCHECK(current_entry_ || frame->IsMainFrame());
235
236 // Commit the provisional entry, but only if it is a plausible transition.
237 // Do not commit it if the navigation is in a subframe and the provisional
238 // entry's main frame item does not match the current entry's main frame,
239 // which can happen if multiple forward navigations occur. In that case,
240 // committing the provisional entry would corrupt it, leading to a URL
241 // spoof. See https://crbug.com/597322. (Note that the race in this bug
242 // does not affect main frame navigations, only navigations in subframes.)
243 //
244 // Note that we cannot compare the provisional entry against |item|, since
245 // |item| may have redirected to a different URL and ISN. We also cannot
246 // compare against the main frame's URL, since that may have changed due
247 // to a replaceState. (Even origin can change on replaceState in certain
248 // modes.)
249 //
250 // It would be safe to additionally check the ISNs of all parent frames
251 // (and not just the root), but that is less critical because it won't
252 // lead to a URL spoof.
253 if (frame->IsMainFrame() ||
254 current_entry_->root().itemSequenceNumber() ==
255 provisional_entry_->root().itemSequenceNumber()) {
256 current_entry_ = std::move(provisional_entry_);
257 }
258
259 // We're guaranteed to have a current entry now.
260 DCHECK(current_entry_);
261
262 if (HistoryEntry::HistoryNode* node =
263 current_entry_->GetHistoryNodeForFrame(frame)) {
264 // Clear the children and any NavigationParams if this commit isn't for
265 // the same item. Otherwise we might have stale data from a race.
266 if (node->item().itemSequenceNumber() != item.itemSequenceNumber()) {
267 node->RemoveChildren();
268 navigation_params_.reset();
269 }
270
271 node->set_item(item);
272 }
273 break;
274 case blink::WebStandardCommit:
275 CreateNewBackForwardItem(frame, item, navigation_within_page);
276 break;
277 case blink::WebInitialCommitInChildFrame:
278 UpdateForInitialLoadInChildFrame(frame, item);
279 break;
280 case blink::WebHistoryInertCommit:
281 // Even for inert commits (e.g., location.replace, client redirects), make
282 // sure the current entry gets updated, if there is one.
283 if (current_entry_) {
284 if (HistoryEntry::HistoryNode* node =
285 current_entry_->GetHistoryNodeForFrame(frame)) {
286 // Inert commits that reset the page without changing the item (e.g.,
287 // reloads, location.replace) shouldn't keep the old subtree.
288 if (!navigation_within_page)
289 node->RemoveChildren();
290 node->set_item(item);
291 }
292 }
293 break;
294 default:
295 NOTREACHED() << "Invalid commit type: " << commit_type;
296 }
297 }
298
299 HistoryEntry* HistoryController::GetCurrentEntry() {
300 return current_entry_.get();
301 }
302
303 WebHistoryItem HistoryController::GetItemForNewChildFrame(
304 RenderFrameImpl* frame) const {
305 if (navigation_params_.get()) {
306 frame->SetPendingNavigationParams(
307 base::MakeUnique<NavigationParams>(*navigation_params_.get()));
308 }
309
310 if (!current_entry_)
311 return WebHistoryItem();
312 return current_entry_->GetItemForFrame(frame);
313 }
314
315 void HistoryController::RemoveChildrenForRedirect(RenderFrameImpl* frame) {
316 if (!provisional_entry_)
317 return;
318 if (HistoryEntry::HistoryNode* node =
319 provisional_entry_->GetHistoryNodeForFrame(frame))
320 node->RemoveChildren();
321 }
322
323 void HistoryController::CreateNewBackForwardItem(
324 RenderFrameImpl* target_frame,
325 const WebHistoryItem& new_item,
326 bool clone_children_of_target) {
327 if (!current_entry_) {
328 current_entry_.reset(new HistoryEntry(new_item));
329 } else {
330 current_entry_.reset(current_entry_->CloneAndReplace(
331 new_item, clone_children_of_target, target_frame, render_view_));
332 }
333 }
334
335 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/history_controller.h ('k') | content/renderer/history_controller_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698