Home | History | Annotate | Download | only in net
      1 // Copyright (c) 2011 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 "chrome/browser/net/view_http_cache_job_factory.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/message_loop.h"
      9 #include "base/string_util.h"
     10 #include "base/task.h"
     11 #include "chrome/common/url_constants.h"
     12 #include "net/base/net_errors.h"
     13 #include "net/url_request/url_request.h"
     14 #include "net/url_request/url_request_context.h"
     15 #include "net/url_request/url_request_simple_job.h"
     16 #include "net/url_request/view_cache_helper.h"
     17 
     18 namespace {
     19 
     20 // A job subclass that dumps an HTTP cache entry.
     21 class ViewHttpCacheJob : public net::URLRequestJob {
     22  public:
     23   explicit ViewHttpCacheJob(net::URLRequest* request)
     24       : net::URLRequestJob(request),
     25         core_(new Core),
     26         ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
     27         ALLOW_THIS_IN_INITIALIZER_LIST(
     28             callback_(NewCallback(this,
     29                                   &ViewHttpCacheJob::OnStartCompleted))) {}
     30 
     31   virtual void Start();
     32   virtual void Kill();
     33   virtual bool GetMimeType(std::string* mime_type) const {
     34     return core_->GetMimeType(mime_type);
     35   }
     36   virtual bool GetCharset(std::string* charset) {
     37     return core_->GetCharset(charset);
     38   }
     39   virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read) {
     40     return core_->ReadRawData(buf, buf_size, bytes_read);
     41   }
     42 
     43  private:
     44   class Core : public base::RefCounted<Core> {
     45    public:
     46     Core()
     47         : data_offset_(0),
     48           ALLOW_THIS_IN_INITIALIZER_LIST(
     49               callback_(this, &Core::OnIOComplete)),
     50           user_callback_(NULL) {}
     51 
     52     int Start(const net::URLRequest& request, Callback0::Type* callback);
     53 
     54     // Prevents it from invoking its callback. It will self-delete.
     55     void Orphan() {
     56       DCHECK(user_callback_);
     57       user_callback_ = NULL;
     58     }
     59 
     60     bool GetMimeType(std::string* mime_type) const;
     61     bool GetCharset(std::string* charset);
     62     bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
     63 
     64    private:
     65     friend class base::RefCounted<Core>;
     66 
     67     ~Core() {}
     68 
     69     // Called when ViewCacheHelper completes the operation.
     70     void OnIOComplete(int result);
     71 
     72     std::string data_;
     73     int data_offset_;
     74     net::ViewCacheHelper cache_helper_;
     75     net::CompletionCallbackImpl<Core> callback_;
     76     Callback0::Type* user_callback_;
     77 
     78     DISALLOW_COPY_AND_ASSIGN(Core);
     79   };
     80 
     81   ~ViewHttpCacheJob() {}
     82 
     83   void StartAsync();
     84   void OnStartCompleted();
     85 
     86   scoped_refptr<Core> core_;
     87   ScopedRunnableMethodFactory<ViewHttpCacheJob> method_factory_;
     88   scoped_ptr<Callback0::Type> callback_;
     89 
     90   DISALLOW_COPY_AND_ASSIGN(ViewHttpCacheJob);
     91 };
     92 
     93 void ViewHttpCacheJob::Start() {
     94   MessageLoop::current()->PostTask(
     95       FROM_HERE,
     96       method_factory_.NewRunnableMethod(&ViewHttpCacheJob::StartAsync));
     97 }
     98 
     99 void ViewHttpCacheJob::Kill() {
    100   method_factory_.RevokeAll();
    101   core_->Orphan();
    102   core_ = NULL;
    103   net::URLRequestJob::Kill();
    104 }
    105 
    106 void ViewHttpCacheJob::StartAsync() {
    107   DCHECK(request());
    108 
    109   if (!request())
    110     return;
    111 
    112   int rv = core_->Start(*request(), callback_.get());
    113   if (rv != net::ERR_IO_PENDING) {
    114     DCHECK_EQ(net::OK, rv);
    115     OnStartCompleted();
    116   }
    117 }
    118 
    119 void ViewHttpCacheJob::OnStartCompleted() {
    120   NotifyHeadersComplete();
    121 }
    122 
    123 int ViewHttpCacheJob::Core::Start(const net::URLRequest& request,
    124                                   Callback0::Type* callback) {
    125   DCHECK(callback);
    126   DCHECK(!user_callback_);
    127 
    128   AddRef();  // Released on OnIOComplete().
    129   std::string cache_key =
    130       request.url().spec().substr(strlen(chrome::kNetworkViewCacheURL));
    131 
    132   int rv;
    133   if (cache_key.empty()) {
    134     rv = cache_helper_.GetContentsHTML(request.context(),
    135                                        chrome::kNetworkViewCacheURL, &data_,
    136                                        &callback_);
    137   } else {
    138     rv = cache_helper_.GetEntryInfoHTML(cache_key, request.context(),
    139                                         &data_, &callback_);
    140   }
    141 
    142   if (rv == net::ERR_IO_PENDING)
    143     user_callback_ = callback;
    144 
    145   return rv;
    146 }
    147 
    148 bool ViewHttpCacheJob::Core::GetMimeType(std::string* mime_type) const {
    149   mime_type->assign("text/html");
    150   return true;
    151 }
    152 
    153 bool ViewHttpCacheJob::Core::GetCharset(std::string* charset) {
    154   charset->assign("UTF-8");
    155   return true;
    156 }
    157 
    158 bool ViewHttpCacheJob::Core::ReadRawData(net::IOBuffer* buf,
    159                                          int buf_size,
    160                                          int* bytes_read) {
    161   DCHECK(bytes_read);
    162   int remaining = static_cast<int>(data_.size()) - data_offset_;
    163   if (buf_size > remaining)
    164     buf_size = remaining;
    165   memcpy(buf->data(), data_.data() + data_offset_, buf_size);
    166   data_offset_ += buf_size;
    167   *bytes_read = buf_size;
    168   return true;
    169 }
    170 
    171 void ViewHttpCacheJob::Core::OnIOComplete(int result) {
    172   DCHECK_EQ(net::OK, result);
    173 
    174   if (user_callback_)
    175     user_callback_->Run();
    176 
    177   // We may be holding the last reference to this job. Do not access |this|
    178   // after Release().
    179   Release();  // Acquired on Start().
    180 }
    181 
    182 }  // namespace.
    183 
    184 // Static.
    185 bool ViewHttpCacheJobFactory::IsSupportedURL(const GURL& url) {
    186   return StartsWithASCII(url.spec(), chrome::kNetworkViewCacheURL,
    187                          true /*case_sensitive*/);
    188 }
    189 
    190 // Static.
    191 net::URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest(
    192     net::URLRequest* request) {
    193   return new ViewHttpCacheJob(request);
    194 }
    195