| Index: chrome/browser/renderer_host/buffered_resource_handler.cc
|
| ===================================================================
|
| --- chrome/browser/renderer_host/buffered_resource_handler.cc (revision 23449)
|
| +++ chrome/browser/renderer_host/buffered_resource_handler.cc (working copy)
|
| @@ -9,12 +9,15 @@
|
| #include "base/string_util.h"
|
| #include "net/base/mime_sniffer.h"
|
| #include "net/base/net_errors.h"
|
| +#include "chrome/browser/chrome_thread.h"
|
| #include "chrome/browser/renderer_host/download_throttling_resource_handler.h"
|
| #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
|
| #include "chrome/common/url_constants.h"
|
| #include "net/base/mime_sniffer.h"
|
| +#include "net/base/mime_util.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/http/http_response_headers.h"
|
| +#include "webkit/glue/plugins/plugin_list.h"
|
|
|
| namespace {
|
|
|
| @@ -49,6 +52,7 @@
|
| bytes_read_(0),
|
| sniff_content_(false),
|
| should_buffer_(false),
|
| + wait_for_plugins_(false),
|
| buffering_(false),
|
| finished_(false) {
|
| }
|
| @@ -75,7 +79,6 @@
|
| return true;
|
| }
|
|
|
| -
|
| bool BufferedResourceHandler::OnResponseCompleted(
|
| int request_id,
|
| const URLRequestStatus& status,
|
| @@ -83,6 +86,11 @@
|
| return real_handler_->OnResponseCompleted(request_id, status, security_info);
|
| }
|
|
|
| +void BufferedResourceHandler::OnRequestClosed() {
|
| + request_ = NULL;
|
| + real_handler_->OnRequestClosed();
|
| +}
|
| +
|
| // 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,
|
| @@ -118,12 +126,13 @@
|
| return true;
|
|
|
| LOG(INFO) << "Finished buffering " << request_->url().spec();
|
| - sniff_content_ = should_buffer_ = false;
|
| *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.
|
| @@ -171,6 +180,12 @@
|
| LOG(INFO) << "To buffer: " << request_->url().spec();
|
| return true;
|
| }
|
| +
|
| + if (ShouldWaitForPlugins()) {
|
| + wait_for_plugins_ = true;
|
| + return true;
|
| + }
|
| +
|
| return false;
|
| }
|
|
|
| @@ -189,6 +204,12 @@
|
| 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_) {
|
| @@ -219,17 +240,29 @@
|
| 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))
|
| + if (ShouldBuffer(request_->url(), new_type)) {
|
| should_buffer_ = true;
|
| + } else if (ShouldWaitForPlugins()) {
|
| + wait_for_plugins_ = true;
|
| + }
|
| }
|
|
|
| - if (!finished_ && should_buffer_) {
|
| - if (!DidBufferEnough(bytes_read_)) {
|
| + 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;
|
| }
|
|
|
| @@ -238,16 +271,10 @@
|
| // 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.
|
| - std::string content_disposition;
|
| - request_->GetResponseHeaderByName("content-disposition",
|
| - &content_disposition);
|
| -
|
| ResourceDispatcherHost::ExtraRequestInfo* info =
|
| ResourceDispatcherHost::ExtraInfoForRequest(request_);
|
|
|
| - if (info->allow_download &&
|
| - host_->ShouldDownload(response_->response_head.mime_type,
|
| - content_disposition)) {
|
| + 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
|
| @@ -293,8 +320,97 @@
|
| return real_handler_->OnResponseStarted(request_id, response_);
|
| }
|
|
|
| -bool BufferedResourceHandler::DidBufferEnough(int bytes_read) {
|
| - const int kRequiredLength = 256;
|
| +bool BufferedResourceHandler::ShouldWaitForPlugins() {
|
| + bool need_plugin_list;
|
| + if (!ShouldDownload(&need_plugin_list) || !need_plugin_list)
|
| + return false;
|
|
|
| - return bytes_read >= kRequiredLength;
|
| + // We don't want to keep buffering as our buffer will fill up.
|
| + ResourceDispatcherHost::ExtraRequestInfo* info =
|
| + ResourceDispatcherHost::ExtraInfoForRequest(request_);
|
| + host_->PauseRequest(info->process_id, info->request_id, true);
|
| +
|
| + // Schedule plugin loading on the file thread.
|
| + ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(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;
|
| + }
|
| +
|
| + // MIME type checking.
|
| + if (net::IsSupportedMimeType(type))
|
| + return false;
|
| +
|
| + if (need_plugin_list) {
|
| + if (!NPAPI::PluginList::Singleton()->PluginsLoaded()) {
|
| + *need_plugin_list = true;
|
| + return true;
|
| + }
|
| + } else {
|
| + DCHECK(NPAPI::PluginList::Singleton()->PluginsLoaded());
|
| + }
|
| +
|
| + // Finally, check the plugin list.
|
| + WebPluginInfo info;
|
| + bool allow_wildcard = false;
|
| + return !NPAPI::PluginList::Singleton()->GetPluginInfo(
|
| + GURL(), type, "", allow_wildcard, &info, NULL);
|
| +}
|
| +
|
| +void BufferedResourceHandler::LoadPlugins() {
|
| + std::vector<WebPluginInfo> plugins;
|
| + NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
|
| + ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE,
|
| + NewRunnableMethod(this, &BufferedResourceHandler::OnPluginsLoaded));
|
| +}
|
| +
|
| +void BufferedResourceHandler::OnPluginsLoaded() {
|
| + wait_for_plugins_ = false;
|
| + if (!request_)
|
| + return;
|
| +
|
| + ResourceDispatcherHost::ExtraRequestInfo* info =
|
| + ResourceDispatcherHost::ExtraInfoForRequest(request_);
|
| + host_->PauseRequest(info->process_id, info->request_id, false);
|
| + if (!CompleteResponseStarted(info->request_id, false))
|
| + host_->CancelRequest(info->process_id, info->request_id, false);
|
| +}
|
|
|