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.
5 #include "chrome/renderer/security_filter_peer.h"
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"
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) {
21 SecurityFilterPeer::~SecurityFilterPeer() {
26 SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
27 ResourceType::Type resource_type,
28 webkit_glue::ResourceLoaderBridge::Peer* peer,
30 // Create a filter for SSL and CERT errors.
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());
51 // For other errors, we use our normal error handling.
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
61 std::string html = base::StringPrintf(
62 "<html><meta charset='UTF-8'>"
63 "<body style='background-color:#990000;color:white;'>"
65 l10n_util::GetStringUTF8(IDS_UNSAFE_FRAME_MESSAGE).c_str());
66 return new ReplaceContentPeer(NULL, peer, "text/html", html);
69 void SecurityFilterPeer::OnUploadProgress(uint64 position, uint64 size) {
70 original_peer_->OnUploadProgress(position, size);
73 bool SecurityFilterPeer::OnReceivedRedirect(
75 const webkit_glue::ResourceResponseInfo& info,
76 bool* has_new_first_party_for_cookies,
77 GURL* new_first_party_for_cookies) {
82 void SecurityFilterPeer::OnReceivedResponse(
83 const webkit_glue::ResourceResponseInfo& info) {
87 void SecurityFilterPeer::OnReceivedData(const char* data,
89 int encoded_data_length) {
93 void SecurityFilterPeer::OnCompletedRequest(
95 bool was_ignored_by_handler,
96 bool stale_copy_in_cache,
97 const std::string& security_info,
98 const base::TimeTicks& completion_time,
99 int64 total_transfer_size) {
104 void ProcessResponseInfo(
105 const webkit_glue::ResourceResponseInfo& info_in,
106 webkit_glue::ResourceResponseInfo* info_out,
107 const std::string& mime_type) {
110 info_out->mime_type = mime_type;
111 // Let's create our own HTTP headers.
112 std::string raw_headers;
113 raw_headers.append("HTTP/1.1 200 OK");
114 raw_headers.push_back('\0');
115 // Don't cache the data we are serving, it is not the real data for that URL
116 // (if the filtered resource were to make it into the WebCore cache, then the
117 // same URL loaded in a safe scenario would still return the filtered
119 raw_headers.append("cache-control: no-cache");
120 raw_headers.push_back('\0');
121 if (!mime_type.empty()) {
122 raw_headers.append("content-type: ");
123 raw_headers.append(mime_type);
124 raw_headers.push_back('\0');
126 raw_headers.push_back('\0');
127 net::HttpResponseHeaders* new_headers =
128 new net::HttpResponseHeaders(raw_headers);
129 info_out->headers = new_headers;
132 ////////////////////////////////////////////////////////////////////////////////
135 BufferedPeer::BufferedPeer(
136 webkit_glue::ResourceLoaderBridge* resource_loader_bridge,
137 webkit_glue::ResourceLoaderBridge::Peer* peer,
138 const std::string& mime_type)
139 : SecurityFilterPeer(resource_loader_bridge, peer),
140 mime_type_(mime_type) {
143 BufferedPeer::~BufferedPeer() {
146 void BufferedPeer::OnReceivedResponse(
147 const webkit_glue::ResourceResponseInfo& info) {
148 ProcessResponseInfo(info, &response_info_, mime_type_);
151 void BufferedPeer::OnReceivedData(const char* data,
153 int encoded_data_length) {
154 data_.append(data, data_length);
157 void BufferedPeer::OnCompletedRequest(int error_code,
158 bool was_ignored_by_handler,
159 bool stale_copy_in_cache,
160 const std::string& security_info,
161 const base::TimeTicks& completion_time,
162 int64 total_transfer_size) {
163 // Make sure we delete ourselves at the end of this call.
164 scoped_ptr<BufferedPeer> this_deleter(this);
166 // Give sub-classes a chance at altering the data.
167 if (error_code != net::OK || !DataReady()) {
168 // Pretend we failed to load the resource.
169 original_peer_->OnReceivedResponse(response_info_);
170 original_peer_->OnCompletedRequest(net::ERR_ABORTED, false,
172 security_info, completion_time,
173 total_transfer_size);
177 original_peer_->OnReceivedResponse(response_info_);
179 original_peer_->OnReceivedData(data_.data(),
180 static_cast<int>(data_.size()),
182 original_peer_->OnCompletedRequest(error_code, was_ignored_by_handler,
183 stale_copy_in_cache, security_info,
184 completion_time, total_transfer_size);
187 ////////////////////////////////////////////////////////////////////////////////
188 // ReplaceContentPeer
190 ReplaceContentPeer::ReplaceContentPeer(
191 webkit_glue::ResourceLoaderBridge* resource_loader_bridge,
192 webkit_glue::ResourceLoaderBridge::Peer* peer,
193 const std::string& mime_type,
194 const std::string& data)
195 : SecurityFilterPeer(resource_loader_bridge, peer),
196 mime_type_(mime_type),
200 ReplaceContentPeer::~ReplaceContentPeer() {
203 void ReplaceContentPeer::OnReceivedResponse(
204 const webkit_glue::ResourceResponseInfo& info) {
205 // Ignore this, we'll serve some alternate content in OnCompletedRequest.
208 void ReplaceContentPeer::OnReceivedData(const char* data,
210 int encoded_data_length) {
211 // Ignore this, we'll serve some alternate content in OnCompletedRequest.
214 void ReplaceContentPeer::OnCompletedRequest(
216 bool was_ignored_by_handler,
217 bool stale_copy_in_cache,
218 const std::string& security_info,
219 const base::TimeTicks& completion_time,
220 int64 total_transfer_size) {
221 webkit_glue::ResourceResponseInfo info;
222 ProcessResponseInfo(info, &info, mime_type_);
223 info.security_info = security_info;
224 info.content_length = static_cast<int>(data_.size());
225 original_peer_->OnReceivedResponse(info);
227 original_peer_->OnReceivedData(data_.data(),
228 static_cast<int>(data_.size()),
230 original_peer_->OnCompletedRequest(net::OK,
235 total_transfer_size);
237 // The request processing is complete, we must delete ourselves.