1 // Copyright 2013 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.
5 #include "content/browser/frame_host/navigation_entry_impl.h"
7 #include "base/metrics/histogram.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/common/navigation_params.h"
11 #include "content/public/common/content_constants.h"
12 #include "content/public/common/url_constants.h"
13 #include "net/base/net_util.h"
14 #include "ui/gfx/text_elider.h"
16 // Use this to get a new unique ID for a NavigationEntry during construction.
17 // The returned ID is guaranteed to be nonzero (which is the "no ID" indicator).
18 static int GetUniqueIDInConstructor() {
19 static int unique_id_counter
= 0;
20 return ++unique_id_counter
;
25 int NavigationEntryImpl::kInvalidBindings
= -1;
27 NavigationEntryImpl::TreeNode::TreeNode(FrameNavigationEntry
* frame_entry
)
28 : frame_entry(frame_entry
) {
31 NavigationEntryImpl::TreeNode::~TreeNode() {
34 NavigationEntryImpl::TreeNode
* NavigationEntryImpl::TreeNode::Clone() const {
35 // Clone the tree using a copy of the FrameNavigationEntry, without sharing.
36 NavigationEntryImpl::TreeNode
* copy
=
37 new NavigationEntryImpl::TreeNode(frame_entry
->Clone());
39 // TODO(creis): Clone children once we add them.
43 NavigationEntry
* NavigationEntry::Create() {
44 return new NavigationEntryImpl();
47 NavigationEntryImpl
* NavigationEntryImpl::FromNavigationEntry(
48 NavigationEntry
* entry
) {
49 return static_cast<NavigationEntryImpl
*>(entry
);
52 NavigationEntryImpl::NavigationEntryImpl()
53 : NavigationEntryImpl(nullptr, -1, GURL(), Referrer(), base::string16(),
54 ui::PAGE_TRANSITION_LINK
, false) {
57 NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl
* instance
,
60 const Referrer
& referrer
,
61 const base::string16
& title
,
62 ui::PageTransition transition_type
,
63 bool is_renderer_initiated
)
65 new TreeNode(new FrameNavigationEntry(instance
, url
, referrer
))),
66 unique_id_(GetUniqueIDInConstructor()),
67 bindings_(kInvalidBindings
),
68 page_type_(PAGE_TYPE_NORMAL
),
69 update_virtual_url_with_url_(false),
72 transition_type_(transition_type
),
73 has_post_data_(false),
75 restore_type_(RESTORE_NONE
),
76 is_overriding_user_agent_(false),
78 is_renderer_initiated_(is_renderer_initiated
),
79 should_replace_entry_(false),
80 should_clear_history_list_(false),
81 can_load_local_resources_(false),
82 frame_tree_node_id_(-1) {
85 NavigationEntryImpl::~NavigationEntryImpl() {
88 int NavigationEntryImpl::GetUniqueID() const {
92 PageType
NavigationEntryImpl::GetPageType() const {
96 void NavigationEntryImpl::SetURL(const GURL
& url
) {
97 frame_tree_
->frame_entry
->set_url(url
);
98 cached_display_title_
.clear();
101 const GURL
& NavigationEntryImpl::GetURL() const {
102 return frame_tree_
->frame_entry
->url();
105 void NavigationEntryImpl::SetBaseURLForDataURL(const GURL
& url
) {
106 base_url_for_data_url_
= url
;
109 const GURL
& NavigationEntryImpl::GetBaseURLForDataURL() const {
110 return base_url_for_data_url_
;
113 void NavigationEntryImpl::SetReferrer(const Referrer
& referrer
) {
114 frame_tree_
->frame_entry
->set_referrer(referrer
);
117 const Referrer
& NavigationEntryImpl::GetReferrer() const {
118 return frame_tree_
->frame_entry
->referrer();
121 void NavigationEntryImpl::SetVirtualURL(const GURL
& url
) {
122 virtual_url_
= (url
== GetURL()) ? GURL() : url
;
123 cached_display_title_
.clear();
126 const GURL
& NavigationEntryImpl::GetVirtualURL() const {
127 return virtual_url_
.is_empty() ? GetURL() : virtual_url_
;
130 void NavigationEntryImpl::SetTitle(const base::string16
& title
) {
132 cached_display_title_
.clear();
135 const base::string16
& NavigationEntryImpl::GetTitle() const {
139 void NavigationEntryImpl::SetPageState(const PageState
& state
) {
143 const PageState
& NavigationEntryImpl::GetPageState() const {
147 void NavigationEntryImpl::SetPageID(int page_id
) {
151 int32
NavigationEntryImpl::GetPageID() const {
155 void NavigationEntryImpl::set_site_instance(SiteInstanceImpl
* site_instance
) {
156 // TODO(creis): Update all callers and remove this method.
157 frame_tree_
->frame_entry
->set_site_instance(site_instance
);
160 void NavigationEntryImpl::set_source_site_instance(
161 SiteInstanceImpl
* source_site_instance
) {
162 source_site_instance_
= source_site_instance
;
165 void NavigationEntryImpl::SetBindings(int bindings
) {
166 // Ensure this is set to a valid value, and that it stays the same once set.
167 CHECK_NE(bindings
, kInvalidBindings
);
168 CHECK(bindings_
== kInvalidBindings
|| bindings_
== bindings
);
169 bindings_
= bindings
;
172 const base::string16
& NavigationEntryImpl::GetTitleForDisplay(
173 const std::string
& languages
) const {
174 // Most pages have real titles. Don't even bother caching anything if this is
179 // More complicated cases will use the URLs as the title. This result we will
180 // cache since it's more complicated to compute.
181 if (!cached_display_title_
.empty())
182 return cached_display_title_
;
184 // Use the virtual URL first if any, and fall back on using the real URL.
185 base::string16 title
;
186 if (!virtual_url_
.is_empty()) {
187 title
= net::FormatUrl(virtual_url_
, languages
);
188 } else if (!GetURL().is_empty()) {
189 title
= net::FormatUrl(GetURL(), languages
);
192 // For file:// URLs use the filename as the title, not the full path.
193 if (GetURL().SchemeIsFile()) {
194 base::string16::size_type slashpos
= title
.rfind('/');
195 if (slashpos
!= base::string16::npos
)
196 title
= title
.substr(slashpos
+ 1);
199 gfx::ElideString(title
, kMaxTitleChars
, &cached_display_title_
);
200 return cached_display_title_
;
203 bool NavigationEntryImpl::IsViewSourceMode() const {
204 return virtual_url_
.SchemeIs(kViewSourceScheme
);
207 void NavigationEntryImpl::SetTransitionType(
208 ui::PageTransition transition_type
) {
209 transition_type_
= transition_type
;
212 ui::PageTransition
NavigationEntryImpl::GetTransitionType() const {
213 return transition_type_
;
216 const GURL
& NavigationEntryImpl::GetUserTypedURL() const {
217 return user_typed_url_
;
220 void NavigationEntryImpl::SetHasPostData(bool has_post_data
) {
221 has_post_data_
= has_post_data
;
224 bool NavigationEntryImpl::GetHasPostData() const {
225 return has_post_data_
;
228 void NavigationEntryImpl::SetPostID(int64 post_id
) {
232 int64
NavigationEntryImpl::GetPostID() const {
236 void NavigationEntryImpl::SetBrowserInitiatedPostData(
237 const base::RefCountedMemory
* data
) {
238 browser_initiated_post_data_
= data
;
241 const base::RefCountedMemory
*
242 NavigationEntryImpl::GetBrowserInitiatedPostData() const {
243 return browser_initiated_post_data_
.get();
247 const FaviconStatus
& NavigationEntryImpl::GetFavicon() const {
251 FaviconStatus
& NavigationEntryImpl::GetFavicon() {
255 const SSLStatus
& NavigationEntryImpl::GetSSL() const {
259 SSLStatus
& NavigationEntryImpl::GetSSL() {
263 void NavigationEntryImpl::SetOriginalRequestURL(const GURL
& original_url
) {
264 original_request_url_
= original_url
;
267 const GURL
& NavigationEntryImpl::GetOriginalRequestURL() const {
268 return original_request_url_
;
271 void NavigationEntryImpl::SetIsOverridingUserAgent(bool override
) {
272 is_overriding_user_agent_
= override
;
275 bool NavigationEntryImpl::GetIsOverridingUserAgent() const {
276 return is_overriding_user_agent_
;
279 void NavigationEntryImpl::SetTimestamp(base::Time timestamp
) {
280 timestamp_
= timestamp
;
283 base::Time
NavigationEntryImpl::GetTimestamp() const {
287 void NavigationEntryImpl::SetHttpStatusCode(int http_status_code
) {
288 http_status_code_
= http_status_code
;
291 int NavigationEntryImpl::GetHttpStatusCode() const {
292 return http_status_code_
;
295 void NavigationEntryImpl::SetRedirectChain(
296 const std::vector
<GURL
>& redirect_chain
) {
297 redirect_chain_
= redirect_chain
;
300 const std::vector
<GURL
>& NavigationEntryImpl::GetRedirectChain() const {
301 return redirect_chain_
;
304 bool NavigationEntryImpl::IsRestored() const {
305 return restore_type_
!= RESTORE_NONE
;
308 void NavigationEntryImpl::SetCanLoadLocalResources(bool allow
) {
309 can_load_local_resources_
= allow
;
312 bool NavigationEntryImpl::GetCanLoadLocalResources() const {
313 return can_load_local_resources_
;
316 void NavigationEntryImpl::SetFrameToNavigate(const std::string
& frame_name
) {
317 frame_to_navigate_
= frame_name
;
320 const std::string
& NavigationEntryImpl::GetFrameToNavigate() const {
321 return frame_to_navigate_
;
324 void NavigationEntryImpl::SetExtraData(const std::string
& key
,
325 const base::string16
& data
) {
326 extra_data_
[key
] = data
;
329 bool NavigationEntryImpl::GetExtraData(const std::string
& key
,
330 base::string16
* data
) const {
331 std::map
<std::string
, base::string16
>::const_iterator iter
=
332 extra_data_
.find(key
);
333 if (iter
== extra_data_
.end())
335 *data
= iter
->second
;
339 void NavigationEntryImpl::ClearExtraData(const std::string
& key
) {
340 extra_data_
.erase(key
);
343 NavigationEntryImpl
* NavigationEntryImpl::Clone() const {
344 NavigationEntryImpl
* copy
= new NavigationEntryImpl();
346 // TODO(creis): Only share the same FrameNavigationEntries if cloning within
348 copy
->frame_tree_
.reset(frame_tree_
->Clone());
350 // Copy all state over, unless cleared in ResetForCommit.
351 copy
->unique_id_
= unique_id_
;
352 copy
->bindings_
= bindings_
;
353 copy
->page_type_
= page_type_
;
354 copy
->virtual_url_
= virtual_url_
;
355 copy
->update_virtual_url_with_url_
= update_virtual_url_with_url_
;
356 copy
->title_
= title_
;
357 copy
->favicon_
= favicon_
;
358 copy
->page_state_
= page_state_
;
359 copy
->page_id_
= page_id_
;
361 copy
->transition_type_
= transition_type_
;
362 copy
->user_typed_url_
= user_typed_url_
;
363 copy
->has_post_data_
= has_post_data_
;
364 copy
->post_id_
= post_id_
;
365 copy
->restore_type_
= restore_type_
;
366 copy
->original_request_url_
= original_request_url_
;
367 copy
->is_overriding_user_agent_
= is_overriding_user_agent_
;
368 copy
->timestamp_
= timestamp_
;
369 copy
->http_status_code_
= http_status_code_
;
370 // ResetForCommit: browser_initiated_post_data_
371 copy
->screenshot_
= screenshot_
;
372 copy
->extra_headers_
= extra_headers_
;
373 // ResetForCommit: source_site_instance_
374 copy
->base_url_for_data_url_
= base_url_for_data_url_
;
375 // ResetForCommit: is_renderer_initiated_
376 copy
->cached_display_title_
= cached_display_title_
;
377 // ResetForCommit: transferred_global_request_id_
378 // ResetForCommit: should_replace_entry_
379 copy
->redirect_chain_
= redirect_chain_
;
380 // ResetForCommit: should_clear_history_list_
381 copy
->frame_to_navigate_
= frame_to_navigate_
;
382 // ResetForCommit: frame_tree_node_id_
383 // ResetForCommit: intent_received_timestamp_
384 copy
->extra_data_
= extra_data_
;
389 CommonNavigationParams
NavigationEntryImpl::ConstructCommonNavigationParams(
390 FrameMsg_Navigate_Type::Value navigation_type
) const {
391 FrameMsg_UILoadMetricsReportType::Value report_type
=
392 FrameMsg_UILoadMetricsReportType::NO_REPORT
;
393 base::TimeTicks ui_timestamp
= base::TimeTicks();
394 #if defined(OS_ANDROID)
395 if (!intent_received_timestamp().is_null())
396 report_type
= FrameMsg_UILoadMetricsReportType::REPORT_INTENT
;
397 ui_timestamp
= intent_received_timestamp();
400 return CommonNavigationParams(
401 GetURL(), GetReferrer(), GetTransitionType(), navigation_type
,
402 !IsViewSourceMode(), ui_timestamp
, report_type
, GetBaseURLForDataURL(),
403 GetHistoryURLForDataURL());
406 StartNavigationParams
NavigationEntryImpl::ConstructStartNavigationParams()
408 std::vector
<unsigned char> browser_initiated_post_data
;
409 if (GetBrowserInitiatedPostData()) {
410 browser_initiated_post_data
.assign(
411 GetBrowserInitiatedPostData()->front(),
412 GetBrowserInitiatedPostData()->front() +
413 GetBrowserInitiatedPostData()->size());
416 return StartNavigationParams(
417 GetHasPostData(), extra_headers(), browser_initiated_post_data
,
418 should_replace_entry(), transferred_global_request_id().child_id
,
419 transferred_global_request_id().request_id
);
422 RequestNavigationParams
NavigationEntryImpl::ConstructRequestNavigationParams(
423 base::TimeTicks navigation_start
,
424 int pending_history_list_offset
,
425 int current_history_list_offset
,
426 int current_history_list_length
) const {
427 // Set the redirect chain to the navigation's redirects, unless returning to a
428 // completed navigation (whose previous redirects don't apply).
429 std::vector
<GURL
> redirects
;
430 if (ui::PageTransitionIsNewNavigation(GetTransitionType())) {
431 redirects
= GetRedirectChain();
434 int pending_offset_to_send
= pending_history_list_offset
;
435 int current_offset_to_send
= current_history_list_offset
;
436 int current_length_to_send
= current_history_list_length
;
437 if (should_clear_history_list()) {
438 // Set the history list related parameters to the same values a
439 // NavigationController would return before its first navigation. This will
440 // fully clear the RenderView's view of the session history.
441 pending_offset_to_send
= -1;
442 current_offset_to_send
= -1;
443 current_length_to_send
= 0;
445 return RequestNavigationParams(
446 GetIsOverridingUserAgent(), navigation_start
, redirects
,
447 GetCanLoadLocalResources(), GetFrameToNavigate(), base::Time::Now(),
448 GetPageState(), GetPageID(), pending_offset_to_send
,
449 current_offset_to_send
, current_length_to_send
,
450 should_clear_history_list());
453 void NavigationEntryImpl::ResetForCommit() {
454 // Any state that only matters when a navigation entry is pending should be
456 // TODO(creis): This state should be moved to NavigationRequest once
457 // PlzNavigate is enabled.
458 SetBrowserInitiatedPostData(nullptr);
459 set_source_site_instance(nullptr);
460 set_is_renderer_initiated(false);
461 set_transferred_global_request_id(GlobalRequestID());
462 set_should_replace_entry(false);
464 set_should_clear_history_list(false);
465 set_frame_tree_node_id(-1);
467 #if defined(OS_ANDROID)
468 // Reset the time stamp so that the metrics are not reported if this entry is
469 // loaded again in the future.
470 set_intent_received_timestamp(base::TimeTicks());
474 void NavigationEntryImpl::AddOrUpdateFrameEntry(int64 frame_tree_node_id
,
475 SiteInstanceImpl
* site_instance
,
477 const Referrer
& referrer
) {
478 // TODO(creis): Walk tree to find the node to update.
479 // TODO(creis): Only create a new entry if one doesn't exist yet.
480 FrameNavigationEntry
* frame_entry
=
481 new FrameNavigationEntry(site_instance
, url
, referrer
);
482 root_node()->children
.push_back(
483 new NavigationEntryImpl::TreeNode(frame_entry
));
486 void NavigationEntryImpl::SetScreenshotPNGData(
487 scoped_refptr
<base::RefCountedBytes
> png_data
) {
488 screenshot_
= png_data
;
489 if (screenshot_
.get())
490 UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_
->size());
493 GURL
NavigationEntryImpl::GetHistoryURLForDataURL() const {
494 return GetBaseURLForDataURL().is_empty() ? GURL() : GetVirtualURL();
497 } // namespace content