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 "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 ResourceType::Type 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 (ResourceType::IsFrame(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 GURL& new_url, 73 const GURL& new_first_party_for_cookies, 74 const content::ResourceResponseInfo& info) { 75 NOTREACHED(); 76 return false; 77} 78 79void SecurityFilterPeer::OnReceivedResponse( 80 const content::ResourceResponseInfo& info) { 81 NOTREACHED(); 82} 83 84void SecurityFilterPeer::OnReceivedData(const char* data, 85 int data_length, 86 int encoded_data_length) { 87 NOTREACHED(); 88} 89 90void SecurityFilterPeer::OnCompletedRequest( 91 int error_code, 92 bool was_ignored_by_handler, 93 bool stale_copy_in_cache, 94 const std::string& security_info, 95 const base::TimeTicks& completion_time, 96 int64 total_transfer_size) { 97 NOTREACHED(); 98} 99 100// static 101void ProcessResponseInfo(const content::ResourceResponseInfo& info_in, 102 content::ResourceResponseInfo* info_out, 103 const std::string& mime_type) { 104 DCHECK(info_out); 105 *info_out = info_in; 106 info_out->mime_type = mime_type; 107 // Let's create our own HTTP headers. 108 std::string raw_headers; 109 raw_headers.append("HTTP/1.1 200 OK"); 110 raw_headers.push_back('\0'); 111 // Don't cache the data we are serving, it is not the real data for that URL 112 // (if the filtered resource were to make it into the WebCore cache, then the 113 // same URL loaded in a safe scenario would still return the filtered 114 // resource). 115 raw_headers.append("cache-control: no-cache"); 116 raw_headers.push_back('\0'); 117 if (!mime_type.empty()) { 118 raw_headers.append("content-type: "); 119 raw_headers.append(mime_type); 120 raw_headers.push_back('\0'); 121 } 122 raw_headers.push_back('\0'); 123 net::HttpResponseHeaders* new_headers = 124 new net::HttpResponseHeaders(raw_headers); 125 info_out->headers = new_headers; 126} 127 128//////////////////////////////////////////////////////////////////////////////// 129// BufferedPeer 130 131BufferedPeer::BufferedPeer(content::RequestPeer* peer, 132 const std::string& mime_type) 133 : SecurityFilterPeer(peer), mime_type_(mime_type) {} 134 135BufferedPeer::~BufferedPeer() { 136} 137 138void BufferedPeer::OnReceivedResponse( 139 const content::ResourceResponseInfo& info) { 140 ProcessResponseInfo(info, &response_info_, mime_type_); 141} 142 143void BufferedPeer::OnReceivedData(const char* data, 144 int data_length, 145 int encoded_data_length) { 146 data_.append(data, data_length); 147} 148 149void BufferedPeer::OnCompletedRequest(int error_code, 150 bool was_ignored_by_handler, 151 bool stale_copy_in_cache, 152 const std::string& security_info, 153 const base::TimeTicks& completion_time, 154 int64 total_transfer_size) { 155 // Make sure we delete ourselves at the end of this call. 156 scoped_ptr<BufferedPeer> this_deleter(this); 157 158 // Give sub-classes a chance at altering the data. 159 if (error_code != net::OK || !DataReady()) { 160 // Pretend we failed to load the resource. 161 original_peer_->OnReceivedResponse(response_info_); 162 original_peer_->OnCompletedRequest(net::ERR_ABORTED, false, 163 stale_copy_in_cache, 164 security_info, completion_time, 165 total_transfer_size); 166 return; 167 } 168 169 original_peer_->OnReceivedResponse(response_info_); 170 if (!data_.empty()) 171 original_peer_->OnReceivedData(data_.data(), 172 static_cast<int>(data_.size()), 173 -1); 174 original_peer_->OnCompletedRequest(error_code, was_ignored_by_handler, 175 stale_copy_in_cache, security_info, 176 completion_time, total_transfer_size); 177} 178 179//////////////////////////////////////////////////////////////////////////////// 180// ReplaceContentPeer 181 182ReplaceContentPeer::ReplaceContentPeer(content::RequestPeer* peer, 183 const std::string& mime_type, 184 const std::string& data) 185 : SecurityFilterPeer(peer), 186 mime_type_(mime_type), 187 data_(data) {} 188 189ReplaceContentPeer::~ReplaceContentPeer() { 190} 191 192void ReplaceContentPeer::OnReceivedResponse( 193 const content::ResourceResponseInfo& info) { 194 // Ignore this, we'll serve some alternate content in OnCompletedRequest. 195} 196 197void ReplaceContentPeer::OnReceivedData(const char* data, 198 int data_length, 199 int encoded_data_length) { 200 // Ignore this, we'll serve some alternate content in OnCompletedRequest. 201} 202 203void ReplaceContentPeer::OnCompletedRequest( 204 int error_code, 205 bool was_ignored_by_handler, 206 bool stale_copy_in_cache, 207 const std::string& security_info, 208 const base::TimeTicks& completion_time, 209 int64 total_transfer_size) { 210 content::ResourceResponseInfo info; 211 ProcessResponseInfo(info, &info, mime_type_); 212 info.security_info = security_info; 213 info.content_length = static_cast<int>(data_.size()); 214 original_peer_->OnReceivedResponse(info); 215 if (!data_.empty()) 216 original_peer_->OnReceivedData(data_.data(), 217 static_cast<int>(data_.size()), 218 -1); 219 original_peer_->OnCompletedRequest(net::OK, 220 false, 221 stale_copy_in_cache, 222 security_info, 223 completion_time, 224 total_transfer_size); 225 226 // The request processing is complete, we must delete ourselves. 227 delete this; 228} 229