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