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