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_split.h"
11 #include "base/strings/string_util.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/common/content_switches.h"
14 #include "net/http/http_response_headers.h"
15 #include "net/http/http_util.h"
19 // Enumerate all Link: headers with the specified relation in this
20 // response, and optionally returns the URL and any additional attributes of
21 // each one. See EnumerateHeaders for |iter| usage.
22 bool EnumerateLinkHeaders(
23 const scoped_refptr
<net::HttpResponseHeaders
>& headers
,
25 const std::string
& rel
,
27 base::StringPairs
* attributes
) {
28 std::string header_body
;
29 bool rel_matched
= false;
30 while (!rel_matched
&& headers
->EnumerateHeader(iter
, "link", &header_body
)) {
31 const std::string::const_iterator begin
= header_body
.begin();
32 size_t url_start
= header_body
.find_first_of('<');
33 size_t url_end
= header_body
.find_first_of('>');
34 if (url_start
== std::string::npos
|| url_end
== std::string::npos
||
35 url_start
> url_end
) {
42 net::HttpUtil::NameValuePairsIterator
param_iter(
43 begin
+ url_end
+ 1, header_body
.end(), ';');
45 while (param_iter
.GetNext()) {
46 if (LowerCaseEqualsASCII(
47 param_iter
.name_begin(), param_iter
.name_end(), "rel")) {
48 if (LowerCaseEqualsASCII(param_iter
.value_begin(),
49 param_iter
.value_end(),
52 url
->assign(begin
+ url_start
+ 1, begin
+ url_end
);
58 } else if (attributes
) {
59 std::string
attribute_name(param_iter
.name_begin(),
60 param_iter
.name_end());
61 std::string
attribute_value(param_iter
.value_begin(),
62 param_iter
.value_end());
63 attributes
->push_back(std::make_pair(attribute_name
, attribute_value
));
68 if (!rel_matched
&& attributes
) {
79 TransitionLayerData::TransitionLayerData() {
82 TransitionLayerData::~TransitionLayerData() {
85 TransitionRequestManager::TransitionRequestData::AllowedEntry::AllowedEntry(
86 const std::string
& allowed_destination_host_pattern
,
87 const std::string
& css_selector
,
88 const std::string
& markup
,
89 const std::vector
<TransitionElement
>& elements
)
90 : allowed_destination_host_pattern(allowed_destination_host_pattern
),
91 css_selector(css_selector
),
96 TransitionRequestManager::TransitionRequestData::AllowedEntry::~AllowedEntry() {
99 void TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
100 const scoped_refptr
<net::HttpResponseHeaders
>& headers
,
101 std::vector
<GURL
>& entering_stylesheets
,
102 const GURL
& resolve_address
) {
103 if (headers
.get() == NULL
)
106 std::string transition_stylesheet
;
107 base::StringPairs attributes
;
108 void* header_iter
= NULL
;
109 while (EnumerateLinkHeaders(headers
,
111 "transition-entering-stylesheet",
112 &transition_stylesheet
,
114 GURL stylesheet_url
= resolve_address
.Resolve(transition_stylesheet
);
115 if (stylesheet_url
.is_valid())
116 entering_stylesheets
.push_back(stylesheet_url
);
120 TransitionRequestManager::TransitionRequestData::TransitionRequestData() {
123 TransitionRequestManager::TransitionRequestData::~TransitionRequestData() {
126 void TransitionRequestManager::TransitionRequestData::AddEntry(
127 const std::string
& allowed_destination_host_pattern
,
128 const std::string
& css_selector
,
129 const std::string
& markup
,
130 const std::vector
<TransitionElement
>& elements
) {
131 allowed_entries_
.push_back(AllowedEntry(allowed_destination_host_pattern
,
137 bool TransitionRequestManager::TransitionRequestData::FindEntry(
138 const GURL
& request_url
,
139 TransitionLayerData
* transition_data
) {
140 DCHECK(!allowed_entries_
.empty());
141 CHECK(transition_data
);
142 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
143 switches::kEnableExperimentalWebPlatformFeatures
) ||
144 base::FieldTrialList::FindFullName("NavigationTransitions") ==
147 for (const AllowedEntry
& allowed_entry
: allowed_entries_
) {
148 // Note: This is a small subset of the CSP source-list standard; once the
149 // full CSP support is moved from the renderer to the browser, we should
151 bool is_valid
= (allowed_entry
.allowed_destination_host_pattern
== "*");
153 GURL
allowed_host(allowed_entry
.allowed_destination_host_pattern
);
154 if (allowed_host
.is_valid() &&
155 (allowed_host
.GetOrigin() == request_url
.GetOrigin())) {
161 transition_data
->markup
= allowed_entry
.markup
;
162 transition_data
->css_selector
= allowed_entry
.css_selector
;
163 transition_data
->elements
= allowed_entry
.elements
;
171 bool TransitionRequestManager::GetPendingTransitionRequest(
172 int render_process_id
,
174 const GURL
& request_url
,
175 TransitionLayerData
* transition_data
) {
176 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
177 DCHECK(transition_data
);
178 std::pair
<int, int> key(render_process_id
, render_frame_id
);
179 RenderFrameRequestDataMap::iterator iter
=
180 pending_transition_frames_
.find(key
);
181 return iter
!= pending_transition_frames_
.end() &&
182 iter
->second
.FindEntry(request_url
, transition_data
);
185 void TransitionRequestManager::AddPendingTransitionRequestData(
186 int render_process_id
,
188 const std::string
& allowed_destination_host_pattern
,
189 const std::string
& css_selector
,
190 const std::string
& markup
,
191 const std::vector
<TransitionElement
>& elements
) {
192 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
194 std::pair
<int, int> key(render_process_id
, render_frame_id
);
195 pending_transition_frames_
[key
].AddEntry(
196 allowed_destination_host_pattern
, css_selector
, markup
, elements
);
199 void TransitionRequestManager::AddPendingTransitionRequestDataForTesting(
200 int render_process_id
,
201 int render_frame_id
) {
202 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
204 std::pair
<int, int> key(render_process_id
, render_frame_id
);
205 pending_transition_frames_
[key
].AddEntry(
206 "*", /* allowed_destination_host_pattern */
207 "", /* css_selector */
209 std::vector
<TransitionElement
>()); /* elements */
212 void TransitionRequestManager::ClearPendingTransitionRequestData(
213 int render_process_id
, int render_frame_id
) {
214 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
215 std::pair
<int, int> key(render_process_id
, render_frame_id
);
216 pending_transition_frames_
.erase(key
);
219 TransitionRequestManager::TransitionRequestManager() {
222 TransitionRequestManager::~TransitionRequestManager() {
226 TransitionRequestManager
* TransitionRequestManager::GetInstance() {
227 return Singleton
<TransitionRequestManager
>::get();
230 } // namespace content