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/message_loop.h" 13#include "base/strings/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 callback_(base::Bind(&ViewHttpCacheJob::OnStartCompleted, 32 base::Unretained(this))), 33 weak_factory_(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::Closure callback_; 93 94 base::WeakPtrFactory<ViewHttpCacheJob> weak_factory_; 95 96 DISALLOW_COPY_AND_ASSIGN(ViewHttpCacheJob); 97}; 98 99void ViewHttpCacheJob::Start() { 100 base::MessageLoop::current()->PostTask( 101 FROM_HERE, 102 base::Bind(&ViewHttpCacheJob::StartAsync, weak_factory_.GetWeakPtr())); 103} 104 105void ViewHttpCacheJob::Kill() { 106 weak_factory_.InvalidateWeakPtrs(); 107 if (core_.get()) { 108 core_->Orphan(); 109 core_ = NULL; 110 } 111 net::URLRequestJob::Kill(); 112} 113 114void ViewHttpCacheJob::StartAsync() { 115 DCHECK(request()); 116 117 if (!request()) 118 return; 119 120 int rv = core_->Start(*request(), callback_); 121 if (rv != net::ERR_IO_PENDING) { 122 DCHECK_EQ(net::OK, rv); 123 OnStartCompleted(); 124 } 125} 126 127void ViewHttpCacheJob::OnStartCompleted() { 128 NotifyHeadersComplete(); 129} 130 131int ViewHttpCacheJob::Core::Start(const net::URLRequest& request, 132 const base::Closure& callback) { 133 DCHECK(!callback.is_null()); 134 DCHECK(user_callback_.is_null()); 135 136 AddRef(); // Released on OnIOComplete(). 137 std::string cache_key = 138 request.url().spec().substr(strlen(kChromeUINetworkViewCacheURL)); 139 140 int rv; 141 if (cache_key.empty()) { 142 rv = cache_helper_.GetContentsHTML(request.context(), 143 kChromeUINetworkViewCacheURL, 144 &data_, callback_); 145 } else { 146 rv = cache_helper_.GetEntryInfoHTML(cache_key, request.context(), 147 &data_, callback_); 148 } 149 150 if (rv == net::ERR_IO_PENDING) 151 user_callback_ = callback; 152 153 return rv; 154} 155 156bool ViewHttpCacheJob::Core::GetMimeType(std::string* mime_type) const { 157 mime_type->assign("text/html"); 158 return true; 159} 160 161bool ViewHttpCacheJob::Core::GetCharset(std::string* charset) { 162 charset->assign("UTF-8"); 163 return true; 164} 165 166bool ViewHttpCacheJob::Core::ReadRawData(net::IOBuffer* buf, 167 int buf_size, 168 int* bytes_read) { 169 DCHECK(bytes_read); 170 int remaining = static_cast<int>(data_.size()) - data_offset_; 171 if (buf_size > remaining) 172 buf_size = remaining; 173 memcpy(buf->data(), data_.data() + data_offset_, buf_size); 174 data_offset_ += buf_size; 175 *bytes_read = buf_size; 176 return true; 177} 178 179void ViewHttpCacheJob::Core::OnIOComplete(int result) { 180 DCHECK_EQ(net::OK, result); 181 182 if (!user_callback_.is_null()) 183 user_callback_.Run(); 184 185 // We may be holding the last reference to this job. Do not access |this| 186 // after Release(). 187 Release(); // Acquired on Start(). 188} 189 190} // namespace. 191 192// Static. 193bool ViewHttpCacheJobFactory::IsSupportedURL(const GURL& url) { 194 return url.SchemeIs(kChromeUIScheme) && 195 url.host() == kChromeUINetworkViewCacheHost; 196} 197 198// Static. 199net::URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest( 200 net::URLRequest* request, net::NetworkDelegate* network_delegate) { 201 return new ViewHttpCacheJob(request, network_delegate); 202} 203 204} // namespace content 205