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