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