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