9e12864b322434bb056fe2ded4da622e21c6cda4
[platform/framework/web/crosswalk.git] / src / content / browser / webui / url_data_manager_backend.cc
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
3 // found in the LICENSE file.
4
5 #include "content/browser/webui/url_data_manager_backend.h"
6
7 #include <set>
8
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/compiler_specific.h"
13 #include "base/debug/alias.h"
14 #include "base/debug/trace_event.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "content/browser/appcache/view_appcache_internals_job.h"
23 #include "content/browser/fileapi/chrome_blob_storage_context.h"
24 #include "content/browser/histogram_internals_request_job.h"
25 #include "content/browser/net/view_blob_internals_job_factory.h"
26 #include "content/browser/net/view_http_cache_job_factory.h"
27 #include "content/browser/resource_context_impl.h"
28 #include "content/browser/tcmalloc_internals_request_job.h"
29 #include "content/browser/webui/shared_resources_data_source.h"
30 #include "content/browser/webui/url_data_source_impl.h"
31 #include "content/public/browser/browser_context.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/resource_request_info.h"
36 #include "content/public/common/url_constants.h"
37 #include "net/base/io_buffer.h"
38 #include "net/base/net_errors.h"
39 #include "net/http/http_response_headers.h"
40 #include "net/http/http_status_code.h"
41 #include "net/url_request/url_request.h"
42 #include "net/url_request/url_request_context.h"
43 #include "net/url_request/url_request_job.h"
44 #include "net/url_request/url_request_job_factory.h"
45 #include "url/url_util.h"
46
47 namespace content {
48
49 namespace {
50
51 // TODO(tsepez) remove unsafe-eval when bidichecker_packaged.js fixed.
52 const char kChromeURLContentSecurityPolicyHeaderBase[] =
53     "Content-Security-Policy: script-src chrome://resources "
54     "'self' 'unsafe-eval'; ";
55
56 const char kChromeURLXFrameOptionsHeader[] = "X-Frame-Options: DENY";
57
58 const int kNoRenderProcessId = -1;
59
60 bool SchemeIsInSchemes(const std::string& scheme,
61                        const std::vector<std::string>& schemes) {
62   return std::find(schemes.begin(), schemes.end(), scheme) != schemes.end();
63 }
64
65 // Returns whether |url| passes some sanity checks and is a valid GURL.
66 bool CheckURLIsValid(const GURL& url) {
67   std::vector<std::string> additional_schemes;
68   DCHECK(url.SchemeIs(kChromeDevToolsScheme) || url.SchemeIs(kChromeUIScheme) ||
69          (GetContentClient()->browser()->GetAdditionalWebUISchemes(
70               &additional_schemes),
71           SchemeIsInSchemes(url.scheme(), additional_schemes)));
72
73   if (!url.is_valid()) {
74     NOTREACHED();
75     return false;
76   }
77
78   return true;
79 }
80
81 // Parse |url| to get the path which will be used to resolve the request. The
82 // path is the remaining portion after the scheme and hostname.
83 void URLToRequestPath(const GURL& url, std::string* path) {
84   const std::string& spec = url.possibly_invalid_spec();
85   const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
86   // + 1 to skip the slash at the beginning of the path.
87   int offset = parsed.CountCharactersBefore(url::Parsed::PATH, false) + 1;
88
89   if (offset < static_cast<int>(spec.size()))
90     path->assign(spec.substr(offset));
91 }
92
93 // Returns a value of 'Origin:' header for the |request| if the header is set.
94 // Otherwise returns an empty string.
95 std::string GetOriginHeaderValue(const net::URLRequest* request) {
96   std::string result;
97   if (request->extra_request_headers().GetHeader(
98           net::HttpRequestHeaders::kOrigin, &result))
99     return result;
100   net::HttpRequestHeaders headers;
101   if (request->GetFullRequestHeaders(&headers))
102     headers.GetHeader(net::HttpRequestHeaders::kOrigin, &result);
103   return result;
104 }
105
106 }  // namespace
107
108 // URLRequestChromeJob is a net::URLRequestJob that manages running
109 // chrome-internal resource requests asynchronously.
110 // It hands off URL requests to ChromeURLDataManager, which asynchronously
111 // calls back once the data is available.
112 class URLRequestChromeJob : public net::URLRequestJob,
113                             public base::SupportsWeakPtr<URLRequestChromeJob> {
114  public:
115   // |is_incognito| set when job is generated from an incognito profile.
116   URLRequestChromeJob(net::URLRequest* request,
117                       net::NetworkDelegate* network_delegate,
118                       URLDataManagerBackend* backend,
119                       bool is_incognito);
120
121   // net::URLRequestJob implementation.
122   void Start() override;
123   void Kill() override;
124   bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
125   bool GetMimeType(std::string* mime_type) const override;
126   int GetResponseCode() const override;
127   void GetResponseInfo(net::HttpResponseInfo* info) override;
128
129   // Used to notify that the requested data's |mime_type| is ready.
130   void MimeTypeAvailable(const std::string& mime_type);
131
132   // Called by ChromeURLDataManager to notify us that the data blob is ready
133   // for us.
134   void DataAvailable(base::RefCountedMemory* bytes);
135
136   void set_mime_type(const std::string& mime_type) {
137     mime_type_ = mime_type;
138   }
139
140   void set_allow_caching(bool allow_caching) {
141     allow_caching_ = allow_caching;
142   }
143
144   void set_add_content_security_policy(bool add_content_security_policy) {
145     add_content_security_policy_ = add_content_security_policy;
146   }
147
148   void set_content_security_policy_object_source(
149       const std::string& data) {
150     content_security_policy_object_source_ = data;
151   }
152
153   void set_content_security_policy_frame_source(
154       const std::string& data) {
155     content_security_policy_frame_source_ = data;
156   }
157
158   void set_deny_xframe_options(bool deny_xframe_options) {
159     deny_xframe_options_ = deny_xframe_options;
160   }
161
162   void set_send_content_type_header(bool send_content_type_header) {
163     send_content_type_header_ = send_content_type_header;
164   }
165
166   void set_access_control_allow_origin(const std::string& value) {
167     access_control_allow_origin_ = value;
168   }
169
170   // Returns true when job was generated from an incognito profile.
171   bool is_incognito() const {
172     return is_incognito_;
173   }
174
175  private:
176   ~URLRequestChromeJob() override;
177
178   // Helper for Start(), to let us start asynchronously.
179   // (This pattern is shared by most net::URLRequestJob implementations.)
180   void StartAsync(bool allowed);
181
182   // Called on the UI thread to check if this request is allowed.
183   static void CheckStoragePartitionMatches(
184       int render_process_id,
185       const GURL& url,
186       const base::WeakPtr<URLRequestChromeJob>& job);
187
188   // Do the actual copy from data_ (the data we're serving) into |buf|.
189   // Separate from ReadRawData so we can handle async I/O.
190   void CompleteRead(net::IOBuffer* buf, int buf_size, int* bytes_read);
191
192   // The actual data we're serving.  NULL until it's been fetched.
193   scoped_refptr<base::RefCountedMemory> data_;
194   // The current offset into the data that we're handing off to our
195   // callers via the Read interfaces.
196   int data_offset_;
197
198   // For async reads, we keep around a pointer to the buffer that
199   // we're reading into.
200   scoped_refptr<net::IOBuffer> pending_buf_;
201   int pending_buf_size_;
202   std::string mime_type_;
203
204   // If true, set a header in the response to prevent it from being cached.
205   bool allow_caching_;
206
207   // If true, set the Content Security Policy (CSP) header.
208   bool add_content_security_policy_;
209
210   // These are used with the CSP.
211   std::string content_security_policy_object_source_;
212   std::string content_security_policy_frame_source_;
213
214   // If true, sets  the "X-Frame-Options: DENY" header.
215   bool deny_xframe_options_;
216
217   // If true, sets the "Content-Type: <mime-type>" header.
218   bool send_content_type_header_;
219
220   // If not empty, "Access-Control-Allow-Origin:" is set to the value of this
221   // string.
222   std::string access_control_allow_origin_;
223
224   // True when job is generated from an incognito profile.
225   const bool is_incognito_;
226
227   // The backend is owned by net::URLRequestContext and always outlives us.
228   URLDataManagerBackend* backend_;
229
230   base::WeakPtrFactory<URLRequestChromeJob> weak_factory_;
231
232   DISALLOW_COPY_AND_ASSIGN(URLRequestChromeJob);
233 };
234
235 URLRequestChromeJob::URLRequestChromeJob(net::URLRequest* request,
236                                          net::NetworkDelegate* network_delegate,
237                                          URLDataManagerBackend* backend,
238                                          bool is_incognito)
239     : net::URLRequestJob(request, network_delegate),
240       data_offset_(0),
241       pending_buf_size_(0),
242       allow_caching_(true),
243       add_content_security_policy_(true),
244       content_security_policy_object_source_("object-src 'none';"),
245       content_security_policy_frame_source_("frame-src 'none';"),
246       deny_xframe_options_(true),
247       send_content_type_header_(false),
248       is_incognito_(is_incognito),
249       backend_(backend),
250       weak_factory_(this) {
251   DCHECK(backend);
252 }
253
254 URLRequestChromeJob::~URLRequestChromeJob() {
255   CHECK(!backend_->HasPendingJob(this));
256 }
257
258 void URLRequestChromeJob::Start() {
259   int render_process_id, unused;
260   bool is_renderer_request = ResourceRequestInfo::GetRenderFrameForRequest(
261       request_, &render_process_id, &unused);
262   if (!is_renderer_request)
263     render_process_id = kNoRenderProcessId;
264   BrowserThread::PostTask(
265       BrowserThread::UI,
266       FROM_HERE,
267       base::Bind(&URLRequestChromeJob::CheckStoragePartitionMatches,
268                  render_process_id, request_->url(), AsWeakPtr()));
269   TRACE_EVENT_ASYNC_BEGIN1("browser", "DataManager:Request", this, "URL",
270       request_->url().possibly_invalid_spec());
271 }
272
273 void URLRequestChromeJob::Kill() {
274   backend_->RemoveRequest(this);
275 }
276
277 bool URLRequestChromeJob::GetMimeType(std::string* mime_type) const {
278   *mime_type = mime_type_;
279   return !mime_type_.empty();
280 }
281
282 int URLRequestChromeJob::GetResponseCode() const {
283   return net::HTTP_OK;
284 }
285
286 void URLRequestChromeJob::GetResponseInfo(net::HttpResponseInfo* info) {
287   DCHECK(!info->headers.get());
288   // Set the headers so that requests serviced by ChromeURLDataManager return a
289   // status code of 200. Without this they return a 0, which makes the status
290   // indistiguishable from other error types. Instant relies on getting a 200.
291   info->headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
292
293   // Determine the least-privileged content security policy header, if any,
294   // that is compatible with a given WebUI URL, and append it to the existing
295   // response headers.
296   if (add_content_security_policy_) {
297     std::string base = kChromeURLContentSecurityPolicyHeaderBase;
298     base.append(content_security_policy_object_source_);
299     base.append(content_security_policy_frame_source_);
300     info->headers->AddHeader(base);
301   }
302
303   if (deny_xframe_options_)
304     info->headers->AddHeader(kChromeURLXFrameOptionsHeader);
305
306   if (!allow_caching_)
307     info->headers->AddHeader("Cache-Control: no-cache");
308
309   if (send_content_type_header_ && !mime_type_.empty()) {
310     std::string content_type =
311         base::StringPrintf("%s:%s", net::HttpRequestHeaders::kContentType,
312                            mime_type_.c_str());
313     info->headers->AddHeader(content_type);
314   }
315
316   if (!access_control_allow_origin_.empty()) {
317     info->headers->AddHeader("Access-Control-Allow-Origin: " +
318                              access_control_allow_origin_);
319     info->headers->AddHeader("Vary: Origin");
320   }
321 }
322
323 void URLRequestChromeJob::MimeTypeAvailable(const std::string& mime_type) {
324   set_mime_type(mime_type);
325   NotifyHeadersComplete();
326 }
327
328 void URLRequestChromeJob::DataAvailable(base::RefCountedMemory* bytes) {
329   TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this);
330   if (bytes) {
331     // The request completed, and we have all the data.
332     // Clear any IO pending status.
333     SetStatus(net::URLRequestStatus());
334
335     data_ = bytes;
336     int bytes_read;
337     if (pending_buf_.get()) {
338       CHECK(pending_buf_->data());
339       CompleteRead(pending_buf_.get(), pending_buf_size_, &bytes_read);
340       pending_buf_ = NULL;
341       NotifyReadComplete(bytes_read);
342     }
343   } else {
344     // The request failed.
345     NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
346                                      net::ERR_FAILED));
347   }
348 }
349
350 bool URLRequestChromeJob::ReadRawData(net::IOBuffer* buf, int buf_size,
351                                       int* bytes_read) {
352   if (!data_.get()) {
353     SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
354     DCHECK(!pending_buf_.get());
355     CHECK(buf->data());
356     pending_buf_ = buf;
357     pending_buf_size_ = buf_size;
358     return false;  // Tell the caller we're still waiting for data.
359   }
360
361   // Otherwise, the data is available.
362   CompleteRead(buf, buf_size, bytes_read);
363   return true;
364 }
365
366 void URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size,
367                                        int* bytes_read) {
368   // http://crbug.com/373841
369   char url_buf[128];
370   base::strlcpy(url_buf, request_->url().spec().c_str(), arraysize(url_buf));
371   base::debug::Alias(url_buf);
372
373   int remaining = static_cast<int>(data_->size()) - data_offset_;
374   if (buf_size > remaining)
375     buf_size = remaining;
376   if (buf_size > 0) {
377     memcpy(buf->data(), data_->front() + data_offset_, buf_size);
378     data_offset_ += buf_size;
379   }
380   *bytes_read = buf_size;
381 }
382
383 void URLRequestChromeJob::CheckStoragePartitionMatches(
384     int render_process_id,
385     const GURL& url,
386     const base::WeakPtr<URLRequestChromeJob>& job) {
387   // The embedder could put some webui pages in separate storage partition.
388   // RenderProcessHostImpl::IsSuitableHost would guard against top level pages
389   // being in the same process. We do an extra check to guard against an
390   // exploited renderer pretending to add them as a subframe. We skip this check
391   // for resources.
392   bool allowed = false;
393   std::vector<std::string> hosts;
394   GetContentClient()->
395       browser()->GetAdditionalWebUIHostsToIgnoreParititionCheck(&hosts);
396   if (url.SchemeIs(kChromeUIScheme) &&
397       (url.SchemeIs(kChromeUIScheme) ||
398        std::find(hosts.begin(), hosts.end(), url.host()) != hosts.end())) {
399     allowed = true;
400   } else if (render_process_id == kNoRenderProcessId) {
401     // Request was not issued by renderer.
402     allowed = true;
403   } else {
404     RenderProcessHost* process = RenderProcessHost::FromID(render_process_id);
405     if (process) {
406       StoragePartition* partition = BrowserContext::GetStoragePartitionForSite(
407           process->GetBrowserContext(), url);
408       allowed = partition == process->GetStoragePartition();
409     }
410   }
411
412   BrowserThread::PostTask(
413       BrowserThread::IO,
414       FROM_HERE,
415       base::Bind(&URLRequestChromeJob::StartAsync, job, allowed));
416 }
417
418 void URLRequestChromeJob::StartAsync(bool allowed) {
419   if (!request_)
420     return;
421
422   if (!allowed || !backend_->StartRequest(request_, this)) {
423     NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
424                                            net::ERR_INVALID_URL));
425   }
426 }
427
428 namespace {
429
430 // Gets mime type for data that is available from |source| by |path|.
431 // After that, notifies |job| that mime type is available. This method
432 // should be called on the UI thread, but notification is performed on
433 // the IO thread.
434 void GetMimeTypeOnUI(URLDataSourceImpl* source,
435                      const std::string& path,
436                      const base::WeakPtr<URLRequestChromeJob>& job) {
437   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
438   std::string mime_type = source->source()->GetMimeType(path);
439   BrowserThread::PostTask(
440       BrowserThread::IO, FROM_HERE,
441       base::Bind(&URLRequestChromeJob::MimeTypeAvailable, job, mime_type));
442 }
443
444 }  // namespace
445
446 namespace {
447
448 class ChromeProtocolHandler
449     : public net::URLRequestJobFactory::ProtocolHandler {
450  public:
451   // |is_incognito| should be set for incognito profiles.
452   ChromeProtocolHandler(ResourceContext* resource_context,
453                         bool is_incognito,
454                         AppCacheServiceImpl* appcache_service,
455                         ChromeBlobStorageContext* blob_storage_context)
456       : resource_context_(resource_context),
457         is_incognito_(is_incognito),
458         appcache_service_(appcache_service),
459         blob_storage_context_(blob_storage_context) {}
460   ~ChromeProtocolHandler() override {}
461
462   net::URLRequestJob* MaybeCreateJob(
463       net::URLRequest* request,
464       net::NetworkDelegate* network_delegate) const override {
465     DCHECK(request);
466
467     // Check for chrome://view-http-cache/*, which uses its own job type.
468     if (ViewHttpCacheJobFactory::IsSupportedURL(request->url()))
469       return ViewHttpCacheJobFactory::CreateJobForRequest(request,
470                                                           network_delegate);
471
472     // Next check for chrome://appcache-internals/, which uses its own job type.
473     if (request->url().SchemeIs(kChromeUIScheme) &&
474         request->url().host() == kChromeUIAppCacheInternalsHost) {
475       return ViewAppCacheInternalsJobFactory::CreateJobForRequest(
476           request, network_delegate, appcache_service_);
477     }
478
479     // Next check for chrome://blob-internals/, which uses its own job type.
480     if (ViewBlobInternalsJobFactory::IsSupportedURL(request->url())) {
481       return ViewBlobInternalsJobFactory::CreateJobForRequest(
482           request, network_delegate, blob_storage_context_->context());
483     }
484
485 #if defined(USE_TCMALLOC)
486     // Next check for chrome://tcmalloc/, which uses its own job type.
487     if (request->url().SchemeIs(kChromeUIScheme) &&
488         request->url().host() == kChromeUITcmallocHost) {
489       return new TcmallocInternalsRequestJob(request, network_delegate);
490     }
491 #endif
492
493     // Next check for chrome://histograms/, which uses its own job type.
494     if (request->url().SchemeIs(kChromeUIScheme) &&
495         request->url().host() == kChromeUIHistogramHost) {
496       return new HistogramInternalsRequestJob(request, network_delegate);
497     }
498
499     // Fall back to using a custom handler
500     return new URLRequestChromeJob(
501         request, network_delegate,
502         GetURLDataManagerForResourceContext(resource_context_), is_incognito_);
503   }
504
505   bool IsSafeRedirectTarget(const GURL& location) const override {
506     return false;
507   }
508
509  private:
510   // These members are owned by ProfileIOData, which owns this ProtocolHandler.
511   content::ResourceContext* const resource_context_;
512
513   // True when generated from an incognito profile.
514   const bool is_incognito_;
515   AppCacheServiceImpl* appcache_service_;
516   ChromeBlobStorageContext* blob_storage_context_;
517
518   DISALLOW_COPY_AND_ASSIGN(ChromeProtocolHandler);
519 };
520
521 }  // namespace
522
523 URLDataManagerBackend::URLDataManagerBackend()
524     : next_request_id_(0) {
525   URLDataSource* shared_source = new SharedResourcesDataSource();
526   URLDataSourceImpl* source_impl =
527       new URLDataSourceImpl(shared_source->GetSource(), shared_source);
528   AddDataSource(source_impl);
529 }
530
531 URLDataManagerBackend::~URLDataManagerBackend() {
532   for (DataSourceMap::iterator i = data_sources_.begin();
533        i != data_sources_.end(); ++i) {
534     i->second->backend_ = NULL;
535   }
536   data_sources_.clear();
537 }
538
539 // static
540 net::URLRequestJobFactory::ProtocolHandler*
541 URLDataManagerBackend::CreateProtocolHandler(
542     content::ResourceContext* resource_context,
543     bool is_incognito,
544     AppCacheServiceImpl* appcache_service,
545     ChromeBlobStorageContext* blob_storage_context) {
546   DCHECK(resource_context);
547   return new ChromeProtocolHandler(
548       resource_context, is_incognito, appcache_service, blob_storage_context);
549 }
550
551 void URLDataManagerBackend::AddDataSource(
552     URLDataSourceImpl* source) {
553   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
554   DataSourceMap::iterator i = data_sources_.find(source->source_name());
555   if (i != data_sources_.end()) {
556     if (!source->source()->ShouldReplaceExistingSource())
557       return;
558     i->second->backend_ = NULL;
559   }
560   data_sources_[source->source_name()] = source;
561   source->backend_ = this;
562 }
563
564 bool URLDataManagerBackend::HasPendingJob(
565     URLRequestChromeJob* job) const {
566   for (PendingRequestMap::const_iterator i = pending_requests_.begin();
567        i != pending_requests_.end(); ++i) {
568     if (i->second == job)
569       return true;
570   }
571   return false;
572 }
573
574 bool URLDataManagerBackend::StartRequest(const net::URLRequest* request,
575                                          URLRequestChromeJob* job) {
576   if (!CheckURLIsValid(request->url()))
577     return false;
578
579   URLDataSourceImpl* source = GetDataSourceFromURL(request->url());
580   if (!source)
581     return false;
582
583   if (!source->source()->ShouldServiceRequest(request))
584     return false;
585
586   std::string path;
587   URLToRequestPath(request->url(), &path);
588   source->source()->WillServiceRequest(request, &path);
589
590   // Save this request so we know where to send the data.
591   RequestID request_id = next_request_id_++;
592   pending_requests_.insert(std::make_pair(request_id, job));
593
594   job->set_allow_caching(source->source()->AllowCaching());
595   job->set_add_content_security_policy(
596       source->source()->ShouldAddContentSecurityPolicy());
597   job->set_content_security_policy_object_source(
598       source->source()->GetContentSecurityPolicyObjectSrc());
599   job->set_content_security_policy_frame_source(
600       source->source()->GetContentSecurityPolicyFrameSrc());
601   job->set_deny_xframe_options(
602       source->source()->ShouldDenyXFrameOptions());
603   job->set_send_content_type_header(
604       source->source()->ShouldServeMimeTypeAsContentTypeHeader());
605
606   std::string origin = GetOriginHeaderValue(request);
607   if (!origin.empty()) {
608     std::string header =
609         source->source()->GetAccessControlAllowOriginForOrigin(origin);
610     DCHECK(header.empty() || header == origin || header == "*" ||
611            header == "null");
612     job->set_access_control_allow_origin(header);
613   }
614
615   // Look up additional request info to pass down.
616   int render_process_id = -1;
617   int render_frame_id = -1;
618   ResourceRequestInfo::GetRenderFrameForRequest(request,
619                                                 &render_process_id,
620                                                 &render_frame_id);
621
622   // Forward along the request to the data source.
623   base::MessageLoop* target_message_loop =
624       source->source()->MessageLoopForRequestPath(path);
625   if (!target_message_loop) {
626     job->MimeTypeAvailable(source->source()->GetMimeType(path));
627     // Eliminate potentially dangling pointer to avoid future use.
628     job = NULL;
629
630     // The DataSource is agnostic to which thread StartDataRequest is called
631     // on for this path.  Call directly into it from this thread, the IO
632     // thread.
633     source->source()->StartDataRequest(
634         path, render_process_id, render_frame_id,
635         base::Bind(&URLDataSourceImpl::SendResponse, source, request_id));
636   } else {
637     // URLRequestChromeJob should receive mime type before data. This
638     // is guaranteed because request for mime type is placed in the
639     // message loop before request for data. And correspondingly their
640     // replies are put on the IO thread in the same order.
641     target_message_loop->PostTask(
642         FROM_HERE,
643         base::Bind(&GetMimeTypeOnUI,
644                    scoped_refptr<URLDataSourceImpl>(source),
645                    path, job->AsWeakPtr()));
646
647     // The DataSource wants StartDataRequest to be called on a specific thread,
648     // usually the UI thread, for this path.
649     target_message_loop->PostTask(
650         FROM_HERE,
651         base::Bind(&URLDataManagerBackend::CallStartRequest,
652                    make_scoped_refptr(source), path, render_process_id,
653                    render_frame_id, request_id));
654   }
655   return true;
656 }
657
658 URLDataSourceImpl* URLDataManagerBackend::GetDataSourceFromURL(
659     const GURL& url) {
660   // The input usually looks like: chrome://source_name/extra_bits?foo
661   // so do a lookup using the host of the URL.
662   DataSourceMap::iterator i = data_sources_.find(url.host());
663   if (i != data_sources_.end())
664     return i->second.get();
665
666   // No match using the host of the URL, so do a lookup using the scheme for
667   // URLs on the form source_name://extra_bits/foo .
668   i = data_sources_.find(url.scheme() + "://");
669   if (i != data_sources_.end())
670     return i->second.get();
671
672   // No matches found, so give up.
673   return NULL;
674 }
675
676 void URLDataManagerBackend::CallStartRequest(
677     scoped_refptr<URLDataSourceImpl> source,
678     const std::string& path,
679     int render_process_id,
680     int render_frame_id,
681     int request_id) {
682   if (BrowserThread::CurrentlyOn(BrowserThread::UI) &&
683       render_process_id != -1 &&
684       !RenderProcessHost::FromID(render_process_id)) {
685     // Make the request fail if its initiating renderer is no longer valid.
686     // This can happen when the IO thread posts this task just before the
687     // renderer shuts down.
688     source->SendResponse(request_id, NULL);
689     return;
690   }
691   source->source()->StartDataRequest(
692       path,
693       render_process_id,
694       render_frame_id,
695       base::Bind(&URLDataSourceImpl::SendResponse, source, request_id));
696 }
697
698 void URLDataManagerBackend::RemoveRequest(URLRequestChromeJob* job) {
699   // Remove the request from our list of pending requests.
700   // If/when the source sends the data that was requested, the data will just
701   // be thrown away.
702   for (PendingRequestMap::iterator i = pending_requests_.begin();
703        i != pending_requests_.end(); ++i) {
704     if (i->second == job) {
705       pending_requests_.erase(i);
706       return;
707     }
708   }
709 }
710
711 void URLDataManagerBackend::DataAvailable(RequestID request_id,
712                                           base::RefCountedMemory* bytes) {
713   // Forward this data on to the pending net::URLRequest, if it exists.
714   PendingRequestMap::iterator i = pending_requests_.find(request_id);
715   if (i != pending_requests_.end()) {
716     URLRequestChromeJob* job(i->second);
717     pending_requests_.erase(i);
718     job->DataAvailable(bytes);
719   }
720 }
721
722 namespace {
723
724 class DevToolsJobFactory
725     : public net::URLRequestJobFactory::ProtocolHandler {
726  public:
727   // |is_incognito| should be set for incognito profiles.
728   DevToolsJobFactory(content::ResourceContext* resource_context,
729                      bool is_incognito);
730   ~DevToolsJobFactory() override;
731
732   net::URLRequestJob* MaybeCreateJob(
733       net::URLRequest* request,
734       net::NetworkDelegate* network_delegate) const override;
735
736  private:
737   // |resource_context_| and |network_delegate_| are owned by ProfileIOData,
738   // which owns this ProtocolHandler.
739   content::ResourceContext* const resource_context_;
740
741   // True when generated from an incognito profile.
742   const bool is_incognito_;
743
744   DISALLOW_COPY_AND_ASSIGN(DevToolsJobFactory);
745 };
746
747 DevToolsJobFactory::DevToolsJobFactory(
748     content::ResourceContext* resource_context,
749     bool is_incognito)
750     : resource_context_(resource_context),
751       is_incognito_(is_incognito) {
752   DCHECK(resource_context_);
753 }
754
755 DevToolsJobFactory::~DevToolsJobFactory() {}
756
757 net::URLRequestJob*
758 DevToolsJobFactory::MaybeCreateJob(
759     net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
760   return new URLRequestChromeJob(
761       request, network_delegate,
762       GetURLDataManagerForResourceContext(resource_context_), is_incognito_);
763 }
764
765 }  // namespace
766
767 net::URLRequestJobFactory::ProtocolHandler*
768 CreateDevToolsProtocolHandler(content::ResourceContext* resource_context,
769                               bool is_incognito) {
770   return new DevToolsJobFactory(resource_context, is_incognito);
771 }
772
773 }  // namespace content