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