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