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