| OLD | NEW |
| 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 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/debug/trace_event.h" | 13 #include "base/debug/trace_event.h" |
| 14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
| 16 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
| 17 #include "base/memory/ref_counted_memory.h" | 17 #include "base/memory/ref_counted_memory.h" |
| 18 #include "base/memory/weak_ptr.h" | 18 #include "base/memory/weak_ptr.h" |
| 19 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
| 20 #include "base/string_util.h" | 20 #include "base/string_util.h" |
| 21 #include "content/browser/fileapi/chrome_blob_storage_context.h" |
| 22 #include "content/browser/histogram_internals_request_job.h" |
| 23 #include "content/browser/net/view_blob_internals_job_factory.h" |
| 24 #include "content/browser/net/view_http_cache_job_factory.h" |
| 21 #include "content/browser/resource_context_impl.h" | 25 #include "content/browser/resource_context_impl.h" |
| 26 #include "content/browser/tcmalloc_internals_request_job.h" |
| 22 #include "content/browser/webui/shared_resources_data_source.h" | 27 #include "content/browser/webui/shared_resources_data_source.h" |
| 23 #include "content/browser/webui/url_data_source_impl.h" | 28 #include "content/browser/webui/url_data_source_impl.h" |
| 24 #include "content/public/browser/browser_thread.h" | 29 #include "content/public/browser/browser_thread.h" |
| 30 #include "content/public/browser/content_browser_client.h" |
| 25 #include "content/public/common/url_constants.h" | 31 #include "content/public/common/url_constants.h" |
| 26 #include "googleurl/src/url_util.h" | 32 #include "googleurl/src/url_util.h" |
| 27 #include "net/base/io_buffer.h" | 33 #include "net/base/io_buffer.h" |
| 28 #include "net/base/net_errors.h" | 34 #include "net/base/net_errors.h" |
| 29 #include "net/http/http_response_headers.h" | 35 #include "net/http/http_response_headers.h" |
| 30 #include "net/url_request/url_request.h" | 36 #include "net/url_request/url_request.h" |
| 31 #include "net/url_request/url_request_context.h" | 37 #include "net/url_request/url_request_context.h" |
| 32 #include "net/url_request/url_request_job.h" | 38 #include "net/url_request/url_request_job.h" |
| 33 #include "net/url_request/url_request_job_factory.h" | 39 #include "net/url_request/url_request_job_factory.h" |
| 40 #include "webkit/appcache/view_appcache_internals_job.h" |
| 41 |
| 42 using appcache::AppCacheService; |
| 34 | 43 |
| 35 namespace content { | 44 namespace content { |
| 36 | 45 |
| 37 namespace { | 46 namespace { |
| 38 | 47 |
| 39 // TODO(tsepez) remove unsafe-eval when bidichecker_packaged.js fixed. | 48 // TODO(tsepez) remove unsafe-eval when bidichecker_packaged.js fixed. |
| 40 const char kChromeURLContentSecurityPolicyHeaderBase[] = | 49 const char kChromeURLContentSecurityPolicyHeaderBase[] = |
| 41 "Content-Security-Policy: script-src chrome://resources " | 50 "Content-Security-Policy: script-src chrome://resources " |
| 42 "'self' 'unsafe-eval'; "; | 51 "'self' 'unsafe-eval'; "; |
| 43 | 52 |
| 44 const char kChromeURLXFrameOptionsHeader[] = "X-Frame-Options: DENY"; | 53 const char kChromeURLXFrameOptionsHeader[] = "X-Frame-Options: DENY"; |
| 45 | 54 |
| 55 bool SchemeIsInSchemes(const std::string& scheme, |
| 56 const std::vector<std::string>& schemes) { |
| 57 return std::find(schemes.begin(), schemes.end(), scheme) != schemes.end(); |
| 58 } |
| 59 |
| 46 // Parse a URL into the components used to resolve its request. |source_name| | 60 // Parse a URL into the components used to resolve its request. |source_name| |
| 47 // is the hostname and |path| is the remaining portion of the URL. | 61 // is the hostname and |path| is the remaining portion of the URL. |
| 48 void URLToRequest(const GURL& url, std::string* source_name, | 62 void URLToRequest(const GURL& url, std::string* source_name, |
| 49 std::string* path) { | 63 std::string* path) { |
| 50 DCHECK(url.SchemeIs(chrome::kChromeDevToolsScheme) || | 64 DCHECK(url.SchemeIs(chrome::kChromeDevToolsScheme) || |
| 51 url.SchemeIs(chrome::kChromeUIScheme)); | 65 url.SchemeIs(chrome::kChromeUIScheme) || |
| 66 SchemeIsInSchemes( |
| 67 url.scheme(), |
| 68 GetContentClient()->browser()->GetAdditionalWebUISchemes())); |
| 52 | 69 |
| 53 if (!url.is_valid()) { | 70 if (!url.is_valid()) { |
| 54 NOTREACHED(); | 71 NOTREACHED(); |
| 55 return; | 72 return; |
| 56 } | 73 } |
| 57 | 74 |
| 58 // Our input looks like: chrome://source_name/extra_bits?foo . | 75 // Our input looks like: chrome://source_name/extra_bits?foo . |
| 59 // So the url's "host" is our source, and everything after the host is | 76 // So the url's "host" is our source, and everything after the host is |
| 60 // the path. | 77 // the path. |
| 61 source_name->assign(url.host()); | 78 source_name->assign(url.host()); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 memcpy(buf->data(), data_->front() + data_offset_, buf_size); | 314 memcpy(buf->data(), data_->front() + data_offset_, buf_size); |
| 298 data_offset_ += buf_size; | 315 data_offset_ += buf_size; |
| 299 } | 316 } |
| 300 *bytes_read = buf_size; | 317 *bytes_read = buf_size; |
| 301 } | 318 } |
| 302 | 319 |
| 303 void URLRequestChromeJob::StartAsync() { | 320 void URLRequestChromeJob::StartAsync() { |
| 304 if (!request_) | 321 if (!request_) |
| 305 return; | 322 return; |
| 306 | 323 |
| 307 if (!backend_->StartRequest(request_->url(), this)) { | 324 if (!backend_->StartRequest(request_, this)) { |
| 308 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 325 NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 309 net::ERR_INVALID_URL)); | 326 net::ERR_INVALID_URL)); |
| 310 } | 327 } |
| 311 } | 328 } |
| 312 | 329 |
| 313 namespace { | 330 namespace { |
| 314 | 331 |
| 315 // Gets mime type for data that is available from |source| by |path|. | 332 // Gets mime type for data that is available from |source| by |path|. |
| 316 // After that, notifies |job| that mime type is available. This method | 333 // After that, notifies |job| that mime type is available. This method |
| 317 // should be called on the UI thread, but notification is performed on | 334 // should be called on the UI thread, but notification is performed on |
| 318 // the IO thread. | 335 // the IO thread. |
| 319 void GetMimeTypeOnUI(URLDataSourceImpl* source, | 336 void GetMimeTypeOnUI(URLDataSourceImpl* source, |
| 320 const std::string& path, | 337 const std::string& path, |
| 321 const base::WeakPtr<URLRequestChromeJob>& job) { | 338 const base::WeakPtr<URLRequestChromeJob>& job) { |
| 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 323 std::string mime_type = source->source()->GetMimeType(path); | 340 std::string mime_type = source->source()->GetMimeType(path); |
| 324 BrowserThread::PostTask( | 341 BrowserThread::PostTask( |
| 325 BrowserThread::IO, FROM_HERE, | 342 BrowserThread::IO, FROM_HERE, |
| 326 base::Bind(&URLRequestChromeJob::MimeTypeAvailable, job, mime_type)); | 343 base::Bind(&URLRequestChromeJob::MimeTypeAvailable, job, mime_type)); |
| 327 } | 344 } |
| 328 | 345 |
| 329 } // namespace | 346 } // namespace |
| 330 | 347 |
| 331 namespace { | 348 namespace { |
| 332 | 349 |
| 333 class ChromeProtocolHandler | 350 class ChromeProtocolHandler |
| 334 : public net::URLRequestJobFactory::ProtocolHandler { | 351 : public net::URLRequestJobFactory::ProtocolHandler { |
| 335 public: | 352 public: |
| 336 // |is_incognito| should be set for incognito profiles. | 353 // |is_incognito| should be set for incognito profiles. |
| 337 explicit ChromeProtocolHandler(content::ResourceContext* resource_context, | 354 ChromeProtocolHandler(ResourceContext* resource_context, |
| 338 bool is_incognito); | 355 bool is_incognito, |
| 339 virtual ~ChromeProtocolHandler(); | 356 AppCacheService* appcache_service, |
| 357 ChromeBlobStorageContext* blob_storage_context) |
| 358 : resource_context_(resource_context), |
| 359 is_incognito_(is_incognito), |
| 360 appcache_service_(appcache_service), |
| 361 blob_storage_context_(blob_storage_context) {} |
| 362 virtual ~ChromeProtocolHandler() {} |
| 340 | 363 |
| 341 virtual net::URLRequestJob* MaybeCreateJob( | 364 virtual net::URLRequestJob* MaybeCreateJob( |
| 342 net::URLRequest* request, | 365 net::URLRequest* request, |
| 343 net::NetworkDelegate* network_delegate) const OVERRIDE; | 366 net::NetworkDelegate* network_delegate) const OVERRIDE { |
| 367 DCHECK(request); |
| 368 |
| 369 // Check for chrome://view-http-cache/*, which uses its own job type. |
| 370 if (ViewHttpCacheJobFactory::IsSupportedURL(request->url())) |
| 371 return ViewHttpCacheJobFactory::CreateJobForRequest(request, |
| 372 network_delegate); |
| 373 |
| 374 // Next check for chrome://appcache-internals/, which uses its own job type. |
| 375 if (request->url().SchemeIs(chrome::kChromeUIScheme) && |
| 376 request->url().host() == chrome::kChromeUIAppCacheInternalsHost) { |
| 377 return appcache::ViewAppCacheInternalsJobFactory::CreateJobForRequest( |
| 378 request, network_delegate, appcache_service_); |
| 379 } |
| 380 |
| 381 // Next check for chrome://blob-internals/, which uses its own job type. |
| 382 if (ViewBlobInternalsJobFactory::IsSupportedURL(request->url())) { |
| 383 return ViewBlobInternalsJobFactory::CreateJobForRequest( |
| 384 request, network_delegate, blob_storage_context_->controller()); |
| 385 } |
| 386 |
| 387 #if defined(USE_TCMALLOC) |
| 388 // Next check for chrome://tcmalloc/, which uses its own job type. |
| 389 if (request->url().SchemeIs(chrome::kChromeUIScheme) && |
| 390 request->url().host() == chrome::kChromeUITcmallocHost) { |
| 391 return new TcmallocInternalsRequestJob(request, network_delegate); |
| 392 } |
| 393 #endif |
| 394 |
| 395 // Next check for chrome://histograms/, which uses its own job type. |
| 396 if (request->url().SchemeIs(chrome::kChromeUIScheme) && |
| 397 request->url().host() == chrome::kChromeUIHistogramHost) { |
| 398 return new HistogramInternalsRequestJob(request, network_delegate); |
| 399 } |
| 400 |
| 401 // Fall back to using a custom handler |
| 402 return new URLRequestChromeJob( |
| 403 request, network_delegate, |
| 404 GetURLDataManagerForResourceContext(resource_context_), is_incognito_); |
| 405 } |
| 344 | 406 |
| 345 private: | 407 private: |
| 346 // These members are owned by ProfileIOData, which owns this ProtocolHandler. | 408 // These members are owned by ProfileIOData, which owns this ProtocolHandler. |
| 347 content::ResourceContext* const resource_context_; | 409 content::ResourceContext* const resource_context_; |
| 348 | 410 |
| 349 // True when generated from an incognito profile. | 411 // True when generated from an incognito profile. |
| 350 const bool is_incognito_; | 412 const bool is_incognito_; |
| 413 AppCacheService* appcache_service_; |
| 414 ChromeBlobStorageContext* blob_storage_context_; |
| 351 | 415 |
| 352 DISALLOW_COPY_AND_ASSIGN(ChromeProtocolHandler); | 416 DISALLOW_COPY_AND_ASSIGN(ChromeProtocolHandler); |
| 353 }; | 417 }; |
| 354 | 418 |
| 355 ChromeProtocolHandler::ChromeProtocolHandler( | |
| 356 content::ResourceContext* resource_context, bool is_incognito) | |
| 357 : resource_context_(resource_context), is_incognito_(is_incognito) {} | |
| 358 | |
| 359 ChromeProtocolHandler::~ChromeProtocolHandler() {} | |
| 360 | |
| 361 net::URLRequestJob* ChromeProtocolHandler::MaybeCreateJob( | |
| 362 net::URLRequest* request, net::NetworkDelegate* network_delegate) const { | |
| 363 DCHECK(request); | |
| 364 | |
| 365 // Fall back to using a custom handler | |
| 366 return new URLRequestChromeJob( | |
| 367 request, network_delegate, | |
| 368 GetURLDataManagerForResourceContext(resource_context_), is_incognito_); | |
| 369 } | |
| 370 | |
| 371 } // namespace | 419 } // namespace |
| 372 | 420 |
| 373 URLDataManagerBackend::URLDataManagerBackend() | 421 URLDataManagerBackend::URLDataManagerBackend() |
| 374 : next_request_id_(0) { | 422 : next_request_id_(0) { |
| 375 URLDataSource* shared_source = new SharedResourcesDataSource(); | 423 URLDataSource* shared_source = new SharedResourcesDataSource(); |
| 376 URLDataSourceImpl* source_impl = | 424 URLDataSourceImpl* source_impl = |
| 377 new URLDataSourceImpl(shared_source->GetSource(), shared_source); | 425 new URLDataSourceImpl(shared_source->GetSource(), shared_source); |
| 378 AddDataSource(source_impl); | 426 AddDataSource(source_impl); |
| 379 } | 427 } |
| 380 | 428 |
| 381 URLDataManagerBackend::~URLDataManagerBackend() { | 429 URLDataManagerBackend::~URLDataManagerBackend() { |
| 382 for (DataSourceMap::iterator i = data_sources_.begin(); | 430 for (DataSourceMap::iterator i = data_sources_.begin(); |
| 383 i != data_sources_.end(); ++i) { | 431 i != data_sources_.end(); ++i) { |
| 384 i->second->backend_ = NULL; | 432 i->second->backend_ = NULL; |
| 385 } | 433 } |
| 386 data_sources_.clear(); | 434 data_sources_.clear(); |
| 387 } | 435 } |
| 388 | 436 |
| 389 // static | 437 // static |
| 390 net::URLRequestJobFactory::ProtocolHandler* | 438 net::URLRequestJobFactory::ProtocolHandler* |
| 391 URLDataManagerBackend::CreateProtocolHandler( | 439 URLDataManagerBackend::CreateProtocolHandler( |
| 392 content::ResourceContext* resource_context, bool is_incognito) { | 440 content::ResourceContext* resource_context, |
| 441 bool is_incognito, |
| 442 AppCacheService* appcache_service, |
| 443 ChromeBlobStorageContext* blob_storage_context) { |
| 393 DCHECK(resource_context); | 444 DCHECK(resource_context); |
| 394 return new ChromeProtocolHandler(resource_context, is_incognito); | 445 return new ChromeProtocolHandler( |
| 446 resource_context, is_incognito, appcache_service, blob_storage_context); |
| 395 } | 447 } |
| 396 | 448 |
| 397 void URLDataManagerBackend::AddDataSource( | 449 void URLDataManagerBackend::AddDataSource( |
| 398 URLDataSourceImpl* source) { | 450 URLDataSourceImpl* source) { |
| 399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 451 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 400 DataSourceMap::iterator i = data_sources_.find(source->source_name()); | 452 DataSourceMap::iterator i = data_sources_.find(source->source_name()); |
| 401 if (i != data_sources_.end()) { | 453 if (i != data_sources_.end()) { |
| 402 if (!source->source()->ShouldReplaceExistingSource()) | 454 if (!source->source()->ShouldReplaceExistingSource()) |
| 403 return; | 455 return; |
| 404 i->second->backend_ = NULL; | 456 i->second->backend_ = NULL; |
| 405 } | 457 } |
| 406 data_sources_[source->source_name()] = source; | 458 data_sources_[source->source_name()] = source; |
| 407 source->backend_ = this; | 459 source->backend_ = this; |
| 408 } | 460 } |
| 409 | 461 |
| 410 bool URLDataManagerBackend::HasPendingJob( | 462 bool URLDataManagerBackend::HasPendingJob( |
| 411 URLRequestChromeJob* job) const { | 463 URLRequestChromeJob* job) const { |
| 412 for (PendingRequestMap::const_iterator i = pending_requests_.begin(); | 464 for (PendingRequestMap::const_iterator i = pending_requests_.begin(); |
| 413 i != pending_requests_.end(); ++i) { | 465 i != pending_requests_.end(); ++i) { |
| 414 if (i->second == job) | 466 if (i->second == job) |
| 415 return true; | 467 return true; |
| 416 } | 468 } |
| 417 return false; | 469 return false; |
| 418 } | 470 } |
| 419 | 471 |
| 420 bool URLDataManagerBackend::StartRequest(const GURL& url, | 472 bool URLDataManagerBackend::StartRequest(const net::URLRequest* request, |
| 421 URLRequestChromeJob* job) { | 473 URLRequestChromeJob* job) { |
| 422 // Parse the URL into a request for a source and path. | 474 // Parse the URL into a request for a source and path. |
| 423 std::string source_name; | 475 std::string source_name; |
| 424 std::string path; | 476 std::string path; |
| 425 URLToRequest(url, &source_name, &path); | 477 URLToRequest(request->url(), &source_name, &path); |
| 426 | 478 |
| 427 // Look up the data source for the request. | 479 // Look up the data source for the request. |
| 428 DataSourceMap::iterator i = data_sources_.find(source_name); | 480 DataSourceMap::iterator i = data_sources_.find(source_name); |
| 429 if (i == data_sources_.end()) | 481 if (i == data_sources_.end()) |
| 430 return false; | 482 return false; |
| 431 | 483 |
| 432 URLDataSourceImpl* source = i->second; | 484 URLDataSourceImpl* source = i->second; |
| 433 | 485 |
| 486 if (!source->source()->ShouldServiceRequest(request)) |
| 487 return false; |
| 488 |
| 434 // Save this request so we know where to send the data. | 489 // Save this request so we know where to send the data. |
| 435 RequestID request_id = next_request_id_++; | 490 RequestID request_id = next_request_id_++; |
| 436 pending_requests_.insert(std::make_pair(request_id, job)); | 491 pending_requests_.insert(std::make_pair(request_id, job)); |
| 437 | 492 |
| 438 job->set_allow_caching(source->source()->AllowCaching()); | 493 job->set_allow_caching(source->source()->AllowCaching()); |
| 439 job->set_add_content_security_policy( | 494 job->set_add_content_security_policy( |
| 440 source->source()->ShouldAddContentSecurityPolicy()); | 495 source->source()->ShouldAddContentSecurityPolicy()); |
| 441 job->set_content_security_policy_object_source( | 496 job->set_content_security_policy_object_source( |
| 442 source->source()->GetContentSecurityPolicyObjectSrc()); | 497 source->source()->GetContentSecurityPolicyObjectSrc()); |
| 443 job->set_content_security_policy_frame_source( | 498 job->set_content_security_policy_frame_source( |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 | 617 |
| 563 } // namespace | 618 } // namespace |
| 564 | 619 |
| 565 net::URLRequestJobFactory::ProtocolHandler* | 620 net::URLRequestJobFactory::ProtocolHandler* |
| 566 CreateDevToolsProtocolHandler(content::ResourceContext* resource_context, | 621 CreateDevToolsProtocolHandler(content::ResourceContext* resource_context, |
| 567 bool is_incognito) { | 622 bool is_incognito) { |
| 568 return new DevToolsJobFactory(resource_context, is_incognito); | 623 return new DevToolsJobFactory(resource_context, is_incognito); |
| 569 } | 624 } |
| 570 | 625 |
| 571 } // namespace content | 626 } // namespace content |
| OLD | NEW |