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.
5 #include "content/browser/transition_request_manager.h"
7 #include "base/command_line.h"
8 #include "base/memory/singleton.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/strings/string_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/common/content_switches.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_util.h"
18 // Enumerate all Link: headers with the specified relation in this
19 // response, and optionally returns the URL and any additional attributes of
20 // each one. See EnumerateHeaders for |iter| usage.
21 bool EnumerateLinkHeaders(
22 const scoped_refptr
<net::HttpResponseHeaders
>& headers
,
24 const std::string
& rel
,
26 std::vector
<std::pair
<std::string
, std::string
> >* attributes
) {
27 std::string header_body
;
28 bool rel_matched
= false;
29 while (!rel_matched
&& headers
->EnumerateHeader(iter
, "link", &header_body
)) {
30 const std::string::const_iterator begin
= header_body
.begin();
31 size_t url_start
= header_body
.find_first_of('<');
32 size_t url_end
= header_body
.find_first_of('>');
33 if (url_start
== std::string::npos
|| url_end
== std::string::npos
||
34 url_start
> url_end
) {
41 net::HttpUtil::NameValuePairsIterator
param_iter(
42 begin
+ url_end
+ 1, header_body
.end(), ';');
44 while (param_iter
.GetNext()) {
45 if (LowerCaseEqualsASCII(
46 param_iter
.name_begin(), param_iter
.name_end(), "rel")) {
47 if (LowerCaseEqualsASCII(param_iter
.value_begin(),
48 param_iter
.value_end(),
51 url
->assign(begin
+ url_start
+ 1, begin
+ url_end
);
57 } else if (attributes
) {
58 std::string
attribute_name(param_iter
.name_begin(),
59 param_iter
.name_end());
60 std::string
attribute_value(param_iter
.value_begin(),
61 param_iter
.value_end());
62 attributes
->push_back(std::make_pair(attribute_name
, attribute_value
));
67 if (!rel_matched
&& attributes
) {
78 TransitionLayerData::TransitionLayerData() {
81 TransitionLayerData::~TransitionLayerData() {
84 void TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
85 const scoped_refptr
<net::HttpResponseHeaders
>& headers
,
86 std::vector
<GURL
>& entering_stylesheets
,
87 const GURL
& resolve_address
) {
88 if (headers
.get() == NULL
)
91 std::string transition_stylesheet
;
92 std::vector
<std::pair
<std::string
, std::string
> > attributes
;
93 void* header_iter
= NULL
;
94 while (EnumerateLinkHeaders(headers
,
96 "transition-entering-stylesheet",
97 &transition_stylesheet
,
99 GURL stylesheet_url
= resolve_address
.Resolve(transition_stylesheet
);
100 if (stylesheet_url
.is_valid())
101 entering_stylesheets
.push_back(stylesheet_url
);
105 TransitionRequestManager::TransitionRequestData::TransitionRequestData() {
108 TransitionRequestManager::TransitionRequestData::~TransitionRequestData() {
111 void TransitionRequestManager::TransitionRequestData::AddEntry(
112 const std::string
& allowed_destination_host_pattern
,
113 const std::string
& css_selector
,
114 const std::string
& markup
) {
115 allowed_entries_
.push_back(AllowedEntry(allowed_destination_host_pattern
,
120 bool TransitionRequestManager::TransitionRequestData::FindEntry(
121 const GURL
& request_url
,
122 TransitionLayerData
* transition_data
) {
123 DCHECK(!allowed_entries_
.empty());
124 CHECK(transition_data
);
125 // TODO(oysteine): Add CSP check to validate the host pattern and the
126 // request_url. Must be done before this feature is moved out from the flag.
127 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
128 switches::kEnableExperimentalWebPlatformFeatures
) ||
129 base::FieldTrialList::FindFullName("NavigationTransitions") ==
132 const AllowedEntry
& allowed_entry
= allowed_entries_
[0];
133 transition_data
->markup
= allowed_entry
.markup
;
134 transition_data
->css_selector
= allowed_entry
.css_selector
;
138 bool TransitionRequestManager::HasPendingTransitionRequest(
139 int render_process_id
,
141 const GURL
& request_url
,
142 TransitionLayerData
* transition_data
) {
143 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
144 DCHECK(transition_data
);
145 std::pair
<int, int> key(render_process_id
, render_frame_id
);
146 RenderFrameRequestDataMap::iterator iter
=
147 pending_transition_frames_
.find(key
);
148 return iter
!= pending_transition_frames_
.end() &&
149 iter
->second
.FindEntry(request_url
, transition_data
);
152 void TransitionRequestManager::AddPendingTransitionRequestData(
153 int render_process_id
,
155 const std::string
& allowed_destination_host_pattern
,
156 const std::string
& css_selector
,
157 const std::string
& markup
) {
158 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
160 std::pair
<int, int> key(render_process_id
, render_frame_id
);
161 pending_transition_frames_
[key
].AddEntry(allowed_destination_host_pattern
,
166 void TransitionRequestManager::ClearPendingTransitionRequestData(
167 int render_process_id
, int render_frame_id
) {
168 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
169 std::pair
<int, int> key(render_process_id
, render_frame_id
);
170 pending_transition_frames_
.erase(key
);
173 TransitionRequestManager::TransitionRequestManager() {
176 TransitionRequestManager::~TransitionRequestManager() {
180 TransitionRequestManager
* TransitionRequestManager::GetInstance() {
181 return Singleton
<TransitionRequestManager
>::get();
184 } // namespace content