OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/browser/transition_request_manager.h" | |
6 | |
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" | |
16 | |
17 namespace { | |
18 | |
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, | |
24 void** iter, | |
25 const std::string& rel, | |
26 std::string* url, | |
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) { | |
36 break; | |
37 } | |
38 | |
39 if (attributes) | |
40 attributes->clear(); | |
41 | |
42 net::HttpUtil::NameValuePairsIterator param_iter( | |
43 begin + url_end + 1, header_body.end(), ';'); | |
44 | |
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(), | |
50 rel.c_str())) { | |
51 if (url) { | |
52 url->assign(begin + url_start + 1, begin + url_end); | |
53 } | |
54 rel_matched = true; | |
55 } else { | |
56 break; | |
57 } | |
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)); | |
64 } | |
65 } | |
66 } | |
67 | |
68 if (!rel_matched && attributes) { | |
69 attributes->clear(); | |
70 } | |
71 | |
72 return rel_matched; | |
73 } | |
74 | |
75 } // namespace | |
76 | |
77 namespace content { | |
78 | |
79 TransitionLayerData::TransitionLayerData() { | |
80 } | |
81 | |
82 TransitionLayerData::~TransitionLayerData() { | |
83 } | |
84 | |
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), | |
92 markup(markup), | |
93 elements(elements) { | |
94 } | |
95 | |
96 TransitionRequestManager::TransitionRequestData::AllowedEntry::~AllowedEntry() { | |
97 } | |
98 | |
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) | |
104 return; | |
105 | |
106 std::string transition_stylesheet; | |
107 base::StringPairs attributes; | |
108 void* header_iter = NULL; | |
109 while (EnumerateLinkHeaders(headers, | |
110 &header_iter, | |
111 "transition-entering-stylesheet", | |
112 &transition_stylesheet, | |
113 &attributes)) { | |
114 GURL stylesheet_url = resolve_address.Resolve(transition_stylesheet); | |
115 if (stylesheet_url.is_valid()) | |
116 entering_stylesheets.push_back(stylesheet_url); | |
117 } | |
118 } | |
119 | |
120 TransitionRequestManager::TransitionRequestData::TransitionRequestData() { | |
121 } | |
122 | |
123 TransitionRequestManager::TransitionRequestData::~TransitionRequestData() { | |
124 } | |
125 | |
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, | |
132 css_selector, | |
133 markup, | |
134 elements)); | |
135 } | |
136 | |
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") == | |
145 "Enabled"); | |
146 | |
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 | |
150 // use that instead. | |
151 bool is_valid = (allowed_entry.allowed_destination_host_pattern == "*"); | |
152 if (!is_valid) { | |
153 GURL allowed_host(allowed_entry.allowed_destination_host_pattern); | |
154 if (allowed_host.is_valid() && | |
155 (allowed_host.GetOrigin() == request_url.GetOrigin())) { | |
156 is_valid = true; | |
157 } | |
158 } | |
159 | |
160 if (is_valid) { | |
161 transition_data->markup = allowed_entry.markup; | |
162 transition_data->css_selector = allowed_entry.css_selector; | |
163 transition_data->elements = allowed_entry.elements; | |
164 return true; | |
165 } | |
166 } | |
167 | |
168 return false; | |
169 } | |
170 | |
171 bool TransitionRequestManager::GetPendingTransitionRequest( | |
172 int render_process_id, | |
173 int render_frame_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); | |
183 } | |
184 | |
185 void TransitionRequestManager::AddPendingTransitionRequestData( | |
186 int render_process_id, | |
187 int render_frame_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); | |
193 | |
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); | |
197 } | |
198 | |
199 void TransitionRequestManager::AddPendingTransitionRequestDataForTesting( | |
200 int render_process_id, | |
201 int render_frame_id) { | |
202 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
203 | |
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 */ | |
208 "", /* markup */ | |
209 std::vector<TransitionElement>()); /* elements */ | |
210 } | |
211 | |
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); | |
217 } | |
218 | |
219 TransitionRequestManager::TransitionRequestManager() { | |
220 } | |
221 | |
222 TransitionRequestManager::~TransitionRequestManager() { | |
223 } | |
224 | |
225 // static | |
226 TransitionRequestManager* TransitionRequestManager::GetInstance() { | |
227 return Singleton<TransitionRequestManager>::get(); | |
228 } | |
229 | |
230 } // namespace content | |
OLD | NEW |