Home | History | Annotate | Download | only in loader
      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 "content/browser/loader/buffered_resource_handler.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/logging.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/strings/string_util.h"
     13 #include "content/browser/download/download_resource_handler.h"
     14 #include "content/browser/download/download_stats.h"
     15 #include "content/browser/loader/certificate_resource_handler.h"
     16 #include "content/browser/loader/resource_dispatcher_host_impl.h"
     17 #include "content/browser/loader/resource_request_info_impl.h"
     18 #include "content/browser/loader/stream_resource_handler.h"
     19 #include "content/public/browser/content_browser_client.h"
     20 #include "content/public/browser/download_item.h"
     21 #include "content/public/browser/download_save_info.h"
     22 #include "content/public/browser/download_url_parameters.h"
     23 #include "content/public/browser/resource_context.h"
     24 #include "content/public/browser/resource_dispatcher_host_delegate.h"
     25 #include "content/public/common/resource_response.h"
     26 #include "content/public/common/webplugininfo.h"
     27 #include "net/base/io_buffer.h"
     28 #include "net/base/mime_sniffer.h"
     29 #include "net/base/mime_util.h"
     30 #include "net/base/net_errors.h"
     31 #include "net/http/http_content_disposition.h"
     32 #include "net/http/http_response_headers.h"
     33 
     34 #if defined(ENABLE_PLUGINS)
     35 #include "content/browser/plugin_service_impl.h"
     36 #endif
     37 
     38 namespace content {
     39 
     40 namespace {
     41 
     42 void RecordSnifferMetrics(bool sniffing_blocked,
     43                           bool we_would_like_to_sniff,
     44                           const std::string& mime_type) {
     45   static base::HistogramBase* nosniff_usage(NULL);
     46   if (!nosniff_usage)
     47     nosniff_usage = base::BooleanHistogram::FactoryGet(
     48         "nosniff.usage", base::HistogramBase::kUmaTargetedHistogramFlag);
     49   nosniff_usage->AddBoolean(sniffing_blocked);
     50 
     51   if (sniffing_blocked) {
     52     static base::HistogramBase* nosniff_otherwise(NULL);
     53     if (!nosniff_otherwise)
     54       nosniff_otherwise = base::BooleanHistogram::FactoryGet(
     55           "nosniff.otherwise", base::HistogramBase::kUmaTargetedHistogramFlag);
     56     nosniff_otherwise->AddBoolean(we_would_like_to_sniff);
     57 
     58     static base::HistogramBase* nosniff_empty_mime_type(NULL);
     59     if (!nosniff_empty_mime_type)
     60       nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet(
     61           "nosniff.empty_mime_type",
     62           base::HistogramBase::kUmaTargetedHistogramFlag);
     63     nosniff_empty_mime_type->AddBoolean(mime_type.empty());
     64   }
     65 }
     66 
     67 // Used to write into an existing IOBuffer at a given offset.
     68 class DependentIOBuffer : public net::WrappedIOBuffer {
     69  public:
     70   DependentIOBuffer(net::IOBuffer* buf, int offset)
     71       : net::WrappedIOBuffer(buf->data() + offset),
     72         buf_(buf) {
     73   }
     74 
     75  private:
     76   virtual ~DependentIOBuffer() {}
     77 
     78   scoped_refptr<net::IOBuffer> buf_;
     79 };
     80 
     81 }  // namespace
     82 
     83 BufferedResourceHandler::BufferedResourceHandler(
     84     scoped_ptr<ResourceHandler> next_handler,
     85     ResourceDispatcherHostImpl* host,
     86     net::URLRequest* request)
     87     : LayeredResourceHandler(request, next_handler.Pass()),
     88       state_(STATE_STARTING),
     89       host_(host),
     90       read_buffer_size_(0),
     91       bytes_read_(0),
     92       must_download_(false),
     93       must_download_is_set_(false),
     94       weak_ptr_factory_(this) {
     95 }
     96 
     97 BufferedResourceHandler::~BufferedResourceHandler() {
     98 }
     99 
    100 void BufferedResourceHandler::SetController(ResourceController* controller) {
    101   ResourceHandler::SetController(controller);
    102 
    103   // Downstream handlers see us as their ResourceController, which allows us to
    104   // consume part or all of the resource response, and then later replay it to
    105   // downstream handler.
    106   DCHECK(next_handler_.get());
    107   next_handler_->SetController(this);
    108 }
    109 
    110 bool BufferedResourceHandler::OnResponseStarted(ResourceResponse* response,
    111                                                 bool* defer) {
    112   response_ = response;
    113 
    114   // TODO(darin): It is very odd to special-case 304 responses at this level.
    115   // We do so only because the code always has, see r24977 and r29355.  The
    116   // fact that 204 is no longer special-cased this way suggests that 304 need
    117   // not be special-cased either.
    118   //
    119   // The network stack only forwards 304 responses that were not received in
    120   // response to a conditional request (i.e., If-Modified-Since).  Other 304
    121   // responses end up being translated to 200 or whatever the cached response
    122   // code happens to be.  It should be very rare to see a 304 at this level.
    123 
    124   if (!(response_->head.headers.get() &&
    125         response_->head.headers->response_code() == 304)) {
    126     if (ShouldSniffContent()) {
    127       state_ = STATE_BUFFERING;
    128       return true;
    129     }
    130 
    131     if (response_->head.mime_type.empty()) {
    132       // Ugg.  The server told us not to sniff the content but didn't give us
    133       // a mime type.  What's a browser to do?  Turns out, we're supposed to
    134       // treat the response as "text/plain".  This is the most secure option.
    135       response_->head.mime_type.assign("text/plain");
    136     }
    137 
    138     // Treat feed types as text/plain.
    139     if (response_->head.mime_type == "application/rss+xml" ||
    140         response_->head.mime_type == "application/atom+xml") {
    141       response_->head.mime_type.assign("text/plain");
    142     }
    143   }
    144 
    145   state_ = STATE_PROCESSING;
    146   return ProcessResponse(defer);
    147 }
    148 
    149 // We'll let the original event handler provide a buffer, and reuse it for
    150 // subsequent reads until we're done buffering.
    151 bool BufferedResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
    152                                          int* buf_size,
    153                                          int min_size) {
    154   if (state_ == STATE_STREAMING)
    155     return next_handler_->OnWillRead(buf, buf_size, min_size);
    156 
    157   DCHECK_EQ(-1, min_size);
    158 
    159   if (read_buffer_.get()) {
    160     CHECK_LT(bytes_read_, read_buffer_size_);
    161     *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_);
    162     *buf_size = read_buffer_size_ - bytes_read_;
    163   } else {
    164     if (!next_handler_->OnWillRead(buf, buf_size, min_size))
    165       return false;
    166 
    167     read_buffer_ = *buf;
    168     read_buffer_size_ = *buf_size;
    169     DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
    170   }
    171   return true;
    172 }
    173 
    174 bool BufferedResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
    175   if (state_ == STATE_STREAMING)
    176     return next_handler_->OnReadCompleted(bytes_read, defer);
    177 
    178   DCHECK_EQ(state_, STATE_BUFFERING);
    179   bytes_read_ += bytes_read;
    180 
    181   if (!DetermineMimeType() && (bytes_read > 0))
    182     return true;  // Needs more data, so keep buffering.
    183 
    184   state_ = STATE_PROCESSING;
    185   return ProcessResponse(defer);
    186 }
    187 
    188 void BufferedResourceHandler::OnResponseCompleted(
    189     const net::URLRequestStatus& status,
    190     const std::string& security_info,
    191     bool* defer) {
    192   // Upon completion, act like a pass-through handler in case the downstream
    193   // handler defers OnResponseCompleted.
    194   state_ = STATE_STREAMING;
    195 
    196   next_handler_->OnResponseCompleted(status, security_info, defer);
    197 }
    198 
    199 void BufferedResourceHandler::Resume() {
    200   switch (state_) {
    201     case STATE_BUFFERING:
    202     case STATE_PROCESSING:
    203       NOTREACHED();
    204       break;
    205     case STATE_REPLAYING:
    206       base::MessageLoop::current()->PostTask(
    207           FROM_HERE,
    208           base::Bind(&BufferedResourceHandler::CallReplayReadCompleted,
    209                      weak_ptr_factory_.GetWeakPtr()));
    210       break;
    211     case STATE_STARTING:
    212     case STATE_STREAMING:
    213       controller()->Resume();
    214       break;
    215   }
    216 }
    217 
    218 void BufferedResourceHandler::Cancel() {
    219   controller()->Cancel();
    220 }
    221 
    222 void BufferedResourceHandler::CancelAndIgnore() {
    223   controller()->CancelAndIgnore();
    224 }
    225 
    226 void BufferedResourceHandler::CancelWithError(int error_code) {
    227   controller()->CancelWithError(error_code);
    228 }
    229 
    230 bool BufferedResourceHandler::ProcessResponse(bool* defer) {
    231   DCHECK_EQ(STATE_PROCESSING, state_);
    232 
    233   // TODO(darin): Stop special-casing 304 responses.
    234   if (!(response_->head.headers.get() &&
    235         response_->head.headers->response_code() == 304)) {
    236     if (!SelectNextHandler(defer))
    237       return false;
    238     if (*defer)
    239       return true;
    240   }
    241 
    242   state_ = STATE_REPLAYING;
    243 
    244   if (!next_handler_->OnResponseStarted(response_.get(), defer))
    245     return false;
    246 
    247   if (!read_buffer_.get()) {
    248     state_ = STATE_STREAMING;
    249     return true;
    250   }
    251 
    252   if (!*defer)
    253     return ReplayReadCompleted(defer);
    254 
    255   return true;
    256 }
    257 
    258 bool BufferedResourceHandler::ShouldSniffContent() {
    259   const std::string& mime_type = response_->head.mime_type;
    260 
    261   std::string content_type_options;
    262   request()->GetResponseHeaderByName("x-content-type-options",
    263                                      &content_type_options);
    264 
    265   bool sniffing_blocked =
    266       LowerCaseEqualsASCII(content_type_options, "nosniff");
    267   bool we_would_like_to_sniff =
    268       net::ShouldSniffMimeType(request()->url(), mime_type);
    269 
    270   RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
    271 
    272   if (!sniffing_blocked && we_would_like_to_sniff) {
    273     // We're going to look at the data before deciding what the content type
    274     // is.  That means we need to delay sending the ResponseStarted message
    275     // over the IPC channel.
    276     VLOG(1) << "To buffer: " << request()->url().spec();
    277     return true;
    278   }
    279 
    280   return false;
    281 }
    282 
    283 bool BufferedResourceHandler::DetermineMimeType() {
    284   DCHECK_EQ(STATE_BUFFERING, state_);
    285 
    286   const std::string& type_hint = response_->head.mime_type;
    287 
    288   std::string new_type;
    289   bool made_final_decision =
    290       net::SniffMimeType(read_buffer_->data(), bytes_read_, request()->url(),
    291                          type_hint, &new_type);
    292 
    293   // SniffMimeType() returns false if there is not enough data to determine
    294   // the mime type. However, even if it returns false, it returns a new type
    295   // that is probably better than the current one.
    296   response_->head.mime_type.assign(new_type);
    297 
    298   return made_final_decision;
    299 }
    300 
    301 bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
    302   DCHECK(!response_->head.mime_type.empty());
    303 
    304   ResourceRequestInfoImpl* info = GetRequestInfo();
    305   const std::string& mime_type = response_->head.mime_type;
    306 
    307   if (net::IsSupportedCertificateMimeType(mime_type)) {
    308     // Install certificate file.
    309     info->set_is_download(true);
    310     scoped_ptr<ResourceHandler> handler(
    311         new CertificateResourceHandler(request()));
    312     return UseAlternateNextHandler(handler.Pass(), std::string());
    313   }
    314 
    315   if (!info->allow_download())
    316     return true;
    317 
    318   bool must_download = MustDownload();
    319   if (!must_download) {
    320     if (net::IsSupportedMimeType(mime_type))
    321       return true;
    322 
    323     std::string payload;
    324     scoped_ptr<ResourceHandler> handler(
    325         host_->MaybeInterceptAsStream(request(), response_.get(), &payload));
    326     if (handler) {
    327       return UseAlternateNextHandler(handler.Pass(), payload);
    328     }
    329 
    330 #if defined(ENABLE_PLUGINS)
    331     bool stale;
    332     bool has_plugin = HasSupportingPlugin(&stale);
    333     if (stale) {
    334       // Refresh the plugins asynchronously.
    335       PluginServiceImpl::GetInstance()->GetPlugins(
    336           base::Bind(&BufferedResourceHandler::OnPluginsLoaded,
    337                      weak_ptr_factory_.GetWeakPtr()));
    338       request()->LogBlockedBy("BufferedResourceHandler");
    339       *defer = true;
    340       return true;
    341     }
    342     if (has_plugin)
    343       return true;
    344 #endif
    345   }
    346 
    347   // Install download handler
    348   info->set_is_download(true);
    349   scoped_ptr<ResourceHandler> handler(
    350       host_->CreateResourceHandlerForDownload(
    351           request(),
    352           true,  // is_content_initiated
    353           must_download,
    354           DownloadItem::kInvalidId,
    355           scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()),
    356           DownloadUrlParameters::OnStartedCallback()));
    357   return UseAlternateNextHandler(handler.Pass(), std::string());
    358 }
    359 
    360 bool BufferedResourceHandler::UseAlternateNextHandler(
    361     scoped_ptr<ResourceHandler> new_handler,
    362     const std::string& payload_for_old_handler) {
    363   if (response_->head.headers.get() &&  // Can be NULL if FTP.
    364       response_->head.headers->response_code() / 100 != 2) {
    365     // The response code indicates that this is an error page, but we don't
    366     // know how to display the content.  We follow Firefox here and show our
    367     // own error page instead of triggering a download.
    368     // TODO(abarth): We should abstract the response_code test, but this kind
    369     //               of check is scattered throughout our codebase.
    370     request()->CancelWithError(net::ERR_INVALID_RESPONSE);
    371     return false;
    372   }
    373 
    374   // Inform the original ResourceHandler that this will be handled entirely by
    375   // the new ResourceHandler.
    376   // TODO(darin): We should probably check the return values of these.
    377   bool defer_ignored = false;
    378   next_handler_->OnResponseStarted(response_.get(), &defer_ignored);
    379   // Although deferring OnResponseStarted is legal, the only downstream handler
    380   // which does so is CrossSiteResourceHandler. Cross-site transitions should
    381   // not trigger when switching handlers.
    382   DCHECK(!defer_ignored);
    383   if (payload_for_old_handler.empty()) {
    384     net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
    385                                  net::ERR_ABORTED);
    386     next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored);
    387     DCHECK(!defer_ignored);
    388   } else {
    389     scoped_refptr<net::IOBuffer> buf;
    390     int size = 0;
    391 
    392     next_handler_->OnWillRead(&buf, &size, -1);
    393     CHECK_GE(size, static_cast<int>(payload_for_old_handler.length()));
    394 
    395     memcpy(buf->data(), payload_for_old_handler.c_str(),
    396            payload_for_old_handler.length());
    397 
    398     next_handler_->OnReadCompleted(payload_for_old_handler.length(),
    399                                    &defer_ignored);
    400     DCHECK(!defer_ignored);
    401 
    402     net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
    403     next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored);
    404     DCHECK(!defer_ignored);
    405   }
    406 
    407   // This is handled entirely within the new ResourceHandler, so just reset the
    408   // original ResourceHandler.
    409   next_handler_ = new_handler.Pass();
    410   next_handler_->SetController(this);
    411 
    412   return CopyReadBufferToNextHandler();
    413 }
    414 
    415 bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) {
    416   DCHECK(read_buffer_.get());
    417 
    418   bool result = next_handler_->OnReadCompleted(bytes_read_, defer);
    419 
    420   read_buffer_ = NULL;
    421   read_buffer_size_ = 0;
    422   bytes_read_ = 0;
    423 
    424   state_ = STATE_STREAMING;
    425 
    426   return result;
    427 }
    428 
    429 void BufferedResourceHandler::CallReplayReadCompleted() {
    430   bool defer = false;
    431   if (!ReplayReadCompleted(&defer)) {
    432     controller()->Cancel();
    433   } else if (!defer) {
    434     state_ = STATE_STREAMING;
    435     controller()->Resume();
    436   }
    437 }
    438 
    439 bool BufferedResourceHandler::MustDownload() {
    440   if (must_download_is_set_)
    441     return must_download_;
    442 
    443   must_download_is_set_ = true;
    444 
    445   std::string disposition;
    446   request()->GetResponseHeaderByName("content-disposition", &disposition);
    447   if (!disposition.empty() &&
    448       net::HttpContentDisposition(disposition, std::string()).is_attachment()) {
    449     must_download_ = true;
    450   } else if (host_->delegate() &&
    451              host_->delegate()->ShouldForceDownloadResource(
    452                  request()->url(), response_->head.mime_type)) {
    453     must_download_ = true;
    454   } else {
    455     must_download_ = false;
    456   }
    457 
    458   return must_download_;
    459 }
    460 
    461 bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) {
    462 #if defined(ENABLE_PLUGINS)
    463   ResourceRequestInfoImpl* info = GetRequestInfo();
    464 
    465   bool allow_wildcard = false;
    466   WebPluginInfo plugin;
    467   return PluginServiceImpl::GetInstance()->GetPluginInfo(
    468       info->GetChildID(), info->GetRenderFrameID(), info->GetContext(),
    469       request()->url(), GURL(), response_->head.mime_type, allow_wildcard,
    470       stale, &plugin, NULL);
    471 #else
    472   if (stale)
    473     *stale = false;
    474   return false;
    475 #endif
    476 }
    477 
    478 bool BufferedResourceHandler::CopyReadBufferToNextHandler() {
    479   if (!read_buffer_.get())
    480     return true;
    481 
    482   scoped_refptr<net::IOBuffer> buf;
    483   int buf_len = 0;
    484   if (!next_handler_->OnWillRead(&buf, &buf_len, bytes_read_))
    485     return false;
    486 
    487   CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
    488   memcpy(buf->data(), read_buffer_->data(), bytes_read_);
    489   return true;
    490 }
    491 
    492 void BufferedResourceHandler::OnPluginsLoaded(
    493     const std::vector<WebPluginInfo>& plugins) {
    494   request()->LogUnblocked();
    495   bool defer = false;
    496   if (!ProcessResponse(&defer)) {
    497     controller()->Cancel();
    498   } else if (!defer) {
    499     controller()->Resume();
    500   }
    501 }
    502 
    503 }  // namespace content
    504