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 "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