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 "chrome/renderer/security_filter_peer.h" 6 7#include "base/memory/scoped_ptr.h" 8#include "base/strings/stringprintf.h" 9#include "chrome/grit/generated_resources.h" 10#include "net/base/net_errors.h" 11#include "net/http/http_response_headers.h" 12#include "ui/base/l10n/l10n_util.h" 13 14SecurityFilterPeer::SecurityFilterPeer(content::RequestPeer* peer) 15 : original_peer_(peer) { 16} 17 18SecurityFilterPeer::~SecurityFilterPeer() { 19} 20 21// static 22SecurityFilterPeer* 23SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest( 24 content::ResourceType resource_type, 25 content::RequestPeer* peer, 26 int os_error) { 27 // Create a filter for SSL and CERT errors. 28 switch (os_error) { 29 case net::ERR_SSL_PROTOCOL_ERROR: 30 case net::ERR_CERT_COMMON_NAME_INVALID: 31 case net::ERR_CERT_DATE_INVALID: 32 case net::ERR_CERT_AUTHORITY_INVALID: 33 case net::ERR_CERT_CONTAINS_ERRORS: 34 case net::ERR_CERT_NO_REVOCATION_MECHANISM: 35 case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: 36 case net::ERR_CERT_REVOKED: 37 case net::ERR_CERT_INVALID: 38 case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: 39 case net::ERR_CERT_WEAK_KEY: 40 case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: 41 case net::ERR_INSECURE_RESPONSE: 42 case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: 43 if (content::IsResourceTypeFrame(resource_type)) 44 return CreateSecurityFilterPeerForFrame(peer, os_error); 45 // Any other content is entirely filtered-out. 46 return new ReplaceContentPeer(peer, std::string(), std::string()); 47 default: 48 // For other errors, we use our normal error handling. 49 return NULL; 50 } 51} 52 53// static 54SecurityFilterPeer* SecurityFilterPeer::CreateSecurityFilterPeerForFrame( 55 content::RequestPeer* peer, 56 int os_error) { 57 // TODO(jcampan): use a different message when getting a phishing/malware 58 // error. 59 std::string html = base::StringPrintf( 60 "<html><meta charset='UTF-8'>" 61 "<body style='background-color:#990000;color:white;'>" 62 "%s</body></html>", 63 l10n_util::GetStringUTF8(IDS_UNSAFE_FRAME_MESSAGE).c_str()); 64 return new ReplaceContentPeer(peer, "text/html", html); 65} 66 67void SecurityFilterPeer::OnUploadProgress(uint64 position, uint64 size) { 68 original_peer_->OnUploadProgress(position, size); 69} 70 71bool SecurityFilterPeer::OnReceivedRedirect( 72 const net::RedirectInfo& redirect_info, 73 const content::ResourceResponseInfo& info) { 74 NOTREACHED(); 75 return false; 76} 77 78void SecurityFilterPeer::OnReceivedResponse( 79 const content::ResourceResponseInfo& info) { 80 NOTREACHED(); 81} 82 83void SecurityFilterPeer::OnReceivedData(const char* data, 84 int data_length, 85 int encoded_data_length) { 86 NOTREACHED(); 87} 88 89void SecurityFilterPeer::OnCompletedRequest( 90 int error_code, 91 bool was_ignored_by_handler, 92 bool stale_copy_in_cache, 93 const std::string& security_info, 94 const base::TimeTicks& completion_time, 95 int64 total_transfer_size) { 96 NOTREACHED(); 97} 98 99// static 100void ProcessResponseInfo(const content::ResourceResponseInfo& info_in, 101 content::ResourceResponseInfo* info_out, 102 const std::string& mime_type) { 103 DCHECK(info_out); 104 *info_out = info_in; 105 info_out->mime_type = mime_type; 106 // Let's create our own HTTP headers. 107 std::string raw_headers; 108 raw_headers.append("HTTP/1.1 200 OK"); 109 raw_headers.push_back('\0'); 110 // Don't cache the data we are serving, it is not the real data for that URL 111 // (if the filtered resource were to make it into the WebCore cache, then the 112 // same URL loaded in a safe scenario would still return the filtered 113 // resource). 114 raw_headers.append("cache-control: no-cache"); 115 raw_headers.push_back('\0'); 116 if (!mime_type.empty()) { 117 raw_headers.append("content-type: "); 118 raw_headers.append(mime_type); 119 raw_headers.push_back('\0'); 120 } 121 raw_headers.push_back('\0'); 122 net::HttpResponseHeaders* new_headers = 123 new net::HttpResponseHeaders(raw_headers); 124 info_out->headers = new_headers; 125} 126 127//////////////////////////////////////////////////////////////////////////////// 128// BufferedPeer 129 130BufferedPeer::BufferedPeer(content::RequestPeer* peer, 131 const std::string& mime_type) 132 : SecurityFilterPeer(peer), mime_type_(mime_type) {} 133 134BufferedPeer::~BufferedPeer() { 135} 136 137void BufferedPeer::OnReceivedResponse( 138 const content::ResourceResponseInfo& info) { 139 ProcessResponseInfo(info, &response_info_, mime_type_); 140} 141 142void BufferedPeer::OnReceivedData(const char* data, 143 int data_length, 144 int encoded_data_length) { 145 data_.append(data, data_length); 146} 147 148void BufferedPeer::OnCompletedRequest(int error_code, 149 bool was_ignored_by_handler, 150 bool stale_copy_in_cache, 151 const std::string& security_info, 152 const base::TimeTicks& completion_time, 153 int64 total_transfer_size) { 154 // Make sure we delete ourselves at the end of this call. 155 scoped_ptr<BufferedPeer> this_deleter(this); 156 157 // Give sub-classes a chance at altering the data. 158 if (error_code != net::OK || !DataReady()) { 159 // Pretend we failed to load the resource. 160 original_peer_->OnReceivedResponse(response_info_); 161 original_peer_->OnCompletedRequest(net::ERR_ABORTED, false, 162 stale_copy_in_cache, 163 security_info, completion_time, 164 total_transfer_size); 165 return; 166 } 167 168 original_peer_->OnReceivedResponse(response_info_); 169 if (!data_.empty()) 170 original_peer_->OnReceivedData(data_.data(), 171 static_cast<int>(data_.size()), 172 -1); 173 original_peer_->OnCompletedRequest(error_code, was_ignored_by_handler, 174 stale_copy_in_cache, security_info, 175 completion_time, total_transfer_size); 176} 177 178//////////////////////////////////////////////////////////////////////////////// 179// ReplaceContentPeer 180 181ReplaceContentPeer::ReplaceContentPeer(content::RequestPeer* peer, 182 const std::string& mime_type, 183 const std::string& data) 184 : SecurityFilterPeer(peer), 185 mime_type_(mime_type), 186 data_(data) {} 187 188ReplaceContentPeer::~ReplaceContentPeer() { 189} 190 191void ReplaceContentPeer::OnReceivedResponse( 192 const content::ResourceResponseInfo& info) { 193 // Ignore this, we'll serve some alternate content in OnCompletedRequest. 194} 195 196void ReplaceContentPeer::OnReceivedData(const char* data, 197 int data_length, 198 int encoded_data_length) { 199 // Ignore this, we'll serve some alternate content in OnCompletedRequest. 200} 201 202void ReplaceContentPeer::OnCompletedRequest( 203 int error_code, 204 bool was_ignored_by_handler, 205 bool stale_copy_in_cache, 206 const std::string& security_info, 207 const base::TimeTicks& completion_time, 208 int64 total_transfer_size) { 209 content::ResourceResponseInfo info; 210 ProcessResponseInfo(info, &info, mime_type_); 211 info.security_info = security_info; 212 info.content_length = static_cast<int>(data_.size()); 213 original_peer_->OnReceivedResponse(info); 214 if (!data_.empty()) 215 original_peer_->OnReceivedData(data_.data(), 216 static_cast<int>(data_.size()), 217 -1); 218 original_peer_->OnCompletedRequest(net::OK, 219 false, 220 stale_copy_in_cache, 221 security_info, 222 completion_time, 223 total_transfer_size); 224 225 // The request processing is complete, we must delete ourselves. 226 delete this; 227} 228