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 const std::string
& security_info
,
97 const base::TimeTicks
& completion_time
) {
102 void ProcessResponseInfo(
103 const webkit_glue::ResourceResponseInfo
& info_in
,
104 webkit_glue::ResourceResponseInfo
* info_out
,
105 const std::string
& mime_type
) {
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
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');
124 raw_headers
.push_back('\0');
125 net::HttpResponseHeaders
* new_headers
=
126 new net::HttpResponseHeaders(raw_headers
);
127 info_out
->headers
= new_headers
;
130 ////////////////////////////////////////////////////////////////////////////////
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
) {
141 BufferedPeer::~BufferedPeer() {
144 void BufferedPeer::OnReceivedResponse(
145 const webkit_glue::ResourceResponseInfo
& info
) {
146 ProcessResponseInfo(info
, &response_info_
, mime_type_
);
149 void BufferedPeer::OnReceivedData(const char* data
,
151 int encoded_data_length
) {
152 data_
.append(data
, data_length
);
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);
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
,
171 original_peer_
->OnReceivedResponse(response_info_
);
173 original_peer_
->OnReceivedData(data_
.data(),
174 static_cast<int>(data_
.size()),
176 original_peer_
->OnCompletedRequest(error_code
, was_ignored_by_handler
,
177 security_info
, completion_time
);
180 ////////////////////////////////////////////////////////////////////////////////
181 // ReplaceContentPeer
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
),
193 ReplaceContentPeer::~ReplaceContentPeer() {
196 void ReplaceContentPeer::OnReceivedResponse(
197 const webkit_glue::ResourceResponseInfo
& info
) {
198 // Ignore this, we'll serve some alternate content in OnCompletedRequest.
201 void ReplaceContentPeer::OnReceivedData(const char* data
,
203 int encoded_data_length
) {
204 // Ignore this, we'll serve some alternate content in OnCompletedRequest.
207 void ReplaceContentPeer::OnCompletedRequest(
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
);
218 original_peer_
->OnReceivedData(data_
.data(),
219 static_cast<int>(data_
.size()),
221 original_peer_
->OnCompletedRequest(net::OK
,
226 // The request processing is complete, we must delete ourselves.