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(next_handler.Pass()),
     84       state_(STATE_STARTING),
     85       host_(host),
     86       request_(request),
     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(
    108     int request_id,
    109     ResourceResponse* response,
    110     bool* defer) {
    111   response_ = response;
    112 
    113   // TODO(darin): It is very odd to special-case 304 responses at this level.
    114   // We do so only because the code always has, see r24977 and r29355.  The
    115   // fact that 204 is no longer special-cased this way suggests that 304 need
    116   // not be special-cased either.
    117   //
    118   // The network stack only forwards 304 responses that were not received in
    119   // response to a conditional request (i.e., If-Modified-Since).  Other 304
    120   // responses end up being translated to 200 or whatever the cached response
    121   // code happens to be.  It should be very rare to see a 304 at this level.
    122 
    123   if (!(response_->head.headers.get() &&
    124         response_->head.headers->response_code() == 304)) {
    125     if (ShouldSniffContent()) {
    126       state_ = STATE_BUFFERING;
    127       return true;
    128     }
    129 
    130     if (response_->head.mime_type.empty()) {
    131       // Ugg.  The server told us not to sniff the content but didn't give us
    132       // a mime type.  What's a browser to do?  Turns out, we're supposed to
    133       // treat the response as "text/plain".  This is the most secure option.
    134       response_->head.mime_type.assign("text/plain");
    135     }
    136 
    137     // Treat feed types as text/plain.
    138     if (response_->head.mime_type == "application/rss+xml" ||
    139         response_->head.mime_type == "application/atom+xml") {
    140       response_->head.mime_type.assign("text/plain");
    141     }
    142   }
    143 
    144   state_ = STATE_PROCESSING;
    145   return ProcessResponse(defer);
    146 }
    147 
    148 // We'll let the original event handler provide a buffer, and reuse it for
    149 // subsequent reads until we're done buffering.
    150 bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
    151                                          int* buf_size, int min_size) {
    152   if (state_ == STATE_STREAMING)
    153     return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
    154 
    155   DCHECK_EQ(-1, min_size);
    156 
    157   if (read_buffer_.get()) {
    158     CHECK_LT(bytes_read_, read_buffer_size_);
    159     *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_);
    160     *buf_size = read_buffer_size_ - bytes_read_;
    161   } else {
    162     if (!next_handler_->OnWillRead(request_id, buf, buf_size, min_size))
    163       return false;
    164 
    165     read_buffer_ = *buf;
    166     read_buffer_size_ = *buf_size;
    167     DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
    168   }
    169   return true;
    170 }
    171 
    172 bool BufferedResourceHandler::OnReadCompleted(int request_id, int bytes_read,
    173                                               bool* defer) {
    174   if (state_ == STATE_STREAMING)
    175     return next_handler_->OnReadCompleted(request_id, bytes_read, defer);
    176 
    177   DCHECK_EQ(state_, STATE_BUFFERING);
    178   bytes_read_ += bytes_read;
    179 
    180   if (!DetermineMimeType() && (bytes_read > 0))
    181     return true;  // Needs more data, so keep buffering.
    182 
    183   state_ = STATE_PROCESSING;
    184   return ProcessResponse(defer);
    185 }
    186 
    187 bool BufferedResourceHandler::OnResponseCompleted(
    188     int request_id,
    189     const net::URLRequestStatus& status,
    190     const std::string& security_info) {
    191   // Upon completion, act like a pass-through handler in case the downstream
    192   // handler defers OnResponseCompleted.
    193   state_ = STATE_STREAMING;
    194 
    195   return next_handler_->OnResponseCompleted(request_id, status, security_info);
    196 }
    197 
    198 void BufferedResourceHandler::Resume() {
    199   switch (state_) {
    200     case STATE_BUFFERING:
    201     case STATE_PROCESSING:
    202       NOTREACHED();
    203       break;
    204     case STATE_REPLAYING:
    205       base::MessageLoop::current()->PostTask(
    206           FROM_HERE,
    207           base::Bind(&BufferedResourceHandler::CallReplayReadCompleted,
    208                      weak_ptr_factory_.GetWeakPtr()));
    209       break;
    210     case STATE_STARTING:
    211     case STATE_STREAMING:
    212       controller()->Resume();
    213       break;
    214   }
    215 }
    216 
    217 void BufferedResourceHandler::Cancel() {
    218   controller()->Cancel();
    219 }
    220 
    221 void BufferedResourceHandler::CancelAndIgnore() {
    222   controller()->CancelAndIgnore();
    223 }
    224 
    225 void BufferedResourceHandler::CancelWithError(int error_code) {
    226   controller()->CancelWithError(error_code);
    227 }
    228 
    229 bool BufferedResourceHandler::ProcessResponse(bool* defer) {
    230   DCHECK_EQ(STATE_PROCESSING, state_);
    231 
    232   // TODO(darin): Stop special-casing 304 responses.
    233   if (!(response_->head.headers.get() &&
    234         response_->head.headers->response_code() == 304)) {
    235     if (!SelectNextHandler(defer))
    236       return false;
    237     if (*defer)
    238       return true;
    239   }
    240 
    241   state_ = STATE_REPLAYING;
    242 
    243   int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
    244   if (!next_handler_->OnResponseStarted(request_id, 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 = ResourceRequestInfoImpl::ForRequest(request_);
    305   const std::string& mime_type = response_->head.mime_type;
    306 
    307   if (net::IsSupportedCertificateMimeType(mime_type)) {
    308     // Install certificate file.
    309     scoped_ptr<ResourceHandler> handler(
    310         new CertificateResourceHandler(request_,
    311                                        info->GetChildID(),
    312                                        info->GetRouteID()));
    313     return UseAlternateNextHandler(handler.Pass());
    314   }
    315 
    316   if (!info->allow_download())
    317     return true;
    318 
    319   bool must_download = MustDownload();
    320   if (!must_download) {
    321     if (net::IsSupportedMimeType(mime_type))
    322       return true;
    323 
    324     scoped_ptr<ResourceHandler> handler(
    325         host_->MaybeInterceptAsStream(request_, response_.get()));
    326     if (handler)
    327       return UseAlternateNextHandler(handler.Pass());
    328 
    329 #if defined(ENABLE_PLUGINS)
    330     bool stale;
    331     bool has_plugin = HasSupportingPlugin(&stale);
    332     if (stale) {
    333       // Refresh the plugins asynchronously.
    334       PluginServiceImpl::GetInstance()->GetPlugins(
    335           base::Bind(&BufferedResourceHandler::OnPluginsLoaded,
    336                      weak_ptr_factory_.GetWeakPtr()));
    337       *defer = true;
    338       return true;
    339     }
    340     if (has_plugin)
    341       return true;
    342 #endif
    343   }
    344 
    345   // Install download handler
    346   info->set_is_download(true);
    347   scoped_ptr<ResourceHandler> handler(
    348       host_->CreateResourceHandlerForDownload(
    349           request_,
    350           true,  // is_content_initiated
    351           must_download,
    352           content::DownloadItem::kInvalidId,
    353           scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()),
    354           DownloadUrlParameters::OnStartedCallback()));
    355   return UseAlternateNextHandler(handler.Pass());
    356 }
    357 
    358 bool BufferedResourceHandler::UseAlternateNextHandler(
    359     scoped_ptr<ResourceHandler> new_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_FILE_NOT_FOUND);
    368     return false;
    369   }
    370 
    371   int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
    372 
    373   // Inform the original ResourceHandler that this will be handled entirely by
    374   // the new ResourceHandler.
    375   // TODO(darin): We should probably check the return values of these.
    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 
    383   // This is handled entirely within the new ResourceHandler, so just reset the
    384   // original ResourceHandler.
    385   next_handler_ = new_handler.Pass();
    386   next_handler_->SetController(this);
    387 
    388   return CopyReadBufferToNextHandler(request_id);
    389 }
    390 
    391 bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) {
    392   DCHECK(read_buffer_.get());
    393 
    394   int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
    395   bool result = next_handler_->OnReadCompleted(request_id, bytes_read_, defer);
    396 
    397   read_buffer_ = NULL;
    398   read_buffer_size_ = 0;
    399   bytes_read_ = 0;
    400 
    401   state_ = STATE_STREAMING;
    402 
    403   return result;
    404 }
    405 
    406 void BufferedResourceHandler::CallReplayReadCompleted() {
    407   bool defer = false;
    408   if (!ReplayReadCompleted(&defer)) {
    409     controller()->Cancel();
    410   } else if (!defer) {
    411     state_ = STATE_STREAMING;
    412     controller()->Resume();
    413   }
    414 }
    415 
    416 bool BufferedResourceHandler::MustDownload() {
    417   if (must_download_is_set_)
    418     return must_download_;
    419 
    420   must_download_is_set_ = true;
    421 
    422   std::string disposition;
    423   request_->GetResponseHeaderByName("content-disposition", &disposition);
    424   if (!disposition.empty() &&
    425       net::HttpContentDisposition(disposition, std::string()).is_attachment()) {
    426     must_download_ = true;
    427   } else if (host_->delegate() &&
    428              host_->delegate()->ShouldForceDownloadResource(
    429                  request_->url(), response_->head.mime_type)) {
    430     must_download_ = true;
    431   } else {
    432     must_download_ = false;
    433   }
    434 
    435   return must_download_;
    436 }
    437 
    438 bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) {
    439   ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
    440 
    441   bool allow_wildcard = false;
    442   WebPluginInfo plugin;
    443   return PluginServiceImpl::GetInstance()->GetPluginInfo(
    444       info->GetChildID(), info->GetRouteID(), info->GetContext(),
    445       request_->url(), GURL(), response_->head.mime_type, allow_wildcard,
    446       stale, &plugin, NULL);
    447 }
    448 
    449 bool BufferedResourceHandler::CopyReadBufferToNextHandler(int request_id) {
    450   if (!bytes_read_)
    451     return true;
    452 
    453   net::IOBuffer* buf = NULL;
    454   int buf_len = 0;
    455   if (!next_handler_->OnWillRead(request_id, &buf, &buf_len, bytes_read_))
    456     return false;
    457 
    458   CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
    459   memcpy(buf->data(), read_buffer_->data(), bytes_read_);
    460   return true;
    461 }
    462 
    463 void BufferedResourceHandler::OnPluginsLoaded(
    464     const std::vector<WebPluginInfo>& plugins) {
    465   bool defer = false;
    466   if (!ProcessResponse(&defer)) {
    467     controller()->Cancel();
    468   } else if (!defer) {
    469     controller()->Resume();
    470   }
    471 }
    472 
    473 }  // namespace content
    474