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