summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorellyjones@chromium.org <ellyjones@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-22 00:46:57 +0000
committerellyjones@chromium.org <ellyjones@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-22 00:46:57 +0000
commit262191714589043d5b2dc3c7030b044787712047 (patch)
tree1a9e2103319557ab6cfd8f6f2507202bc8c70f69
parent03cc8854790c813eeffe9bce4882b50720f2cdb6 (diff)
downloadchromium_src-262191714589043d5b2dc3c7030b044787712047.zip
chromium_src-262191714589043d5b2dc3c7030b044787712047.tar.gz
chromium_src-262191714589043d5b2dc3c7030b044787712047.tar.bz2
Fix content-encoding handling with buggy servers.
Some servers will serve compressed filetypes with "content-encoding: gzip" because the file's contents were gzipped, even though the server is not re-encoding the contents at all. The code in Filter::FixupEncodingTypes() attempts to work around this by inferring whether the file is a gzip file with bogus encoding based on the file extension in the URL, but this doesn't work when the file being downloaded comes from a page whose extension doesn't reveal the downloaded file type. This change adds code to FixupEncodingTypes to also consider the download filename, supplied by the "content-disposition" header, if any. This means that we now behave correctly in the case where: -> GET /foo.php?download <- HTTP/1.1 200 OK <- ... <- Content-Disposition: attachment;filename="foo.tar.gz" <- ... <- Content-Encoding: gzip BUG=83292 TEST=unit,trybot Review URL: https://codereview.chromium.org/206503006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@258729 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/filter/filter.cc10
-rw-r--r--net/filter/filter.h4
-rw-r--r--net/filter/filter_unittest.cc17
-rw-r--r--net/filter/mock_filter_context.cc7
-rw-r--r--net/filter/mock_filter_context.h8
-rw-r--r--net/url_request/url_request_http_job.cc9
6 files changed, 52 insertions, 3 deletions
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index 244abae..90d91e1 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -8,6 +8,7 @@
#include "base/strings/string_util.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_util.h"
+#include "net/base/net_util.h"
#include "net/filter/gzip_filter.h"
#include "net/filter/sdch_filter.h"
@@ -170,11 +171,14 @@ void Filter::FixupEncodingTypes(
encoding_types->clear();
GURL url;
+ std::string disposition;
success = filter_context.GetURL(&url);
DCHECK(success);
- base::FilePath filename =
- base::FilePath().AppendASCII(url.ExtractFileName());
- base::FilePath::StringType extension = filename.Extension();
+ filter_context.GetContentDisposition(&disposition);
+ // Don't supply a MIME type here, since that may cause disk IO.
+ base::FilePath filepath = GenerateFileName(url, disposition, "UTF-8", "",
+ "", "");
+ base::FilePath::StringType extension = filepath.Extension();
if (filter_context.IsDownload()) {
// We don't want to decompress gzipped files when the user explicitly
diff --git a/net/filter/filter.h b/net/filter/filter.h
index 1b4d2f5..8189099 100644
--- a/net/filter/filter.h
+++ b/net/filter/filter.h
@@ -74,6 +74,10 @@ class NET_EXPORT_PRIVATE FilterContext {
// Return false if gurl is not present.
virtual bool GetURL(GURL* gurl) const = 0;
+ // What Content-Disposition header came with this data?
+ // Return false if no header was present.
+ virtual bool GetContentDisposition(std::string* disposition) const = 0;
+
// When was this data requested from a server?
virtual base::Time GetRequestTime() const = 0;
diff --git a/net/filter/filter_unittest.cc b/net/filter/filter_unittest.cc
index 3b91252..08a286169 100644
--- a/net/filter/filter_unittest.cc
+++ b/net/filter/filter_unittest.cc
@@ -82,6 +82,23 @@ TEST(FilterTest, ApacheGzip) {
EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
}
+TEST(FilterTest, GzipContentDispositionFilename) {
+ MockFilterContext filter_context;
+ filter_context.SetSdchResponse(false);
+
+ const std::string kGzipMime("application/x-tar");
+ const std::string kContentDisposition("attachment; filename=\"foo.tgz\"");
+ const std::string kURL("http://foo.com/getfoo.php");
+ std::vector<Filter::FilterType> encoding_types;
+
+ encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
+ filter_context.SetMimeType(kGzipMime);
+ filter_context.SetURL(GURL(kURL));
+ filter_context.SetContentDisposition(kContentDisposition);
+ Filter::FixupEncodingTypes(filter_context, &encoding_types);
+ ASSERT_EQ(0U, encoding_types.size());
+}
+
TEST(FilterTest, SdchEncoding) {
// Handle content encodings including SDCH.
const std::string kTextHtmlMime("text/html");
diff --git a/net/filter/mock_filter_context.cc b/net/filter/mock_filter_context.cc
index ec6db0111..06905c0 100644
--- a/net/filter/mock_filter_context.cc
+++ b/net/filter/mock_filter_context.cc
@@ -27,6 +27,13 @@ bool MockFilterContext::GetURL(GURL* gurl) const {
return true;
}
+bool MockFilterContext::GetContentDisposition(std::string* disposition) const {
+ if (content_disposition_.empty())
+ return false;
+ *disposition = content_disposition_;
+ return true;
+}
+
// What was this data requested from a server?
base::Time MockFilterContext::GetRequestTime() const {
return request_time_;
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h
index 00fc8ed..21e56ac 100644
--- a/net/filter/mock_filter_context.h
+++ b/net/filter/mock_filter_context.h
@@ -19,6 +19,9 @@ class MockFilterContext : public FilterContext {
void SetMimeType(const std::string& mime_type) { mime_type_ = mime_type; }
void SetURL(const GURL& gurl) { gurl_ = gurl; }
+ void SetContentDisposition(const std::string& disposition) {
+ content_disposition_ = disposition;
+ }
void SetRequestTime(const base::Time time) { request_time_ = time; }
void SetCached(bool is_cached) { is_cached_content_ = is_cached; }
void SetDownload(bool is_download) { is_download_ = is_download; }
@@ -33,6 +36,10 @@ class MockFilterContext : public FilterContext {
// Return false if gurl is not present.
virtual bool GetURL(GURL* gurl) const OVERRIDE;
+ // What Content-Disposition did the server supply for this data?
+ // Return false if Content-Disposition was not present.
+ virtual bool GetContentDisposition(std::string* disposition) const OVERRIDE;
+
// What was this data requested from a server?
virtual base::Time GetRequestTime() const OVERRIDE;
@@ -55,6 +62,7 @@ class MockFilterContext : public FilterContext {
private:
int buffer_size_;
std::string mime_type_;
+ std::string content_disposition_;
GURL gurl_;
base::Time request_time_;
bool is_cached_content_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 7207777..dbbd4e2 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -25,6 +25,7 @@
#include "net/base/sdch_manager.h"
#include "net/cert/cert_status_flags.h"
#include "net/cookies/cookie_monster.h"
+#include "net/http/http_content_disposition.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
@@ -58,6 +59,7 @@ class URLRequestHttpJob::HttpFilterContext : public FilterContext {
// FilterContext implementation.
virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
virtual bool GetURL(GURL* gurl) const OVERRIDE;
+ virtual bool GetContentDisposition(std::string* disposition) const OVERRIDE;
virtual base::Time GetRequestTime() const OVERRIDE;
virtual bool IsCachedContent() const OVERRIDE;
virtual bool IsDownload() const OVERRIDE;
@@ -96,6 +98,13 @@ bool URLRequestHttpJob::HttpFilterContext::GetURL(GURL* gurl) const {
return true;
}
+bool URLRequestHttpJob::HttpFilterContext::GetContentDisposition(
+ std::string* disposition) const {
+ HttpResponseHeaders* headers = job_->GetResponseHeaders();
+ void *iter = NULL;
+ return headers->EnumerateHeader(&iter, "Content-Disposition", disposition);
+}
+
base::Time URLRequestHttpJob::HttpFilterContext::GetRequestTime() const {
return job_->request() ? job_->request()->request_time() : base::Time();
}