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