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
<std::string
>& names
,
90 const std::vector
<gfx::Rect
>& rects
)
91 : allowed_destination_host_pattern(allowed_destination_host_pattern
),
92 css_selector(css_selector
),
98 TransitionRequestManager::TransitionRequestData::AllowedEntry::~AllowedEntry() {
101 void TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
102 const scoped_refptr
<net::HttpResponseHeaders
>& headers
,
103 std::vector
<GURL
>& entering_stylesheets
,
104 const GURL
& resolve_address
) {
105 if (headers
.get() == NULL
)
108 std::string transition_stylesheet
;
109 base::StringPairs attributes
;
110 void* header_iter
= NULL
;
111 while (EnumerateLinkHeaders(headers
,
113 "transition-entering-stylesheet",
114 &transition_stylesheet
,
116 GURL stylesheet_url
= resolve_address
.Resolve(transition_stylesheet
);
117 if (stylesheet_url
.is_valid())
118 entering_stylesheets
.push_back(stylesheet_url
);
122 TransitionRequestManager::TransitionRequestData::TransitionRequestData() {
125 TransitionRequestManager::TransitionRequestData::~TransitionRequestData() {
128 void TransitionRequestManager::TransitionRequestData::AddEntry(
129 const std::string
& allowed_destination_host_pattern
,
130 const std::string
& css_selector
,
131 const std::string
& markup
,
132 const std::vector
<std::string
>& names
,
133 const std::vector
<gfx::Rect
>& rects
) {
134 allowed_entries_
.push_back(AllowedEntry(allowed_destination_host_pattern
,
141 bool TransitionRequestManager::TransitionRequestData::FindEntry(
142 const GURL
& request_url
,
143 TransitionLayerData
* transition_data
) {
144 DCHECK(!allowed_entries_
.empty());
145 CHECK(transition_data
);
146 // TODO(oysteine): Add CSP check to validate the host pattern and the
147 // request_url. Must be done before this feature is moved out from the flag.
148 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
149 switches::kEnableExperimentalWebPlatformFeatures
) ||
150 base::FieldTrialList::FindFullName("NavigationTransitions") ==
153 const AllowedEntry
& allowed_entry
= allowed_entries_
[0];
154 transition_data
->markup
= allowed_entry
.markup
;
155 transition_data
->css_selector
= allowed_entry
.css_selector
;
156 transition_data
->names
= allowed_entry
.names
;
157 transition_data
->rects
= allowed_entry
.rects
;
161 bool TransitionRequestManager::HasPendingTransitionRequest(
162 int render_process_id
,
164 const GURL
& request_url
,
165 TransitionLayerData
* transition_data
) {
166 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
167 DCHECK(transition_data
);
168 std::pair
<int, int> key(render_process_id
, render_frame_id
);
169 RenderFrameRequestDataMap::iterator iter
=
170 pending_transition_frames_
.find(key
);
171 return iter
!= pending_transition_frames_
.end() &&
172 iter
->second
.FindEntry(request_url
, transition_data
);
175 void TransitionRequestManager::AddPendingTransitionRequestData(
176 int render_process_id
,
178 const std::string
& allowed_destination_host_pattern
,
179 const std::string
& css_selector
,
180 const std::string
& markup
,
181 const std::vector
<std::string
>& names
,
182 const std::vector
<gfx::Rect
>& rects
) {
183 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
185 std::pair
<int, int> key(render_process_id
, render_frame_id
);
186 pending_transition_frames_
[key
].AddEntry(
187 allowed_destination_host_pattern
, css_selector
, markup
, names
, rects
);
190 void TransitionRequestManager::AddPendingTransitionRequestDataForTesting(
191 int render_process_id
,
192 int render_frame_id
) {
193 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
195 std::pair
<int, int> key(render_process_id
, render_frame_id
);
196 pending_transition_frames_
[key
].AddEntry(
197 "*", /* allowed_destination_host_pattern */
198 "", /* css_selector */
200 std::vector
<std::string
>(), /* names */
201 std::vector
<gfx::Rect
>()); /* rects */
204 void TransitionRequestManager::ClearPendingTransitionRequestData(
205 int render_process_id
, int render_frame_id
) {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
207 std::pair
<int, int> key(render_process_id
, render_frame_id
);
208 pending_transition_frames_
.erase(key
);
211 TransitionRequestManager::TransitionRequestManager() {
214 TransitionRequestManager::~TransitionRequestManager() {
218 TransitionRequestManager
* TransitionRequestManager::GetInstance() {
219 return Singleton
<TransitionRequestManager
>::get();
222 } // namespace content