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 // TODO(oysteine): Add CSP check to validate the host pattern and the
143 // request_url. Must be done before this feature is moved out from the flag.
144 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
145 switches::kEnableExperimentalWebPlatformFeatures
) ||
146 base::FieldTrialList::FindFullName("NavigationTransitions") ==
149 const AllowedEntry
& allowed_entry
= allowed_entries_
[0];
150 transition_data
->markup
= allowed_entry
.markup
;
151 transition_data
->css_selector
= allowed_entry
.css_selector
;
152 transition_data
->elements
= allowed_entry
.elements
;
156 bool TransitionRequestManager::GetPendingTransitionRequest(
157 int render_process_id
,
159 const GURL
& request_url
,
160 TransitionLayerData
* transition_data
) {
161 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
162 DCHECK(transition_data
);
163 std::pair
<int, int> key(render_process_id
, render_frame_id
);
164 RenderFrameRequestDataMap::iterator iter
=
165 pending_transition_frames_
.find(key
);
166 return iter
!= pending_transition_frames_
.end() &&
167 iter
->second
.FindEntry(request_url
, transition_data
);
170 void TransitionRequestManager::AddPendingTransitionRequestData(
171 int render_process_id
,
173 const std::string
& allowed_destination_host_pattern
,
174 const std::string
& css_selector
,
175 const std::string
& markup
,
176 const std::vector
<TransitionElement
>& elements
) {
177 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
179 std::pair
<int, int> key(render_process_id
, render_frame_id
);
180 pending_transition_frames_
[key
].AddEntry(
181 allowed_destination_host_pattern
, css_selector
, markup
, elements
);
184 void TransitionRequestManager::AddPendingTransitionRequestDataForTesting(
185 int render_process_id
,
186 int render_frame_id
) {
187 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
189 std::pair
<int, int> key(render_process_id
, render_frame_id
);
190 pending_transition_frames_
[key
].AddEntry(
191 "*", /* allowed_destination_host_pattern */
192 "", /* css_selector */
194 std::vector
<TransitionElement
>()); /* elements */
197 void TransitionRequestManager::ClearPendingTransitionRequestData(
198 int render_process_id
, int render_frame_id
) {
199 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
200 std::pair
<int, int> key(render_process_id
, render_frame_id
);
201 pending_transition_frames_
.erase(key
);
204 TransitionRequestManager::TransitionRequestManager() {
207 TransitionRequestManager::~TransitionRequestManager() {
211 TransitionRequestManager
* TransitionRequestManager::GetInstance() {
212 return Singleton
<TransitionRequestManager
>::get();
215 } // namespace content