Add more robust download handler implementation (issue #156).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@155 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
99a1d4ac58
commit
a99e32072e
|
@ -4,14 +4,14 @@
|
|||
// found in the LICENSE file.
|
||||
//
|
||||
// This file contains an implementation of the ResourceLoaderBridge class.
|
||||
// The class is implemented using net::URLRequest, meaning it is a "simple" version
|
||||
// that directly issues requests. The more complicated one used in the
|
||||
// The class is implemented using net::URLRequest, meaning it is a "simple"
|
||||
// version that directly issues requests. The more complicated one used in the
|
||||
// browser uses IPC.
|
||||
//
|
||||
// Because net::URLRequest only provides an asynchronous resource loading API, this
|
||||
// file makes use of net::URLRequest from a background IO thread. Requests for
|
||||
// cookies and synchronously loaded resources result in the main thread of the
|
||||
// application blocking until the IO thread completes the operation. (See
|
||||
// Because net::URLRequest only provides an asynchronous resource loading API,
|
||||
// this file makes use of net::URLRequest from a background IO thread. Requests
|
||||
// for cookies and synchronously loaded resources result in the main thread of
|
||||
// the application blocking until the IO thread completes the operation. (See
|
||||
// GetCookies and SyncLoad)
|
||||
//
|
||||
// Main thread IO thread
|
||||
|
@ -100,9 +100,26 @@ struct RequestParams {
|
|||
// The interval for calls to RequestProxy::MaybeUpdateUploadProgress
|
||||
static const int kUpdateUploadProgressIntervalMsec = 100;
|
||||
|
||||
class ExtraRequestInfo : public net::URLRequest::UserData {
|
||||
public:
|
||||
ExtraRequestInfo(ResourceType::Type resource_type)
|
||||
: resource_type_(resource_type),
|
||||
allow_download_(resource_type == ResourceType::MAIN_FRAME ||
|
||||
resource_type == ResourceType::SUB_FRAME)
|
||||
{ }
|
||||
|
||||
// Identifies the type of resource, such as subframe, media, etc.
|
||||
ResourceType::Type resource_type() const { return resource_type_; }
|
||||
bool allow_download() const { return allow_download_; }
|
||||
|
||||
private:
|
||||
ResourceType::Type resource_type_;
|
||||
bool allow_download_;
|
||||
};
|
||||
|
||||
// The RequestProxy does most of its work on the IO thread. The Start and
|
||||
// Cancel methods are proxied over to the IO thread, where an net::URLRequest object
|
||||
// is instantiated.
|
||||
// Cancel methods are proxied over to the IO thread, where an net::URLRequest
|
||||
// object is instantiated.
|
||||
class RequestProxy : public net::URLRequest::Delegate,
|
||||
public base::RefCountedThreadSafe<RequestProxy> {
|
||||
public:
|
||||
|
@ -168,18 +185,26 @@ class RequestProxy : public net::URLRequest::Delegate,
|
|||
}
|
||||
|
||||
void NotifyReceivedResponse(const ResourceResponseInfo& info,
|
||||
bool content_filtered) {
|
||||
std::string cd_header, filename;
|
||||
if (info.headers && browser_.get() &&
|
||||
info.headers->GetNormalizedHeader("Content-Disposition", &cd_header) &&
|
||||
webkit_glue::IsContentDispositionAttachment(cd_header, filename)) {
|
||||
// The response represents a download request.
|
||||
bool content_filtered,
|
||||
const GURL& url, bool allow_download) {
|
||||
|
||||
if (browser_.get() && info.headers.get()) {
|
||||
CefRefPtr<CefHandler> handler = browser_->GetHandler();
|
||||
if (handler.get()) {
|
||||
CefRefPtr<CefDownloadHandler> dl_handler;
|
||||
if (handler->HandleDownloadResponse(browser_, info.mime_type, filename,
|
||||
info.content_length, dl_handler) == RV_CONTINUE) {
|
||||
download_handler_ = dl_handler;
|
||||
std::string content_disposition;
|
||||
info.headers->GetNormalizedHeader("Content-Disposition",
|
||||
&content_disposition);
|
||||
|
||||
if (allow_download &&
|
||||
webkit_glue::ShouldDownload(content_disposition, info.mime_type)) {
|
||||
FilePath path(net::GetSuggestedFilename(url, content_disposition,
|
||||
info.charset, FilePath(L"download")));
|
||||
CefRefPtr<CefDownloadHandler> dl_handler;
|
||||
if (handler->HandleDownloadResponse(browser_, info.mime_type,
|
||||
path.value(), info.content_length, dl_handler) ==
|
||||
RV_CONTINUE) {
|
||||
download_handler_ = dl_handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +284,8 @@ class RequestProxy : public net::URLRequest::Delegate,
|
|||
{
|
||||
// Build the request object for passing to the handler
|
||||
CefRefPtr<CefRequest> request(new CefRequestImpl());
|
||||
CefRequestImpl* requestimpl = static_cast<CefRequestImpl*>(request.get());
|
||||
CefRequestImpl* requestimpl =
|
||||
static_cast<CefRequestImpl*>(request.get());
|
||||
|
||||
std::string originalUrl(params->url.spec());
|
||||
requestimpl->SetURL(originalUrl);
|
||||
|
@ -370,6 +396,7 @@ class RequestProxy : public net::URLRequest::Delegate,
|
|||
request_->set_load_flags(params->load_flags);
|
||||
request_->set_upload(params->upload.get());
|
||||
request_->set_context(_Context->request_context());
|
||||
request_->SetUserData(NULL, new ExtraRequestInfo(params->request_type));
|
||||
BrowserAppCacheSystem::SetExtraRequestInfo(
|
||||
request_.get(), params->appcache_host_id, params->request_type);
|
||||
|
||||
|
@ -389,7 +416,8 @@ class RequestProxy : public net::URLRequest::Delegate,
|
|||
if (request_->has_upload() &&
|
||||
params->load_flags & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
|
||||
upload_progress_timer_.Start(
|
||||
base::TimeDelta::FromMilliseconds(kUpdateUploadProgressIntervalMsec),
|
||||
base::TimeDelta::FromMilliseconds(
|
||||
kUpdateUploadProgressIntervalMsec),
|
||||
this, &RequestProxy::MaybeUpdateUploadProgress);
|
||||
}
|
||||
}
|
||||
|
@ -463,8 +491,19 @@ class RequestProxy : public net::URLRequest::Delegate,
|
|||
virtual void OnReceivedResponse(
|
||||
const ResourceResponseInfo& info,
|
||||
bool content_filtered) {
|
||||
GURL url;
|
||||
bool allow_download(false);
|
||||
if (request_.get()){
|
||||
url = request_->url();
|
||||
ExtraRequestInfo* info =
|
||||
static_cast<ExtraRequestInfo*>(request_->GetUserData(NULL));
|
||||
if (info)
|
||||
allow_download = info->allow_download();
|
||||
}
|
||||
|
||||
owner_loop_->PostTask(FROM_HERE, NewRunnableMethod(
|
||||
this, &RequestProxy::NotifyReceivedResponse, info, content_filtered));
|
||||
this, &RequestProxy::NotifyReceivedResponse, info, content_filtered,
|
||||
url, allow_download));
|
||||
}
|
||||
|
||||
virtual void OnReceivedData(int bytes_read) {
|
||||
|
@ -550,8 +589,8 @@ class RequestProxy : public net::URLRequest::Delegate,
|
|||
|
||||
// Called on the IO thread.
|
||||
void MaybeUpdateUploadProgress() {
|
||||
// If a redirect is received upload is cancelled in net::URLRequest, we should
|
||||
// try to stop the |upload_progress_timer_| timer and return.
|
||||
// If a redirect is received upload is cancelled in net::URLRequest, we
|
||||
// should try to stop the |upload_progress_timer_| timer and return.
|
||||
if (!request_->has_upload()) {
|
||||
if (upload_progress_timer_.IsRunning())
|
||||
upload_progress_timer_.Stop();
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
MSVC_PUSH_WARNING_LEVEL(0);
|
||||
#include "MemoryCache.h"
|
||||
#include "TextEncoding.h"
|
||||
#include "third_party/WebKit/WebCore/platform/network/HTTPParsers.h"
|
||||
#include "third_party/WebKit/WebKit/chromium/src/WebFrameImpl.h"
|
||||
MSVC_POP_WARNING();
|
||||
#undef LOG
|
||||
#include "base/string_util.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "webkit/glue/plugins/plugin_list.h"
|
||||
|
||||
#include "browser_webkit_glue.h"
|
||||
|
||||
|
@ -136,20 +139,52 @@ void EnableSpdy(bool enable) {
|
|||
// Used in benchmarking, Ignored for CEF.
|
||||
}
|
||||
|
||||
bool IsContentDispositionAttachment(const std::string& cd_header,
|
||||
std::string& file_name) {
|
||||
WTF::String cd_str(cd_header.c_str(), cd_header.length());
|
||||
if (WebCore::contentDispositionType(cd_str) ==
|
||||
WebCore::ContentDispositionAttachment) {
|
||||
WTF::String name_str =
|
||||
WebCore::filenameFromHTTPContentDisposition(cd_str);
|
||||
if (!name_str.isEmpty()) {
|
||||
WTF::CString cstr(name_str.utf8());
|
||||
file_name = std::string(cstr.data(), cstr.length());
|
||||
}
|
||||
return true;
|
||||
// Adapted from Chromium's BufferedResourceHandler::ShouldDownload
|
||||
bool ShouldDownload(const std::string& content_disposition,
|
||||
const std::string& mime_type)
|
||||
{
|
||||
std::string type = StringToLowerASCII(mime_type);
|
||||
std::string disposition = StringToLowerASCII(content_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;
|
||||
}
|
||||
return false;
|
||||
|
||||
// Mirrors WebViewImpl::CanShowMIMEType()
|
||||
if (type.empty() || net::IsSupportedMimeType(type))
|
||||
return false;
|
||||
|
||||
//// Finally, check the plugin list.
|
||||
WebPluginInfo info;
|
||||
bool allow_wildcard = false;
|
||||
return !NPAPI::PluginList::Singleton()->GetPluginInfo(
|
||||
GURL(), type, allow_wildcard, &info, NULL) || !info.enabled;
|
||||
}
|
||||
|
||||
} // namespace webkit_glue
|
||||
|
|
|
@ -42,9 +42,9 @@ v8::Handle<v8::Context> GetV8Context(WebKit::WebFrame* frame);
|
|||
// Clear all cached data.
|
||||
void ClearCache();
|
||||
|
||||
// Returns true if the specified 'Content-Disposition' header value represents
|
||||
// an attachment download. Also returns the file name.
|
||||
bool IsContentDispositionAttachment(const std::string& cd_header,
|
||||
std::string& file_name);
|
||||
// Returns true if the request represents a download based on
|
||||
// the supplied Content-Type and Content-Disposition headers.
|
||||
bool ShouldDownload(const std::string& content_disposition,
|
||||
const std::string& mime_type);
|
||||
|
||||
} // namespace webkit_glue
|
||||
|
|
Loading…
Reference in New Issue