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