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/loader/certificate_resource_handler.h" 6 7 #include "base/strings/string_util.h" 8 #include "content/browser/loader/resource_request_info_impl.h" 9 #include "content/public/browser/content_browser_client.h" 10 #include "content/public/common/resource_response.h" 11 #include "net/base/io_buffer.h" 12 #include "net/base/mime_sniffer.h" 13 #include "net/base/mime_util.h" 14 #include "net/http/http_response_headers.h" 15 #include "net/url_request/redirect_info.h" 16 #include "net/url_request/url_request.h" 17 #include "net/url_request/url_request_status.h" 18 19 namespace content { 20 21 CertificateResourceHandler::CertificateResourceHandler( 22 net::URLRequest* request) 23 : ResourceHandler(request), 24 content_length_(0), 25 read_buffer_(NULL), 26 resource_buffer_(NULL), 27 cert_type_(net::CERTIFICATE_MIME_TYPE_UNKNOWN) { 28 } 29 30 CertificateResourceHandler::~CertificateResourceHandler() { 31 } 32 33 bool CertificateResourceHandler::OnUploadProgress(uint64 position, 34 uint64 size) { 35 return true; 36 } 37 38 bool CertificateResourceHandler::OnRequestRedirected( 39 const net::RedirectInfo& redirect_info, 40 ResourceResponse* resp, 41 bool* defer) { 42 return true; 43 } 44 45 bool CertificateResourceHandler::OnResponseStarted(ResourceResponse* resp, 46 bool* defer) { 47 cert_type_ = net::GetCertificateMimeTypeForMimeType(resp->head.mime_type); 48 return cert_type_ != net::CERTIFICATE_MIME_TYPE_UNKNOWN; 49 } 50 51 bool CertificateResourceHandler::OnWillStart(const GURL& url, bool* defer) { 52 return true; 53 } 54 55 bool CertificateResourceHandler::OnBeforeNetworkStart(const GURL& url, 56 bool* defer) { 57 return true; 58 } 59 60 bool CertificateResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, 61 int* buf_size, 62 int min_size) { 63 static const int kReadBufSize = 32768; 64 65 // TODO(gauravsh): Should we use 'min_size' here? 66 DCHECK(buf && buf_size); 67 if (!read_buffer_.get()) { 68 read_buffer_ = new net::IOBuffer(kReadBufSize); 69 } 70 *buf = read_buffer_.get(); 71 *buf_size = kReadBufSize; 72 73 return true; 74 } 75 76 bool CertificateResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { 77 if (!bytes_read) 78 return true; 79 80 // We have more data to read. 81 DCHECK(read_buffer_.get()); 82 content_length_ += bytes_read; 83 84 // Release the ownership of the buffer, and store a reference 85 // to it. A new one will be allocated in OnWillRead(). 86 scoped_refptr<net::IOBuffer> buffer; 87 read_buffer_.swap(buffer); 88 // TODO(gauravsh): Should this be handled by a separate thread? 89 buffer_.push_back(std::make_pair(buffer, bytes_read)); 90 91 return true; 92 } 93 94 void CertificateResourceHandler::OnResponseCompleted( 95 const net::URLRequestStatus& urs, 96 const std::string& sec_info, 97 bool* defer) { 98 if (urs.status() != net::URLRequestStatus::SUCCESS) 99 return; 100 101 AssembleResource(); 102 103 const void* content_bytes = NULL; 104 if (resource_buffer_.get()) 105 content_bytes = resource_buffer_->data(); 106 107 // Note that it's up to the browser to verify that the certificate 108 // data is well-formed. 109 const ResourceRequestInfo* info = GetRequestInfo(); 110 GetContentClient()->browser()->AddCertificate( 111 cert_type_, content_bytes, content_length_, 112 info->GetChildID(), info->GetRenderFrameID()); 113 } 114 115 void CertificateResourceHandler::AssembleResource() { 116 // 0-length IOBuffers are not allowed. 117 if (content_length_ == 0) { 118 resource_buffer_ = NULL; 119 return; 120 } 121 122 // Create the new buffer. 123 resource_buffer_ = new net::IOBuffer(content_length_); 124 125 // Copy the data into it. 126 size_t bytes_copied = 0; 127 for (size_t i = 0; i < buffer_.size(); ++i) { 128 net::IOBuffer* data = buffer_[i].first.get(); 129 size_t data_len = buffer_[i].second; 130 DCHECK(data != NULL); 131 DCHECK_LE(bytes_copied + data_len, content_length_); 132 memcpy(resource_buffer_->data() + bytes_copied, data->data(), data_len); 133 bytes_copied += data_len; 134 } 135 DCHECK_EQ(content_length_, bytes_copied); 136 } 137 138 void CertificateResourceHandler::OnDataDownloaded(int bytes_downloaded) { 139 NOTREACHED(); 140 } 141 142 } // namespace content 143