| 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 |