Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(658)

Unified Diff: chrome/browser/renderer_host/buffered_resource_handler.cc

Issue 6532073: Move core pieces of browser\renderer_host to src\content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/renderer_host/buffered_resource_handler.cc
===================================================================
--- chrome/browser/renderer_host/buffered_resource_handler.cc (revision 75488)
+++ chrome/browser/renderer_host/buffered_resource_handler.cc (working copy)
@@ -1,491 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/renderer_host/buffered_resource_handler.h"
-
-#include <vector>
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
-#include "chrome/browser/renderer_host/x509_user_cert_resource_handler.h"
-#include "chrome/common/extensions/user_script.h"
-#include "chrome/common/resource_response.h"
-#include "chrome/common/url_constants.h"
-#include "net/base/io_buffer.h"
-#include "net/base/mime_sniffer.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
-#include "webkit/plugins/npapi/plugin_list.h"
-
-namespace {
-
-void RecordSnifferMetrics(bool sniffing_blocked,
- bool we_would_like_to_sniff,
- const std::string& mime_type) {
- static scoped_refptr<base::Histogram> nosniff_usage =
- base::BooleanHistogram::FactoryGet(
- "nosniff.usage", base::Histogram::kUmaTargetedHistogramFlag);
- nosniff_usage->AddBoolean(sniffing_blocked);
-
- if (sniffing_blocked) {
- static scoped_refptr<base::Histogram> nosniff_otherwise =
- base::BooleanHistogram::FactoryGet(
- "nosniff.otherwise", base::Histogram::kUmaTargetedHistogramFlag);
- nosniff_otherwise->AddBoolean(we_would_like_to_sniff);
-
- static scoped_refptr<base::Histogram> nosniff_empty_mime_type =
- base::BooleanHistogram::FactoryGet(
- "nosniff.empty_mime_type",
- base::Histogram::kUmaTargetedHistogramFlag);
- nosniff_empty_mime_type->AddBoolean(mime_type.empty());
- }
-}
-
-} // namespace
-
-BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
- ResourceDispatcherHost* host,
- net::URLRequest* request)
- : real_handler_(handler),
- host_(host),
- request_(request),
- read_buffer_size_(0),
- bytes_read_(0),
- sniff_content_(false),
- should_buffer_(false),
- wait_for_plugins_(false),
- buffering_(false),
- finished_(false) {
-}
-
-bool BufferedResourceHandler::OnUploadProgress(int request_id,
- uint64 position,
- uint64 size) {
- return real_handler_->OnUploadProgress(request_id, position, size);
-}
-
-bool BufferedResourceHandler::OnRequestRedirected(int request_id,
- const GURL& new_url,
- ResourceResponse* response,
- bool* defer) {
- return real_handler_->OnRequestRedirected(
- request_id, new_url, response, defer);
-}
-
-bool BufferedResourceHandler::OnResponseStarted(int request_id,
- ResourceResponse* response) {
- response_ = response;
- if (!DelayResponse())
- return CompleteResponseStarted(request_id, false);
- return true;
-}
-
-bool BufferedResourceHandler::OnResponseCompleted(
- int request_id,
- const net::URLRequestStatus& status,
- const std::string& security_info) {
- return real_handler_->OnResponseCompleted(request_id, status, security_info);
-}
-
-void BufferedResourceHandler::OnRequestClosed() {
- request_ = NULL;
- real_handler_->OnRequestClosed();
-}
-
-bool BufferedResourceHandler::OnWillStart(int request_id,
- const GURL& url,
- bool* defer) {
- return real_handler_->OnWillStart(request_id, url, defer);
-}
-
-// We'll let the original event handler provide a buffer, and reuse it for
-// subsequent reads until we're done buffering.
-bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
- int* buf_size, int min_size) {
- if (buffering_) {
- DCHECK(!my_buffer_.get());
- my_buffer_ = new net::IOBuffer(net::kMaxBytesToSniff);
- *buf = my_buffer_.get();
- *buf_size = net::kMaxBytesToSniff;
- return true;
- }
-
- if (finished_)
- return false;
-
- if (!real_handler_->OnWillRead(request_id, buf, buf_size, min_size)) {
- return false;
- }
- read_buffer_ = *buf;
- read_buffer_size_ = *buf_size;
- DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
- bytes_read_ = 0;
- return true;
-}
-
-bool BufferedResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
- if (sniff_content_ || should_buffer_) {
- if (KeepBuffering(*bytes_read))
- return true;
-
- *bytes_read = bytes_read_;
-
- // Done buffering, send the pending ResponseStarted event.
- if (!CompleteResponseStarted(request_id, true))
- return false;
- } else if (wait_for_plugins_) {
- return true;
- }
-
- // Release the reference that we acquired at OnWillRead.
- read_buffer_ = NULL;
- return real_handler_->OnReadCompleted(request_id, bytes_read);
-}
-
-BufferedResourceHandler::~BufferedResourceHandler() {}
-
-bool BufferedResourceHandler::DelayResponse() {
- std::string mime_type;
- request_->GetMimeType(&mime_type);
-
- std::string content_type_options;
- request_->GetResponseHeaderByName("x-content-type-options",
- &content_type_options);
-
- const bool sniffing_blocked =
- LowerCaseEqualsASCII(content_type_options, "nosniff");
- const bool not_modified_status =
- response_->response_head.headers &&
- response_->response_head.headers->response_code() == 304;
- const bool we_would_like_to_sniff = not_modified_status ?
- false : net::ShouldSniffMimeType(request_->url(), mime_type);
-
- RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
-
- if (!sniffing_blocked && we_would_like_to_sniff) {
- // We're going to look at the data before deciding what the content type
- // is. That means we need to delay sending the ResponseStarted message
- // over the IPC channel.
- sniff_content_ = true;
- VLOG(1) << "To buffer: " << request_->url().spec();
- return true;
- }
-
- if (sniffing_blocked && mime_type.empty() && !not_modified_status) {
- // Ugg. The server told us not to sniff the content but didn't give us a
- // mime type. What's a browser to do? Turns out, we're supposed to treat
- // the response as "text/plain". This is the most secure option.
- mime_type.assign("text/plain");
- response_->response_head.mime_type.assign(mime_type);
- }
-
- if (mime_type == "application/rss+xml" ||
- mime_type == "application/atom+xml") {
- // Sad face. The server told us that they wanted us to treat the response
- // as RSS or Atom. Unfortunately, we don't have a built-in feed previewer
- // like other browsers. We can't just render the content as XML because
- // web sites let third parties inject arbitrary script into their RSS
- // feeds. That leaves us with little choice but to practically ignore the
- // response. In the future, when we have an RSS feed previewer, we can
- // remove this logic.
- mime_type.assign("text/plain");
- response_->response_head.mime_type.assign(mime_type);
- }
-
- if (ShouldBuffer(request_->url(), mime_type)) {
- // This is a temporary fix for the fact that webkit expects to have
- // enough data to decode the doctype in order to select the rendering
- // mode.
- should_buffer_ = true;
- return true;
- }
-
- if (!not_modified_status && ShouldWaitForPlugins()) {
- wait_for_plugins_ = true;
- return true;
- }
-
- return false;
-}
-
-bool BufferedResourceHandler::ShouldBuffer(const GURL& url,
- const std::string& mime_type) {
- // We are willing to buffer for HTTP and HTTPS.
- bool sniffable_scheme = url.is_empty() ||
- url.SchemeIs(chrome::kHttpScheme) ||
- url.SchemeIs(chrome::kHttpsScheme);
- if (!sniffable_scheme)
- return false;
-
- // Today, the only reason to buffer the request is to fix the doctype decoding
- // performed by webkit: if there is not enough data it will go to quirks mode.
- // We only expect the doctype check to apply to html documents.
- return mime_type == "text/html";
-}
-
-bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
- const int kRequiredLength = 256;
-
- return bytes_read >= kRequiredLength;
-}
-
-bool BufferedResourceHandler::KeepBuffering(int bytes_read) {
- DCHECK(read_buffer_);
- if (my_buffer_) {
- // We are using our own buffer to read, update the main buffer.
- // TODO(darin): We should handle the case where read_buffer_size_ is small!
- // See RedirectToFileResourceHandler::BufIsFull to see how this impairs
- // downstream ResourceHandler implementations.
- CHECK_LT(bytes_read + bytes_read_, read_buffer_size_);
- memcpy(read_buffer_->data() + bytes_read_, my_buffer_->data(), bytes_read);
- my_buffer_ = NULL;
- }
- bytes_read_ += bytes_read;
- finished_ = (bytes_read == 0);
-
- if (sniff_content_) {
- std::string type_hint, new_type;
- request_->GetMimeType(&type_hint);
-
- if (!net::SniffMimeType(read_buffer_->data(), bytes_read_,
- request_->url(), type_hint, &new_type)) {
- // SniffMimeType() returns false if there is not enough data to determine
- // the mime type. However, even if it returns false, it returns a new type
- // that is probably better than the current one.
- DCHECK_LT(bytes_read_, net::kMaxBytesToSniff);
- if (!finished_) {
- buffering_ = true;
- return true;
- }
- }
- sniff_content_ = false;
- response_->response_head.mime_type.assign(new_type);
-
- // We just sniffed the mime type, maybe there is a doctype to process.
- if (ShouldBuffer(request_->url(), new_type)) {
- should_buffer_ = true;
- } else if (ShouldWaitForPlugins()) {
- wait_for_plugins_ = true;
- }
- }
-
- if (should_buffer_) {
- if (!finished_ && !DidBufferEnough(bytes_read_)) {
- buffering_ = true;
- return true;
- }
-
- should_buffer_ = false;
- if (ShouldWaitForPlugins())
- wait_for_plugins_ = true;
- }
-
- buffering_ = false;
-
- if (wait_for_plugins_)
- return true;
-
- return false;
-}
-
-bool BufferedResourceHandler::CompleteResponseStarted(int request_id,
- bool in_complete) {
- ResourceDispatcherHostRequestInfo* info =
- ResourceDispatcherHost::InfoForRequest(request_);
- std::string mime_type;
- request_->GetMimeType(&mime_type);
-
- // Check if this is an X.509 certificate, if yes, let it be handled
- // by X509UserCertResourceHandler.
- if (mime_type == "application/x-x509-user-cert") {
- // This is entirely similar to how DownloadThrottlingResourceHandler
- // works except we are doing it for an X.509 client certificates.
-
- if (response_->response_head.headers && // Can be NULL if FTP.
- response_->response_head.headers->response_code() / 100 != 2) {
- // The response code indicates that this is an error page, but we are
- // expecting an X.509 user certificate. We follow Firefox here and show
- // our own error page instead of handling the error page as a
- // certificate.
- // TODO(abarth): We should abstract the response_code test, but this kind
- // of check is scattered throughout our codebase.
- request_->SimulateError(net::ERR_FILE_NOT_FOUND);
- return false;
- }
-
- X509UserCertResourceHandler* x509_cert_handler =
- new X509UserCertResourceHandler(host_, request_,
- info->child_id(), info->route_id());
- UseAlternateResourceHandler(request_id, x509_cert_handler);
- }
-
- // Check to see if we should forward the data from this request to the
- // download thread.
- // TODO(paulg): Only download if the context from the renderer allows it.
- if (info->allow_download() && ShouldDownload(NULL)) {
- if (response_->response_head.headers && // Can be NULL if FTP.
- response_->response_head.headers->response_code() / 100 != 2) {
- // The response code indicates that this is an error page, but we don't
- // know how to display the content. We follow Firefox here and show our
- // own error page instead of triggering a download.
- // TODO(abarth): We should abstract the response_code test, but this kind
- // of check is scattered throughout our codebase.
- request_->SimulateError(net::ERR_FILE_NOT_FOUND);
- return false;
- }
-
- info->set_is_download(true);
-
- DownloadThrottlingResourceHandler* download_handler =
- new DownloadThrottlingResourceHandler(host_,
- request_,
- request_->url(),
- info->child_id(),
- info->route_id(),
- request_id,
- in_complete);
- UseAlternateResourceHandler(request_id, download_handler);
- }
- return real_handler_->OnResponseStarted(request_id, response_);
-}
-
-bool BufferedResourceHandler::ShouldWaitForPlugins() {
- bool need_plugin_list;
- if (!ShouldDownload(&need_plugin_list) || !need_plugin_list)
- return false;
-
- // We don't want to keep buffering as our buffer will fill up.
- ResourceDispatcherHostRequestInfo* info =
- ResourceDispatcherHost::InfoForRequest(request_);
- host_->PauseRequest(info->child_id(), info->request_id(), true);
-
- // Schedule plugin loading on the file thread.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &BufferedResourceHandler::LoadPlugins));
- return true;
-}
-
-// This test mirrors the decision that WebKit makes in
-// WebFrameLoaderClient::dispatchDecidePolicyForMIMEType.
-bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
- if (need_plugin_list)
- *need_plugin_list = false;
- std::string type = StringToLowerASCII(response_->response_head.mime_type);
- std::string disposition;
- request_->GetResponseHeaderByName("content-disposition", &disposition);
- disposition = StringToLowerASCII(disposition);
-
- // First, examine content-disposition.
- if (!disposition.empty()) {
- bool should_download = true;
-
- // Some broken sites just send ...
- // Content-Disposition: ; filename="file"
- // ... screen those out here.
- if (disposition[0] == ';')
- should_download = false;
-
- if (disposition.compare(0, 6, "inline") == 0)
- should_download = false;
-
- // Some broken sites just send ...
- // Content-Disposition: filename="file"
- // ... without a disposition token... Screen those out.
- if (disposition.compare(0, 8, "filename") == 0)
- should_download = false;
-
- // Also in use is Content-Disposition: name="file"
- if (disposition.compare(0, 4, "name") == 0)
- should_download = false;
-
- // We have a content-disposition of "attachment" or unknown.
- // RFC 2183, section 2.8 says that an unknown disposition
- // value should be treated as "attachment".
- if (should_download)
- return true;
- }
-
- // Special-case user scripts to get downloaded instead of viewed.
- if (UserScript::HasUserScriptFileExtension(request_->url()))
- return true;
-
- // MIME type checking.
- if (net::IsSupportedMimeType(type))
- return false;
-
- if (need_plugin_list) {
- if (!webkit::npapi::PluginList::Singleton()->PluginsLoaded()) {
- *need_plugin_list = true;
- return true;
- }
- } else {
- DCHECK(webkit::npapi::PluginList::Singleton()->PluginsLoaded());
- }
-
- // Finally, check the plugin list.
- webkit::npapi::WebPluginInfo info;
- bool allow_wildcard = false;
- return !webkit::npapi::PluginList::Singleton()->GetPluginInfo(
- GURL(), type, allow_wildcard, &info, NULL) ||
- !webkit::npapi::IsPluginEnabled(info);
-}
-
-void BufferedResourceHandler::UseAlternateResourceHandler(
- int request_id,
- ResourceHandler* handler) {
- ResourceDispatcherHostRequestInfo* info =
- ResourceDispatcherHost::InfoForRequest(request_);
- if (bytes_read_) {
- // A Read has already occured and we need to copy the data into the new
- // ResourceHandler.
- net::IOBuffer* buf = NULL;
- int buf_len = 0;
- handler->OnWillRead(request_id, &buf, &buf_len, bytes_read_);
- CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
- memcpy(buf->data(), read_buffer_->data(), bytes_read_);
- }
-
- // Inform the original ResourceHandler that this will be handled entirely by
- // the new ResourceHandler.
- real_handler_->OnResponseStarted(info->request_id(), response_);
- net::URLRequestStatus status(net::URLRequestStatus::HANDLED_EXTERNALLY, 0);
- real_handler_->OnResponseCompleted(info->request_id(), status, std::string());
-
- // Remove the non-owning pointer to the CrossSiteResourceHandler, if any,
- // from the extra request info because the CrossSiteResourceHandler (part of
- // the original ResourceHandler chain) will be deleted by the next statement.
- info->set_cross_site_handler(NULL);
-
- // This is handled entirely within the new ResourceHandler, so just reset the
- // original ResourceHandler.
- real_handler_ = handler;
-}
-
-void BufferedResourceHandler::LoadPlugins() {
- std::vector<webkit::npapi::WebPluginInfo> plugins;
- webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &BufferedResourceHandler::OnPluginsLoaded));
-}
-
-void BufferedResourceHandler::OnPluginsLoaded() {
- wait_for_plugins_ = false;
- if (!request_)
- return;
-
- ResourceDispatcherHostRequestInfo* info =
- ResourceDispatcherHost::InfoForRequest(request_);
- host_->PauseRequest(info->child_id(), info->request_id(), false);
- if (!CompleteResponseStarted(info->request_id(), false))
- host_->CancelRequest(info->child_id(), info->request_id(), false);
-}

Powered by Google App Engine
This is Rietveld 408576698