Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: content/browser/webui/url_data_manager_backend.cc

Issue 2860903006: Handle webuis when using the network service. (Closed)
Patch Set: merge Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/webui/url_data_manager_backend.h" 5 #include "content/browser/webui/url_data_manager_backend.h"
6 6
7 #include <set> 7 #include <set>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 27 matching lines...) Expand all
38 #include "content/public/browser/browser_context.h" 38 #include "content/public/browser/browser_context.h"
39 #include "content/public/browser/browser_thread.h" 39 #include "content/public/browser/browser_thread.h"
40 #include "content/public/browser/content_browser_client.h" 40 #include "content/public/browser/content_browser_client.h"
41 #include "content/public/browser/render_process_host.h" 41 #include "content/public/browser/render_process_host.h"
42 #include "content/public/browser/resource_request_info.h" 42 #include "content/public/browser/resource_request_info.h"
43 #include "content/public/common/url_constants.h" 43 #include "content/public/common/url_constants.h"
44 #include "net/base/io_buffer.h" 44 #include "net/base/io_buffer.h"
45 #include "net/base/net_errors.h" 45 #include "net/base/net_errors.h"
46 #include "net/filter/gzip_source_stream.h" 46 #include "net/filter/gzip_source_stream.h"
47 #include "net/filter/source_stream.h" 47 #include "net/filter/source_stream.h"
48 #include "net/http/http_response_headers.h"
49 #include "net/http/http_status_code.h" 48 #include "net/http/http_status_code.h"
50 #include "net/log/net_log_util.h" 49 #include "net/log/net_log_util.h"
51 #include "net/url_request/url_request.h" 50 #include "net/url_request/url_request.h"
52 #include "net/url_request/url_request_context.h" 51 #include "net/url_request/url_request_context.h"
53 #include "net/url_request/url_request_error_job.h" 52 #include "net/url_request/url_request_error_job.h"
54 #include "net/url_request/url_request_job.h" 53 #include "net/url_request/url_request_job.h"
55 #include "net/url_request/url_request_job_factory.h" 54 #include "net/url_request/url_request_job_factory.h"
56 #include "ui/base/template_expressions.h" 55 #include "ui/base/template_expressions.h"
57 #include "url/url_util.h" 56 #include "url/url_util.h"
58 57
59 namespace content { 58 namespace content {
60 59
61 namespace { 60 namespace {
62 61
63 const char kChromeURLContentSecurityPolicyHeaderBase[] = 62 const char kChromeURLContentSecurityPolicyHeaderBase[] =
64 "Content-Security-Policy: "; 63 "Content-Security-Policy: ";
65 64
66 const char kChromeURLXFrameOptionsHeader[] = "X-Frame-Options: DENY"; 65 const char kChromeURLXFrameOptionsHeader[] = "X-Frame-Options: DENY";
67 const char kNetworkErrorKey[] = "netError"; 66 const char kNetworkErrorKey[] = "netError";
68 67
69 bool SchemeIsInSchemes(const std::string& scheme, 68 bool SchemeIsInSchemes(const std::string& scheme,
70 const std::vector<std::string>& schemes) { 69 const std::vector<std::string>& schemes) {
71 return std::find(schemes.begin(), schemes.end(), scheme) != schemes.end(); 70 return std::find(schemes.begin(), schemes.end(), scheme) != schemes.end();
72 } 71 }
73 72
74 // Returns whether |url| passes some sanity checks and is a valid GURL.
75 bool CheckURLIsValid(const GURL& url) {
76 std::vector<std::string> additional_schemes;
77 DCHECK(url.SchemeIs(kChromeDevToolsScheme) || url.SchemeIs(kChromeUIScheme) ||
78 (GetContentClient()->browser()->GetAdditionalWebUISchemes(
79 &additional_schemes),
80 SchemeIsInSchemes(url.scheme(), additional_schemes)));
81
82 if (!url.is_valid()) {
83 NOTREACHED();
84 return false;
85 }
86
87 return true;
88 }
89
90 // Parse |url| to get the path which will be used to resolve the request. The
91 // path is the remaining portion after the scheme and hostname.
92 void URLToRequestPath(const GURL& url, std::string* path) {
93 const std::string& spec = url.possibly_invalid_spec();
94 const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
95 // + 1 to skip the slash at the beginning of the path.
96 int offset = parsed.CountCharactersBefore(url::Parsed::PATH, false) + 1;
97
98 if (offset < static_cast<int>(spec.size()))
99 path->assign(spec.substr(offset));
100 }
101
102 // Returns a value of 'Origin:' header for the |request| if the header is set. 73 // Returns a value of 'Origin:' header for the |request| if the header is set.
103 // Otherwise returns an empty string. 74 // Otherwise returns an empty string.
104 std::string GetOriginHeaderValue(const net::URLRequest* request) { 75 std::string GetOriginHeaderValue(const net::URLRequest* request) {
105 std::string result; 76 std::string result;
106 if (request->extra_request_headers().GetHeader( 77 if (request->extra_request_headers().GetHeader(
107 net::HttpRequestHeaders::kOrigin, &result)) 78 net::HttpRequestHeaders::kOrigin, &result))
108 return result; 79 return result;
109 net::HttpRequestHeaders headers; 80 net::HttpRequestHeaders headers;
110 if (request->GetFullRequestHeaders(&headers)) 81 if (request->GetFullRequestHeaders(&headers))
111 headers.GetHeader(net::HttpRequestHeaders::kOrigin, &result); 82 headers.GetHeader(net::HttpRequestHeaders::kOrigin, &result);
(...skipping 15 matching lines...) Expand all
127 } 98 }
128 99
129 } // namespace 100 } // namespace
130 101
131 // URLRequestChromeJob is a net::URLRequestJob that manages running 102 // URLRequestChromeJob is a net::URLRequestJob that manages running
132 // chrome-internal resource requests asynchronously. 103 // chrome-internal resource requests asynchronously.
133 // It hands off URL requests to ChromeURLDataManager, which asynchronously 104 // It hands off URL requests to ChromeURLDataManager, which asynchronously
134 // calls back once the data is available. 105 // calls back once the data is available.
135 class URLRequestChromeJob : public net::URLRequestJob { 106 class URLRequestChromeJob : public net::URLRequestJob {
136 public: 107 public:
137 // |is_incognito| set when job is generated from an incognito profile.
138 URLRequestChromeJob(net::URLRequest* request, 108 URLRequestChromeJob(net::URLRequest* request,
139 net::NetworkDelegate* network_delegate, 109 net::NetworkDelegate* network_delegate,
140 URLDataManagerBackend* backend, 110 URLDataManagerBackend* backend);
141 bool is_incognito);
142 111
143 // net::URLRequestJob implementation. 112 // net::URLRequestJob implementation.
144 void Start() override; 113 void Start() override;
145 void Kill() override; 114 void Kill() override;
146 int ReadRawData(net::IOBuffer* buf, int buf_size) override; 115 int ReadRawData(net::IOBuffer* buf, int buf_size) override;
147 bool GetMimeType(std::string* mime_type) const override; 116 bool GetMimeType(std::string* mime_type) const override;
148 void GetResponseInfo(net::HttpResponseInfo* info) override; 117 void GetResponseInfo(net::HttpResponseInfo* info) override;
149 std::unique_ptr<net::SourceStream> SetUpSourceStream() override; 118 std::unique_ptr<net::SourceStream> SetUpSourceStream() override;
150 119
151 // Used to notify that the requested data's |mime_type| is ready. 120 // Used to notify that the requested data's |mime_type| is ready.
152 void MimeTypeAvailable(const std::string& mime_type); 121 void MimeTypeAvailable(const std::string& mime_type);
153 122
154 // Called by ChromeURLDataManager to notify us that the data blob is ready 123 // Called by ChromeURLDataManager to notify us that the data blob is ready
155 // for us. |bytes| may be null, indicating an error. 124 // for us. |bytes| may be null, indicating an error.
156 void DataAvailable(base::RefCountedMemory* bytes); 125 void DataAvailable(base::RefCountedMemory* bytes);
157 126
158 // Returns a weak pointer to the job.
159 base::WeakPtr<URLRequestChromeJob> AsWeakPtr();
160
161 void set_mime_type(const std::string& mime_type) {
162 mime_type_ = mime_type;
163 }
164
165 void set_allow_caching(bool allow_caching) {
166 allow_caching_ = allow_caching;
167 }
168
169 void set_add_content_security_policy(bool add_content_security_policy) {
170 add_content_security_policy_ = add_content_security_policy;
171 }
172
173 void set_content_security_policy_object_source(
174 const std::string& data) {
175 content_security_policy_object_source_ = data;
176 }
177
178 void set_content_security_policy_script_source(
179 const std::string& data) {
180 content_security_policy_script_source_ = data;
181 }
182
183 void set_content_security_policy_child_source(
184 const std::string& data) {
185 content_security_policy_child_source_ = data;
186 }
187
188 void set_content_security_policy_style_source(
189 const std::string& data) {
190 content_security_policy_style_source_ = data;
191 }
192
193 void set_content_security_policy_image_source(
194 const std::string& data) {
195 content_security_policy_image_source_ = data;
196 }
197
198 void set_deny_xframe_options(bool deny_xframe_options) {
199 deny_xframe_options_ = deny_xframe_options;
200 }
201
202 void set_send_content_type_header(bool send_content_type_header) {
203 send_content_type_header_ = send_content_type_header;
204 }
205
206 void set_access_control_allow_origin(const std::string& value) {
207 access_control_allow_origin_ = value;
208 }
209
210 void set_is_gzipped(bool is_gzipped) { 127 void set_is_gzipped(bool is_gzipped) {
211 is_gzipped_ = is_gzipped; 128 is_gzipped_ = is_gzipped;
212 } 129 }
213 130
214 void SetReplacements(const ui::TemplateReplacements* replacements) { 131 void SetReplacements(const ui::TemplateReplacements* replacements) {
215 replacements_ = replacements; 132 replacements_ = replacements;
216 } 133 }
217 134
218 // Returns true when job was generated from an incognito profile.
219 bool is_incognito() const {
220 return is_incognito_;
221 }
222
223 private: 135 private:
224 ~URLRequestChromeJob() override; 136 ~URLRequestChromeJob() override;
225 137
226 // Helper for Start(), to let us start asynchronously. 138 // Helper for Start(), to let us start asynchronously.
227 // (This pattern is shared by most net::URLRequestJob implementations.) 139 // (This pattern is shared by most net::URLRequestJob implementations.)
228 void StartAsync(); 140 void StartAsync();
229 141
230 // Due to a race condition, DevTools relies on a legacy thread hop to the UI 142 // Due to a race condition, DevTools relies on a legacy thread hop to the UI
231 // thread before calling StartAsync. 143 // thread before calling StartAsync.
232 // TODO(caseq): Fix the race condition and remove this thread hop in 144 // TODO(caseq): Fix the race condition and remove this thread hop in
(...skipping 15 matching lines...) Expand all
248 // When DataAvailable() is called with a null argument, indicating an error, 160 // When DataAvailable() is called with a null argument, indicating an error,
249 // this is set accordingly to a code for ReadRawData() to return. 161 // this is set accordingly to a code for ReadRawData() to return.
250 net::Error data_available_status_; 162 net::Error data_available_status_;
251 163
252 // For async reads, we keep around a pointer to the buffer that 164 // For async reads, we keep around a pointer to the buffer that
253 // we're reading into. 165 // we're reading into.
254 scoped_refptr<net::IOBuffer> pending_buf_; 166 scoped_refptr<net::IOBuffer> pending_buf_;
255 int pending_buf_size_; 167 int pending_buf_size_;
256 std::string mime_type_; 168 std::string mime_type_;
257 169
258 // If true, set a header in the response to prevent it from being cached.
259 bool allow_caching_;
260
261 // If true, set the Content Security Policy (CSP) header.
262 bool add_content_security_policy_;
263
264 // These are used with the CSP.
265 std::string content_security_policy_script_source_;
266 std::string content_security_policy_object_source_;
267 std::string content_security_policy_child_source_;
268 std::string content_security_policy_style_source_;
269 std::string content_security_policy_image_source_;
270
271 // If true, sets the "X-Frame-Options: DENY" header.
272 bool deny_xframe_options_;
273
274 // If true, sets the "Content-Type: <mime-type>" header.
275 bool send_content_type_header_;
276
277 // If not empty, "Access-Control-Allow-Origin:" is set to the value of this
278 // string.
279 std::string access_control_allow_origin_;
280
281 // True when job is generated from an incognito profile.
282 const bool is_incognito_;
283
284 // True when gzip encoding should be used. NOTE: this requires the original 170 // True when gzip encoding should be used. NOTE: this requires the original
285 // resources in resources.pak use compress="gzip". 171 // resources in resources.pak use compress="gzip".
286 bool is_gzipped_; 172 bool is_gzipped_;
287 173
288 // Replacement dictionary for i18n. 174 // Replacement dictionary for i18n.
289 const ui::TemplateReplacements* replacements_; 175 const ui::TemplateReplacements* replacements_;
290 176
291 // The backend is owned by net::URLRequestContext and always outlives us. 177 // The backend is owned by net::URLRequestContext and always outlives us.
292 URLDataManagerBackend* const backend_; 178 URLDataManagerBackend* const backend_;
293 179
294 base::WeakPtrFactory<URLRequestChromeJob> weak_factory_; 180 base::WeakPtrFactory<URLRequestChromeJob> weak_factory_;
295 181
296 DISALLOW_COPY_AND_ASSIGN(URLRequestChromeJob); 182 DISALLOW_COPY_AND_ASSIGN(URLRequestChromeJob);
297 }; 183 };
298 184
299 URLRequestChromeJob::URLRequestChromeJob(net::URLRequest* request, 185 URLRequestChromeJob::URLRequestChromeJob(net::URLRequest* request,
300 net::NetworkDelegate* network_delegate, 186 net::NetworkDelegate* network_delegate,
301 URLDataManagerBackend* backend, 187 URLDataManagerBackend* backend)
302 bool is_incognito)
303 : net::URLRequestJob(request, network_delegate), 188 : net::URLRequestJob(request, network_delegate),
304 data_offset_(0), 189 data_offset_(0),
305 data_available_status_(net::OK), 190 data_available_status_(net::OK),
306 pending_buf_size_(0), 191 pending_buf_size_(0),
307 allow_caching_(true),
308 add_content_security_policy_(true),
309 deny_xframe_options_(true),
310 send_content_type_header_(false),
311 is_incognito_(is_incognito),
312 is_gzipped_(false), 192 is_gzipped_(false),
313 replacements_(nullptr), 193 replacements_(nullptr),
314 backend_(backend), 194 backend_(backend),
315 weak_factory_(this) { 195 weak_factory_(this) {
316 DCHECK(backend); 196 DCHECK(backend);
317 } 197 }
318 198
319 URLRequestChromeJob::~URLRequestChromeJob() { 199 URLRequestChromeJob::~URLRequestChromeJob() {
320 CHECK(!backend_->HasPendingJob(this)); 200 CHECK(!backend_->HasPendingJob(this));
321 } 201 }
(...skipping 30 matching lines...) Expand all
352 URLRequestJob::Kill(); 232 URLRequestJob::Kill();
353 } 233 }
354 234
355 bool URLRequestChromeJob::GetMimeType(std::string* mime_type) const { 235 bool URLRequestChromeJob::GetMimeType(std::string* mime_type) const {
356 *mime_type = mime_type_; 236 *mime_type = mime_type_;
357 return !mime_type_.empty(); 237 return !mime_type_.empty();
358 } 238 }
359 239
360 void URLRequestChromeJob::GetResponseInfo(net::HttpResponseInfo* info) { 240 void URLRequestChromeJob::GetResponseInfo(net::HttpResponseInfo* info) {
361 DCHECK(!info->headers.get()); 241 DCHECK(!info->headers.get());
362 // Set the headers so that requests serviced by ChromeURLDataManager return a 242 URLDataSourceImpl* source = backend_->GetDataSourceFromURL(request()->url());
363 // status code of 200. Without this they return a 0, which makes the status 243 std::string path;
364 // indistiguishable from other error types. Instant relies on getting a 200. 244 URLDataManagerBackend::URLToRequestPath(request()->url(), &path);
365 info->headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK"); 245 info->headers = URLDataManagerBackend::GetHeaders(
366 246 source, path, GetOriginHeaderValue(request()));
367 // Determine the least-privileged content security policy header, if any,
368 // that is compatible with a given WebUI URL, and append it to the existing
369 // response headers.
370 if (add_content_security_policy_) {
371 std::string base = kChromeURLContentSecurityPolicyHeaderBase;
372 base.append(content_security_policy_script_source_);
373 base.append(content_security_policy_object_source_);
374 base.append(content_security_policy_child_source_);
375 base.append(content_security_policy_style_source_);
376 base.append(content_security_policy_image_source_);
377 info->headers->AddHeader(base);
378 }
379
380 if (deny_xframe_options_)
381 info->headers->AddHeader(kChromeURLXFrameOptionsHeader);
382
383 if (!allow_caching_)
384 info->headers->AddHeader("Cache-Control: no-cache");
385
386 if (send_content_type_header_ && !mime_type_.empty()) {
387 std::string content_type =
388 base::StringPrintf("%s:%s", net::HttpRequestHeaders::kContentType,
389 mime_type_.c_str());
390 info->headers->AddHeader(content_type);
391 }
392
393 if (!access_control_allow_origin_.empty()) {
394 info->headers->AddHeader("Access-Control-Allow-Origin: " +
395 access_control_allow_origin_);
396 info->headers->AddHeader("Vary: Origin");
397 }
398
399 if (is_gzipped_) 247 if (is_gzipped_)
400 info->headers->AddHeader("Content-Encoding: gzip"); 248 info->headers->AddHeader("Content-Encoding: gzip");
401 } 249 }
402 250
403 std::unique_ptr<net::SourceStream> URLRequestChromeJob::SetUpSourceStream() { 251 std::unique_ptr<net::SourceStream> URLRequestChromeJob::SetUpSourceStream() {
404 std::unique_ptr<net::SourceStream> source_stream = 252 std::unique_ptr<net::SourceStream> source_stream =
405 net::URLRequestJob::SetUpSourceStream(); 253 net::URLRequestJob::SetUpSourceStream();
406 254
407 if (is_gzipped_) { 255 if (is_gzipped_) {
408 source_stream = net::GzipSourceStream::Create(std::move(source_stream), 256 source_stream = net::GzipSourceStream::Create(std::move(source_stream),
409 net::SourceStream::TYPE_GZIP); 257 net::SourceStream::TYPE_GZIP);
410 } 258 }
411 259
412 if (replacements_) { 260 if (replacements_) {
413 source_stream = content::I18nSourceStream::Create( 261 source_stream = I18nSourceStream::Create(
414 std::move(source_stream), net::SourceStream::TYPE_NONE, replacements_); 262 std::move(source_stream), net::SourceStream::TYPE_NONE, replacements_);
415 } 263 }
416 264
417 return source_stream; 265 return source_stream;
418 } 266 }
419 267
420 void URLRequestChromeJob::MimeTypeAvailable(const std::string& mime_type) { 268 void URLRequestChromeJob::MimeTypeAvailable(const std::string& mime_type) {
421 set_mime_type(mime_type); 269 mime_type_ = mime_type;
422 NotifyHeadersComplete(); 270 NotifyHeadersComplete();
423 } 271 }
424 272
425 void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) { 273 void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) {
426 TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this); 274 TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this);
427 DCHECK(!data_); 275 DCHECK(!data_);
428 276
429 // All further requests will be satisfied from the passed-in data. 277 // All further requests will be satisfied from the passed-in data.
430 data_ = bytes; 278 data_ = bytes;
431 if (!bytes) 279 if (!bytes)
432 data_available_status_ = net::ERR_FAILED; 280 data_available_status_ = net::ERR_FAILED;
433 281
434 if (pending_buf_) { 282 if (pending_buf_) {
435 // The request has already been marked async. 283 // The request has already been marked async.
436 int result = bytes ? PostReadTask(pending_buf_, pending_buf_size_) 284 int result = bytes ? PostReadTask(pending_buf_, pending_buf_size_)
437 : data_available_status_; 285 : data_available_status_;
438 pending_buf_ = nullptr; 286 pending_buf_ = nullptr;
439 if (result != net::ERR_IO_PENDING) 287 if (result != net::ERR_IO_PENDING)
440 ReadRawDataComplete(result); 288 ReadRawDataComplete(result);
441 } 289 }
442 } 290 }
443 291
444 base::WeakPtr<URLRequestChromeJob> URLRequestChromeJob::AsWeakPtr() {
445 return weak_factory_.GetWeakPtr();
446 }
447
448 int URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size) { 292 int URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
449 DCHECK(!pending_buf_.get()); 293 DCHECK(!pending_buf_.get());
450 294
451 // Handle the cases when DataAvailable() has already been called. 295 // Handle the cases when DataAvailable() has already been called.
452 if (data_available_status_ != net::OK) 296 if (data_available_status_ != net::OK)
453 return data_available_status_; 297 return data_available_status_;
454 if (data_) 298 if (data_)
455 return PostReadTask(buf, buf_size); 299 return PostReadTask(buf, buf_size);
456 300
457 // DataAvailable() has not been called yet. Mark the request as async. 301 // DataAvailable() has not been called yet. Mark the request as async.
(...skipping 12 matching lines...) Expand all
470 if (buf_size > remaining) 314 if (buf_size > remaining)
471 buf_size = remaining; 315 buf_size = remaining;
472 316
473 if (buf_size == 0) 317 if (buf_size == 0)
474 return 0; 318 return 0;
475 319
476 base::PostTaskWithTraitsAndReply( 320 base::PostTaskWithTraitsAndReply(
477 FROM_HERE, {base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, 321 FROM_HERE, {base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
478 base::Bind(&CopyData, base::RetainedRef(buf), buf_size, data_, 322 base::Bind(&CopyData, base::RetainedRef(buf), buf_size, data_,
479 data_offset_), 323 data_offset_),
480 base::Bind(&URLRequestChromeJob::ReadRawDataComplete, AsWeakPtr(), 324 base::Bind(&URLRequestChromeJob::ReadRawDataComplete,
481 buf_size)); 325 weak_factory_.GetWeakPtr(), buf_size));
482 data_offset_ += buf_size; 326 data_offset_ += buf_size;
483 327
484 return net::ERR_IO_PENDING; 328 return net::ERR_IO_PENDING;
485 } 329 }
486 330
487 void URLRequestChromeJob::DelayStartForDevTools( 331 void URLRequestChromeJob::DelayStartForDevTools(
488 const base::WeakPtr<URLRequestChromeJob>& job) { 332 const base::WeakPtr<URLRequestChromeJob>& job) {
489 BrowserThread::PostTask( 333 BrowserThread::PostTask(
490 BrowserThread::IO, 334 BrowserThread::IO,
491 FROM_HERE, 335 FROM_HERE,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 if (error_code == net_error_code) 368 if (error_code == net_error_code)
525 return true; 369 return true;
526 } 370 }
527 } 371 }
528 return false; 372 return false;
529 } 373 }
530 374
531 class ChromeProtocolHandler 375 class ChromeProtocolHandler
532 : public net::URLRequestJobFactory::ProtocolHandler { 376 : public net::URLRequestJobFactory::ProtocolHandler {
533 public: 377 public:
534 // |is_incognito| should be set for incognito profiles.
535 ChromeProtocolHandler(ResourceContext* resource_context, 378 ChromeProtocolHandler(ResourceContext* resource_context,
536 bool is_incognito,
537 ChromeBlobStorageContext* blob_storage_context) 379 ChromeBlobStorageContext* blob_storage_context)
538 : resource_context_(resource_context), 380 : resource_context_(resource_context),
539 is_incognito_(is_incognito),
540 blob_storage_context_(blob_storage_context) {} 381 blob_storage_context_(blob_storage_context) {}
541 ~ChromeProtocolHandler() override {} 382 ~ChromeProtocolHandler() override {}
542 383
543 net::URLRequestJob* MaybeCreateJob( 384 net::URLRequestJob* MaybeCreateJob(
544 net::URLRequest* request, 385 net::URLRequest* request,
545 net::NetworkDelegate* network_delegate) const override { 386 net::NetworkDelegate* network_delegate) const override {
546 DCHECK(request); 387 DCHECK(request);
547 388
548 // Check for chrome://view-http-cache/*, which uses its own job type. 389 // Check for chrome://view-http-cache/*, which uses its own job type.
549 if (ViewHttpCacheJobFactory::IsSupportedURL(request->url())) 390 if (ViewHttpCacheJobFactory::IsSupportedURL(request->url()))
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 // Check for chrome://dino which is an alias for chrome://network-error/-106 424 // Check for chrome://dino which is an alias for chrome://network-error/-106
584 if (request->url().SchemeIs(kChromeUIScheme) && 425 if (request->url().SchemeIs(kChromeUIScheme) &&
585 request->url().host() == kChromeUIDinoHost) { 426 request->url().host() == kChromeUIDinoHost) {
586 return new net::URLRequestErrorJob(request, network_delegate, 427 return new net::URLRequestErrorJob(request, network_delegate,
587 net::Error::ERR_INTERNET_DISCONNECTED); 428 net::Error::ERR_INTERNET_DISCONNECTED);
588 } 429 }
589 430
590 // Fall back to using a custom handler 431 // Fall back to using a custom handler
591 return new URLRequestChromeJob( 432 return new URLRequestChromeJob(
592 request, network_delegate, 433 request, network_delegate,
593 GetURLDataManagerForResourceContext(resource_context_), is_incognito_); 434 GetURLDataManagerForResourceContext(resource_context_));
594 } 435 }
595 436
596 bool IsSafeRedirectTarget(const GURL& location) const override { 437 bool IsSafeRedirectTarget(const GURL& location) const override {
597 return false; 438 return false;
598 } 439 }
599 440
600 private: 441 private:
601 // These members are owned by ProfileIOData, which owns this ProtocolHandler. 442 // These members are owned by ProfileIOData, which owns this ProtocolHandler.
602 ResourceContext* const resource_context_; 443 ResourceContext* const resource_context_;
603 444
604 // True when generated from an incognito profile.
605 const bool is_incognito_;
606 ChromeBlobStorageContext* blob_storage_context_; 445 ChromeBlobStorageContext* blob_storage_context_;
607 446
608 DISALLOW_COPY_AND_ASSIGN(ChromeProtocolHandler); 447 DISALLOW_COPY_AND_ASSIGN(ChromeProtocolHandler);
609 }; 448 };
610 449
611 } // namespace 450 } // namespace
612 451
613 URLDataManagerBackend::URLDataManagerBackend() 452 URLDataManagerBackend::URLDataManagerBackend()
614 : next_request_id_(0) { 453 : next_request_id_(0) {
615 URLDataSource* shared_source = new SharedResourcesDataSource(); 454 URLDataSource* shared_source = new SharedResourcesDataSource();
616 URLDataSourceImpl* source_impl = 455 URLDataSourceImpl* source_impl =
617 new URLDataSourceImpl(shared_source->GetSource(), shared_source); 456 new URLDataSourceImpl(shared_source->GetSource(), shared_source);
618 AddDataSource(source_impl); 457 AddDataSource(source_impl);
619 } 458 }
620 459
621 URLDataManagerBackend::~URLDataManagerBackend() { 460 URLDataManagerBackend::~URLDataManagerBackend() {
622 for (const auto& i : data_sources_) 461 for (const auto& i : data_sources_)
623 i.second->backend_ = nullptr; 462 i.second->backend_ = nullptr;
624 data_sources_.clear(); 463 data_sources_.clear();
625 } 464 }
626 465
627 // static 466 // static
628 std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler> 467 std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
629 URLDataManagerBackend::CreateProtocolHandler( 468 URLDataManagerBackend::CreateProtocolHandler(
630 ResourceContext* resource_context, 469 ResourceContext* resource_context,
631 bool is_incognito,
632 ChromeBlobStorageContext* blob_storage_context) { 470 ChromeBlobStorageContext* blob_storage_context) {
633 DCHECK(resource_context); 471 DCHECK(resource_context);
634 return base::MakeUnique<ChromeProtocolHandler>(resource_context, is_incognito, 472 return base::MakeUnique<ChromeProtocolHandler>(resource_context,
635 blob_storage_context); 473 blob_storage_context);
636 } 474 }
637 475
638 void URLDataManagerBackend::AddDataSource( 476 void URLDataManagerBackend::AddDataSource(
639 URLDataSourceImpl* source) { 477 URLDataSourceImpl* source) {
640 DCHECK_CURRENTLY_ON(BrowserThread::IO); 478 DCHECK_CURRENTLY_ON(BrowserThread::IO);
641 DataSourceMap::iterator i = data_sources_.find(source->source_name()); 479 DataSourceMap::iterator i = data_sources_.find(source->source_name());
642 if (i != data_sources_.end()) { 480 if (i != data_sources_.end()) {
643 if (!source->source()->ShouldReplaceExistingSource()) 481 if (!source->source()->ShouldReplaceExistingSource())
644 return; 482 return;
(...skipping 20 matching lines...) Expand all
665 for (PendingRequestMap::const_iterator i = pending_requests_.begin(); 503 for (PendingRequestMap::const_iterator i = pending_requests_.begin();
666 i != pending_requests_.end(); ++i) { 504 i != pending_requests_.end(); ++i) {
667 if (i->second == job) 505 if (i->second == job)
668 return true; 506 return true;
669 } 507 }
670 return false; 508 return false;
671 } 509 }
672 510
673 bool URLDataManagerBackend::StartRequest(const net::URLRequest* request, 511 bool URLDataManagerBackend::StartRequest(const net::URLRequest* request,
674 URLRequestChromeJob* job) { 512 URLRequestChromeJob* job) {
513 // NOTE: this duplicates code in web_ui_url_loader_factory.cc's URLLoaderImpl.
675 if (!CheckURLIsValid(request->url())) 514 if (!CheckURLIsValid(request->url()))
676 return false; 515 return false;
677 516
678 URLDataSourceImpl* source = GetDataSourceFromURL(request->url()); 517 URLDataSourceImpl* source = GetDataSourceFromURL(request->url());
679 if (!source) 518 if (!source)
680 return false; 519 return false;
681 520
682 const content::ResourceRequestInfo* info = 521 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
683 content::ResourceRequestInfo::ForRequest(request);
684 if (!source->source()->ShouldServiceRequest( 522 if (!source->source()->ShouldServiceRequest(
685 request->url(), info ? info->GetContext() : nullptr, 523 request->url(), info ? info->GetContext() : nullptr,
686 info ? info->GetChildID() : -1)) { 524 info ? info->GetChildID() : -1)) {
687 return false; 525 return false;
688 } 526 }
689 527
690 std::string path; 528 std::string path;
691 URLToRequestPath(request->url(), &path); 529 URLToRequestPath(request->url(), &path);
692 530
693 // Save this request so we know where to send the data. 531 // Save this request so we know where to send the data.
694 RequestID request_id = next_request_id_++; 532 RequestID request_id = next_request_id_++;
695 pending_requests_.insert(std::make_pair(request_id, job)); 533 pending_requests_.insert(std::make_pair(request_id, job));
696 534
697 job->set_allow_caching(source->source()->AllowCaching());
698 job->set_add_content_security_policy(
699 source->source()->ShouldAddContentSecurityPolicy());
700 job->set_content_security_policy_script_source(
701 source->source()->GetContentSecurityPolicyScriptSrc());
702 job->set_content_security_policy_object_source(
703 source->source()->GetContentSecurityPolicyObjectSrc());
704 job->set_content_security_policy_child_source(
705 source->source()->GetContentSecurityPolicyChildSrc());
706 job->set_content_security_policy_style_source(
707 source->source()->GetContentSecurityPolicyStyleSrc());
708 job->set_content_security_policy_image_source(
709 source->source()->GetContentSecurityPolicyImgSrc());
710 job->set_deny_xframe_options(
711 source->source()->ShouldDenyXFrameOptions());
712 job->set_send_content_type_header(
713 source->source()->ShouldServeMimeTypeAsContentTypeHeader());
714 job->set_is_gzipped(source->source()->IsGzipped(path)); 535 job->set_is_gzipped(source->source()->IsGzipped(path));
715 536
716 // TODO(dschuyler): improve filtering of which resource to run template 537 // TODO(dschuyler): improve filtering of which resource to run template
717 // replacements upon. 538 // replacements upon.
718 std::string mime_type = source->source()->GetMimeType(path); 539 std::string mime_type = source->source()->GetMimeType(path);
719 if (mime_type == "text/html") 540 if (mime_type == "text/html")
720 job->SetReplacements(source->GetReplacements()); 541 job->SetReplacements(source->GetReplacements());
721 542
722 std::string origin = GetOriginHeaderValue(request);
723 if (!origin.empty()) {
724 std::string header =
725 source->source()->GetAccessControlAllowOriginForOrigin(origin);
726 DCHECK(header.empty() || header == origin || header == "*" ||
727 header == "null");
728 job->set_access_control_allow_origin(header);
729 }
730
731 // Also notifies that the headers are complete. 543 // Also notifies that the headers are complete.
732 job->MimeTypeAvailable(mime_type); 544 job->MimeTypeAvailable(mime_type);
733 545
734 // Look up additional request info to pass down. 546 // Look up additional request info to pass down.
735 ResourceRequestInfo::WebContentsGetter wc_getter; 547 ResourceRequestInfo::WebContentsGetter wc_getter;
736 if (info) 548 if (info)
737 wc_getter = info->GetWebContentsGetterForRequest(); 549 wc_getter = info->GetWebContentsGetterForRequest();
738 550
739 // Forward along the request to the data source. 551 // Forward along the request to the data source.
740 scoped_refptr<base::SingleThreadTaskRunner> target_runner = 552 scoped_refptr<base::SingleThreadTaskRunner> target_runner =
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
803 base::RefCountedMemory* bytes) { 615 base::RefCountedMemory* bytes) {
804 // Forward this data on to the pending net::URLRequest, if it exists. 616 // Forward this data on to the pending net::URLRequest, if it exists.
805 PendingRequestMap::iterator i = pending_requests_.find(request_id); 617 PendingRequestMap::iterator i = pending_requests_.find(request_id);
806 if (i != pending_requests_.end()) { 618 if (i != pending_requests_.end()) {
807 URLRequestChromeJob* job = i->second; 619 URLRequestChromeJob* job = i->second;
808 pending_requests_.erase(i); 620 pending_requests_.erase(i);
809 job->DataAvailable(bytes); 621 job->DataAvailable(bytes);
810 } 622 }
811 } 623 }
812 624
625 scoped_refptr<net::HttpResponseHeaders> URLDataManagerBackend::GetHeaders(
626 URLDataSourceImpl* source_impl,
627 const std::string& path,
628 const std::string& origin) {
629 // Set the headers so that requests serviced by ChromeURLDataManager return a
630 // status code of 200. Without this they return a 0, which makes the status
631 // indistiguishable from other error types. Instant relies on getting a 200.
632 scoped_refptr<net::HttpResponseHeaders> headers(
633 new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
634 if (!source_impl)
635 return headers;
636
637 URLDataSource* source = source_impl->source();
638 // Determine the least-privileged content security policy header, if any,
639 // that is compatible with a given WebUI URL, and append it to the existing
640 // response headers.
641 if (source->ShouldAddContentSecurityPolicy()) {
642 std::string base = kChromeURLContentSecurityPolicyHeaderBase;
643 base.append(source->GetContentSecurityPolicyScriptSrc());
644 base.append(source->GetContentSecurityPolicyObjectSrc());
645 base.append(source->GetContentSecurityPolicyChildSrc());
646 base.append(source->GetContentSecurityPolicyStyleSrc());
647 base.append(source->GetContentSecurityPolicyImgSrc());
648 headers->AddHeader(base);
649 }
650
651 if (source->ShouldDenyXFrameOptions())
652 headers->AddHeader(kChromeURLXFrameOptionsHeader);
653
654 if (!source->AllowCaching())
655 headers->AddHeader("Cache-Control: no-cache");
656
657 std::string mime_type = source->GetMimeType(path);
658 if (source->ShouldServeMimeTypeAsContentTypeHeader() && !mime_type.empty()) {
659 std::string content_type = base::StringPrintf(
660 "%s:%s", net::HttpRequestHeaders::kContentType, mime_type.c_str());
661 headers->AddHeader(content_type);
662 }
663
664 if (!origin.empty()) {
665 std::string header = source->GetAccessControlAllowOriginForOrigin(origin);
666 DCHECK(header.empty() || header == origin || header == "*" ||
667 header == "null");
668 if (!header.empty()) {
669 headers->AddHeader("Access-Control-Allow-Origin: " + header);
670 headers->AddHeader("Vary: Origin");
671 }
672 }
673
674 return headers;
675 }
676
677 bool URLDataManagerBackend::CheckURLIsValid(const GURL& url) {
678 std::vector<std::string> additional_schemes;
679 DCHECK(url.SchemeIs(kChromeDevToolsScheme) || url.SchemeIs(kChromeUIScheme) ||
680 (GetContentClient()->browser()->GetAdditionalWebUISchemes(
681 &additional_schemes),
682 SchemeIsInSchemes(url.scheme(), additional_schemes)));
683
684 if (!url.is_valid()) {
685 NOTREACHED();
686 return false;
687 }
688
689 return true;
690 }
691
692 void URLDataManagerBackend::URLToRequestPath(const GURL& url,
693 std::string* path) {
694 const std::string& spec = url.possibly_invalid_spec();
695 const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
696 // + 1 to skip the slash at the beginning of the path.
697 int offset = parsed.CountCharactersBefore(url::Parsed::PATH, false) + 1;
698
699 if (offset < static_cast<int>(spec.size()))
700 path->assign(spec.substr(offset));
701 }
702
813 namespace { 703 namespace {
814 704
815 class DevToolsJobFactory 705 class DevToolsJobFactory
816 : public net::URLRequestJobFactory::ProtocolHandler { 706 : public net::URLRequestJobFactory::ProtocolHandler {
817 public: 707 public:
818 // |is_incognito| should be set for incognito profiles. 708 explicit DevToolsJobFactory(ResourceContext* resource_context);
819 DevToolsJobFactory(ResourceContext* resource_context, bool is_incognito);
820 ~DevToolsJobFactory() override; 709 ~DevToolsJobFactory() override;
821 710
822 net::URLRequestJob* MaybeCreateJob( 711 net::URLRequestJob* MaybeCreateJob(
823 net::URLRequest* request, 712 net::URLRequest* request,
824 net::NetworkDelegate* network_delegate) const override; 713 net::NetworkDelegate* network_delegate) const override;
825 714
826 private: 715 private:
827 // |resource_context_| and |network_delegate_| are owned by ProfileIOData, 716 // |resource_context_| and |network_delegate_| are owned by ProfileIOData,
828 // which owns this ProtocolHandler. 717 // which owns this ProtocolHandler.
829 ResourceContext* const resource_context_; 718 ResourceContext* const resource_context_;
830 719
831 // True when generated from an incognito profile.
832 const bool is_incognito_;
833
834 DISALLOW_COPY_AND_ASSIGN(DevToolsJobFactory); 720 DISALLOW_COPY_AND_ASSIGN(DevToolsJobFactory);
835 }; 721 };
836 722
837 DevToolsJobFactory::DevToolsJobFactory(ResourceContext* resource_context, 723 DevToolsJobFactory::DevToolsJobFactory(ResourceContext* resource_context)
838 bool is_incognito) 724 : resource_context_(resource_context) {
839 : resource_context_(resource_context), is_incognito_(is_incognito) {
840 DCHECK(resource_context_); 725 DCHECK(resource_context_);
841 } 726 }
842 727
843 DevToolsJobFactory::~DevToolsJobFactory() {} 728 DevToolsJobFactory::~DevToolsJobFactory() {}
844 729
845 net::URLRequestJob* 730 net::URLRequestJob*
846 DevToolsJobFactory::MaybeCreateJob( 731 DevToolsJobFactory::MaybeCreateJob(
847 net::URLRequest* request, net::NetworkDelegate* network_delegate) const { 732 net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
848 return new URLRequestChromeJob( 733 return new URLRequestChromeJob(
849 request, network_delegate, 734 request, network_delegate,
850 GetURLDataManagerForResourceContext(resource_context_), is_incognito_); 735 GetURLDataManagerForResourceContext(resource_context_));
851 } 736 }
852 737
853 } // namespace 738 } // namespace
854 739
855 net::URLRequestJobFactory::ProtocolHandler* CreateDevToolsProtocolHandler( 740 net::URLRequestJobFactory::ProtocolHandler* CreateDevToolsProtocolHandler(
856 ResourceContext* resource_context, 741 ResourceContext* resource_context) {
857 bool is_incognito) { 742 return new DevToolsJobFactory(resource_context);
858 return new DevToolsJobFactory(resource_context, is_incognito);
859 } 743 }
860 744
861 } // namespace content 745 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/webui/url_data_manager_backend.h ('k') | content/browser/webui/url_data_manager_backend_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698