diff options
author | jungshik@google.com <jungshik@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-01 22:51:50 +0000 |
---|---|---|
committer | jungshik@google.com <jungshik@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-01 22:51:50 +0000 |
commit | c9825a4d401b014d89534020c8cf93302efd398c (patch) | |
tree | dcc654d12d5f538c2507f5f0b920cac091fe1a89 /net | |
parent | 36c165e203d4ddf415c29b865b4c13f0b9f32d38 (diff) | |
download | chromium_src-c9825a4d401b014d89534020c8cf93302efd398c.zip chromium_src-c9825a4d401b014d89534020c8cf93302efd398c.tar.gz chromium_src-c9825a4d401b014d89534020c8cf93302efd398c.tar.bz2 |
This CL makes Chrome on par with Firefox in terms of 'GetSuggestedFilename' for file download via context-menu.
For a download initiated with a click on a link in a web page, a webkit-side change is necessary, which will be done later.
Add a field (referrer_charset) to URLRequestContext and DownloadCreateInfo. It's set to the character encoding of a document where the download request originates from when it's known (download initiated via "save as" in the context menu).
If it's not known (a download initiated by clicking on a download link or typing a url directly to the omnibox), it's initialized to the default character encoding in the user's preference. I guess this is marginally better than leaving it empty (in that case, step 2b below will be skipped and step 2c will be taken) because a user has a better control over how raw 8bit characters in C-D are interpreted (especially on Windows where a reboot is required to change the OS default codepage).
This is later passed to GetSuggestedFilename and used as one of fallback encodings (1. UTF-8, 2. origin_charset, 3. default OS codepage). With this change, we support the following:
1. RFC 2047
2. Raw-8bit-characters : a. UTF-8, b. origin_charset, c. default os codepage.
3. %-escaped UTF-8.
In this CL, for #3, I didn't add a fallback similar to one used for #2. If necessary, it can be added easily. New entries are added to 3 existing tests. What's previously not covered (raw 8bit Content-Disposition header) is now covered in all 3 tests.
BUG=1148
TEST=net unit test: NetUtilTest.GetFileNameFromCD
NetUtilTest.GetSuggestedFilename
unittest : DownloadManagerTest.TestDownloadFilename
Review URL: http://codereview.chromium.org/83002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15113 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_util.cc | 38 | ||||
-rw-r--r-- | net/base/net_util.h | 31 | ||||
-rw-r--r-- | net/base/net_util_unittest.cc | 188 | ||||
-rw-r--r-- | net/url_request/url_request_context.h | 11 |
4 files changed, 174 insertions, 94 deletions
diff --git a/net/base/net_util.cc b/net/base/net_util.cc index 9610e40..e5c53eb 100644 --- a/net/base/net_util.cc +++ b/net/base/net_util.cc @@ -247,17 +247,22 @@ bool DecodeBQEncoding(const std::string& part, RFC2047EncodingType enc_type, } bool DecodeWord(const std::string& encoded_word, + const std::string& referrer_charset, bool *is_rfc2047, std::string* output) { - // TODO(jungshik) : Revisit this later. Do we want to pass through non-ASCII - // strings which can be mozibake? WinHTTP converts a raw 8bit string - // UTF-16 assuming it's in the OS default encoding. if (!IsStringASCII(encoded_word)) { - // Try falling back to the NativeMB encoding if the raw input is not UTF-8. + // Try UTF-8, referrer_charset and the native OS default charset in turn. if (IsStringUTF8(encoded_word)) { *output = encoded_word; } else { - *output = WideToUTF8(base::SysNativeMBToWide(encoded_word)); + std::wstring wide_output; + if (!referrer_charset.empty() && + CodepageToWide(encoded_word, referrer_charset.c_str(), + OnStringUtilConversionError::FAIL, &wide_output)) { + *output = WideToUTF8(wide_output); + } else { + *output = WideToUTF8(base::SysNativeMBToWide(encoded_word)); + } } *is_rfc2047 = false; return true; @@ -357,7 +362,9 @@ bool DecodeWord(const std::string& encoded_word, return false; } -bool DecodeParamValue(const std::string& input, std::string* output) { +bool DecodeParamValue(const std::string& input, + const std::string& referrer_charset, + std::string* output) { std::string tmp; // Tokenize with whitespace characters. StringTokenizer t(input, " \t\n\r"); @@ -378,7 +385,8 @@ bool DecodeParamValue(const std::string& input, std::string* output) { // in a single encoded-word. Firefox/Thunderbird do not support // it, either. std::string decoded; - if (!DecodeWord(t.token(), &is_previous_token_rfc2047, &decoded)) + if (!DecodeWord(t.token(), referrer_charset, &is_previous_token_rfc2047, + &decoded)) return false; tmp.append(decoded); } @@ -683,7 +691,8 @@ std::string GetSpecificHeader(const std::string& headers, return GetSpecificHeaderT(headers, name); } -std::wstring GetFileNameFromCD(const std::string& header) { +std::wstring GetFileNameFromCD(const std::string& header, + const std::string& referrer_charset) { std::string param_value = GetHeaderParamValue(header, "filename"); if (param_value.empty()) { // Some servers use 'name' parameter. @@ -692,7 +701,7 @@ std::wstring GetFileNameFromCD(const std::string& header) { if (param_value.empty()) return std::wstring(); std::string decoded; - if (DecodeParamValue(param_value, &decoded)) + if (DecodeParamValue(param_value, referrer_charset, &decoded)) return UTF8ToWide(decoded); return std::wstring(); } @@ -863,8 +872,10 @@ std::wstring StripWWW(const std::wstring& text) { std::wstring GetSuggestedFilename(const GURL& url, const std::string& content_disposition, + const std::string& referrer_charset, const std::wstring& default_name) { - std::wstring filename = GetFileNameFromCD(content_disposition); + std::wstring filename = GetFileNameFromCD(content_disposition, + referrer_charset); if (!filename.empty()) { // Remove any path information the server may have sent, take the name // only. @@ -901,13 +912,6 @@ std::wstring GetSuggestedFilename(const GURL& url, return filename; } -std::wstring GetSuggestedFilename(const GURL& url, - const std::wstring& content_disposition, - const std::wstring& default_name) { - return GetSuggestedFilename( - url, WideToUTF8(content_disposition), default_name); -} - bool IsPortAllowedByDefault(int port) { int array_size = arraysize(kRestrictedPorts); for (int i = 0; i < array_size; i++) { diff --git a/net/base/net_util.h b/net/base/net_util.h index 2ad81bf..9aba789 100644 --- a/net/base/net_util.h +++ b/net/base/net_util.h @@ -71,12 +71,20 @@ std::wstring GetHeaderParamValue(const std::wstring& field, std::string GetHeaderParamValue(const std::string& field, const std::string& param_name); -// Return the filename extracted from Content-Disposition header. Only two -// formats are supported: a. %-escaped UTF-8 b. RFC 2047. +// Return the filename extracted from Content-Disposition header. The following +// formats are tried in order listed below: // -// A non-ASCII param value is just returned as it is (assuming a NativeMB -// encoding). When a param value is ASCII, but is not in one of two forms -// supported, it is returned as it is unless it's pretty close to two supported +// 1. RFC 2047 +// 2. Raw-8bit-characters : +// a. UTF-8, b. referrer_charset, c. default os codepage. +// 3. %-escaped UTF-8. +// +// In step 2, if referrer_charset is empty(i.e. unknown), 2b is skipped. +// In step 3, the fallback charsets tried in step 2 are not tried. We +// can consider doing that later. +// +// When a param value is ASCII, but is not in format #1 or format #3 above, +// it is returned as it is unless it's pretty close to two supported // formats but not well-formed. In that case, an empty string is returned. // // In any case, a caller must check for the empty return value and resort to @@ -90,7 +98,8 @@ std::string GetHeaderParamValue(const std::string& field, // other caller is a unit test. Need to figure out expose this function only to // net_util_unittest. // -std::wstring GetFileNameFromCD(const std::string& header); +std::wstring GetFileNameFromCD(const std::string& header, + const std::string& referrer_charset); // Converts the given host name to unicode characters, APPENDING them to the // the given output string. This can be called for any host name, if the @@ -133,14 +142,12 @@ std::wstring StripWWW(const std::wstring& text); // Gets the filename from the raw Content-Disposition header (as read from the // network). Otherwise uses the last path component name or hostname from // |url|. Note: it's possible for the suggested filename to be empty (e.g., -// file:/// or view-cache:). +// file:/// or view-cache:). referrer_charset is used as one of charsets +// to interpret a raw 8bit string in C-D header (after interpreting +// as UTF-8 fails). See the comment for GetFilenameFromCD for more details. std::wstring GetSuggestedFilename(const GURL& url, const std::string& content_disposition, - const std::wstring& default_name); - -// DEPRECATED: Please use the above version of this method. -std::wstring GetSuggestedFilename(const GURL& url, - const std::wstring& content_disposition, + const std::string& referrer_charset, const std::wstring& default_name); // Checks the given port against a list of ports which are restricted by diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc index f9bc7f7..1a3bcdc 100644 --- a/net/base/net_util_unittest.cc +++ b/net/base/net_util_unittest.cc @@ -39,6 +39,7 @@ struct HeaderParamCase { struct FileNameCDCase { const char* header_field; + const char* referrer_charset; const wchar_t* expected; }; @@ -58,7 +59,8 @@ struct IDNTestCase { struct SuggestedFilenameCase { const char* url; - const wchar_t* content_disp_header; + const char* content_disp_header; + const char* referrer_charset; const wchar_t* default_filename; const wchar_t* expected_filename; }; @@ -299,75 +301,96 @@ TEST(NetUtilTest, GetHeaderParamValue) { TEST(NetUtilTest, GetFileNameFromCD) { const FileNameCDCase tests[] = { // Test various forms of C-D header fields emitted by web servers. - {"content-disposition: inline; filename=\"abcde.pdf\"", L"abcde.pdf"}, - {"content-disposition: inline; name=\"abcde.pdf\"", L"abcde.pdf"}, - {"content-disposition: attachment; filename=abcde.pdf", L"abcde.pdf"}, - {"content-disposition: attachment; name=abcde.pdf", L"abcde.pdf"}, - {"content-disposition: attachment; filename=abc,de.pdf", L"abc,de.pdf"}, - {"content-disposition: filename=abcde.pdf", L"abcde.pdf"}, - {"content-disposition: filename= abcde.pdf", L"abcde.pdf"}, - {"content-disposition: filename =abcde.pdf", L"abcde.pdf"}, - {"content-disposition: filename = abcde.pdf", L"abcde.pdf"}, - {"content-disposition: filename\t=abcde.pdf", L"abcde.pdf"}, - {"content-disposition: filename \t\t =abcde.pdf", L"abcde.pdf"}, - {"content-disposition: name=abcde.pdf", L"abcde.pdf"}, - {"content-disposition: inline; filename=\"abc%20de.pdf\"", L"abc de.pdf"}, + {"content-disposition: inline; filename=\"abcde.pdf\"", "", L"abcde.pdf"}, + {"content-disposition: inline; name=\"abcde.pdf\"", "", L"abcde.pdf"}, + {"content-disposition: attachment; filename=abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: attachment; name=abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: attachment; filename=abc,de.pdf", "", L"abc,de.pdf"}, + {"content-disposition: filename=abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: filename= abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: filename =abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: filename = abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: filename\t=abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: filename \t\t =abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: name=abcde.pdf", "", L"abcde.pdf"}, + {"content-disposition: inline; filename=\"abc%20de.pdf\"", "", + L"abc de.pdf"}, // Whitespaces are converted to a space. - {"content-disposition: inline; filename=\"abc \t\nde.pdf\"", + {"content-disposition: inline; filename=\"abc \t\nde.pdf\"", "", L"abc de.pdf"}, // %-escaped UTF-8 {"Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0%20" - "%EC%98%88%EC%88%A0.jpg\"", L"\xc608\xc220 \xc608\xc220.jpg"}, + "%EC%98%88%EC%88%A0.jpg\"", "", L"\xc608\xc220 \xc608\xc220.jpg"}, {"Content-Disposition: attachment; filename=\"%F0%90%8C%B0%F0%90%8C%B1" - "abc.jpg\"", L"\U00010330\U00010331abc.jpg"}, + "abc.jpg\"", "", L"\U00010330\U00010331abc.jpg"}, {"Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0 \n" - "%EC%98%88%EC%88%A0.jpg\"", L"\xc608\xc220 \xc608\xc220.jpg"}, + "%EC%98%88%EC%88%A0.jpg\"", "", L"\xc608\xc220 \xc608\xc220.jpg"}, // RFC 2047 with various charsets and Q/B encodings {"Content-Disposition: attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD=" - "D13=2Epng?=\"", L"\x82b8\x8853" L"3.png"}, + "D13=2Epng?=\"", "", L"\x82b8\x8853" L"3.png"}, {"Content-Disposition: attachment; filename==?eUc-Kr?b?v7m8+iAzLnBuZw==?=", - L"\xc608\xc220 3.png"}, + "", L"\xc608\xc220 3.png"}, {"Content-Disposition: attachment; filename==?utf-8?Q?=E8=8A=B8=E8" - "=A1=93_3=2Epng?=", L"\x82b8\x8853 3.png"}, + "=A1=93_3=2Epng?=", "", L"\x82b8\x8853 3.png"}, {"Content-Disposition: attachment; filename==?utf-8?Q?=F0=90=8C=B0" - "_3=2Epng?=", L"\U00010330 3.png"}, - {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=e3_=2epng?=\"", - L"caf\x00e3 .png"}, + "_3=2Epng?=", "", L"\U00010330 3.png"}, + {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=e9_=2epng?=\"", + "", L"caf\x00e9 .png"}, // Space after an encode word should be removed. - {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=E3_?= .png\"", - L"caf\x00e3 .png"}, + {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=E9_?= .png\"", + "", L"caf\x00e9 .png"}, // Two encoded words with different charsets (not very likely to be emitted // by web servers in the wild). Spaces between them are removed. {"Content-Disposition: inline; filename=\"=?euc-kr?b?v7m8+iAz?=" - " =?ksc5601?q?=BF=B9=BC=FA=2Epng?=\"", L"\xc608\xc220 3\xc608\xc220.png"}, - {"Content-Disposition: attachment; filename=\"=?windows-1252?Q?caf=E3?=" - " =?iso-8859-7?b?4eI=?= .png\"", L"caf\x00e3\x03b1\x03b2.png"}, - // Non-ASCII string is passed through (and treated as UTF-8). - {"Content-Disposition: attachment; filename=caf\xc3\xa3.png", - L"caf\x00e3.png"}, + " =?ksc5601?q?=BF=B9=BC=FA=2Epng?=\"", "", + L"\xc608\xc220 3\xc608\xc220.png"}, + {"Content-Disposition: attachment; filename=\"=?windows-1252?Q?caf=E9?=" + " =?iso-8859-7?b?4eI=?= .png\"", "", L"caf\x00e9\x03b1\x03b2.png"}, + // Non-ASCII string is passed through and treated as UTF-8 as long as + // it's valid as UTF-8 and regardless of |referrer_charset|. + {"Content-Disposition: attachment; filename=caf\xc3\xa9.png", + "iso-8859-1", L"caf\x00e9.png"}, + {"Content-Disposition: attachment; filename=caf\xc3\xa9.png", + "", L"caf\x00e9.png"}, + // Non-ASCII/Non-UTF-8 string. Fall back to the referrer charset. + {"Content-Disposition: attachment; filename=caf\xe5.png", + "windows-1253", L"caf\x03b5.png"}, +#if 0 + // Non-ASCII/Non-UTF-8 string. Fall back to the native codepage. + // TODO(jungshik): We need to set the OS default codepage + // to a specific value before testing. On Windows, we can use + // SetThreadLocale(). + {"Content-Disposition: attachment; filename=\xb0\xa1\xb0\xa2.png", + "", L"\xac00\xac01.png"}, +#endif // Failure cases // Invalid hex-digit "G" - {"Content-Disposition: attachment; filename==?iiso88591?Q?caf=EG?=", L""}, + {"Content-Disposition: attachment; filename==?iiso88591?Q?caf=EG?=", "", + L""}, // Incomplete RFC 2047 encoded-word (missing '='' at the end) - {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?", L""}, + {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?", "", L""}, // Extra character at the end of an encoded word - {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?==", L""}, + {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?==", + "", L""}, // Extra token at the end of an encoded word - {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?=?", L""}, - {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?=?=", L""}, + {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?=?", + "", L""}, + {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?=?=", + "", L""}, // Incomplete hex-escaped chars {"Content-Disposition: attachment; filename==?windows-1252?Q?=63=61=E?=", - L""}, - {"Content-Disposition: attachment; filename=%EC%98%88%EC%88%A", L""}, + "", L""}, + {"Content-Disposition: attachment; filename=%EC%98%88%EC%88%A", "", L""}, // %-escaped non-UTF-8 encoding is an "error" - {"Content-Disposition: attachment; filename=%B7%DD%BD%D1.png", L""}, + {"Content-Disposition: attachment; filename=%B7%DD%BD%D1.png", "", L""}, // Two RFC 2047 encoded words in a row without a space is an error. {"Content-Disposition: attachment; filename==?windows-1252?Q?caf=E3?=" - "=?iso-8859-7?b?4eIucG5nCg==?=", L""}, + "=?iso-8859-7?b?4eIucG5nCg==?=", "", L""}, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { EXPECT_EQ(tests[i].expected, - net::GetFileNameFromCD(tests[i].header_field)); + net::GetFileNameFromCD(tests[i].header_field, + tests[i].referrer_charset)); } } @@ -669,97 +692,132 @@ TEST(NetUtilTest, StripWWW) { TEST(NetUtilTest, GetSuggestedFilename) { const SuggestedFilenameCase test_cases[] = { {"http://www.google.com/", - L"Content-disposition: attachment; filename=test.html", + "Content-disposition: attachment; filename=test.html", + "", L"", L"test.html"}, {"http://www.google.com/", - L"Content-disposition: attachment; filename=\"test.html\"", + "Content-disposition: attachment; filename=\"test.html\"", + "", L"", L"test.html"}, {"http://www.google.com/path/test.html", - L"Content-disposition: attachment", + "Content-disposition: attachment", + "", L"", L"test.html"}, {"http://www.google.com/path/test.html", - L"Content-disposition: attachment;", + "Content-disposition: attachment;", + "", L"", L"test.html"}, {"http://www.google.com/", - L"", + "", + "", L"", L"www.google.com"}, {"http://www.google.com/test.html", - L"", + "", + "", L"", L"test.html"}, // Now that we use googleurl's ExtractFileName, this case falls back // to the hostname. If this behavior is not desirable, we'd better // change ExtractFileName (in url_parse). {"http://www.google.com/path/", - L"", + "", + "", L"", L"www.google.com"}, {"http://www.google.com/path", - L"", + "", + "", L"", L"path"}, {"file:///", - L"", + "", + "", L"", L"download"}, {"view-cache:", - L"", + "", + "", L"", L"download"}, {"http://www.google.com/", - L"Content-disposition: attachment; filename =\"test.html\"", + "Content-disposition: attachment; filename =\"test.html\"", + "", L"download", L"test.html"}, {"http://www.google.com/", - L"", + "", + "", L"download", L"download"}, {"http://www.google.com/", - L"Content-disposition: attachment; filename=\"../test.html\"", + "Content-disposition: attachment; filename=\"../test.html\"", + "", L"", L"test.html"}, {"http://www.google.com/", - L"Content-disposition: attachment; filename=\"..\"", + "Content-disposition: attachment; filename=\"..\"", + "", L"download", L"download"}, {"http://www.google.com/test.html", - L"Content-disposition: attachment; filename=\"..\"", + "Content-disposition: attachment; filename=\"..\"", + "", L"download", L"test.html"}, // Below is a small subset of cases taken from GetFileNameFromCD test above. {"http://www.google.com/", - L"Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0%20" - L"%EC%98%88%EC%88%A0.jpg\"", + "Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0%20" + "%EC%98%88%EC%88%A0.jpg\"", + "", L"", L"\uc608\uc220 \uc608\uc220.jpg"}, {"http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg", - L"", + "", + "", L"download", L"\uc608\uc220 \uc608\uc220.jpg"}, {"http://www.google.com/", - L"Content-disposition: attachment;", + "Content-disposition: attachment;", + "", L"\uB2E4\uC6B4\uB85C\uB4DC", L"\uB2E4\uC6B4\uB85C\uB4DC"}, {"http://www.google.com/", - L"Content-Disposition: attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD=" - L"D13=2Epng?=\"", + "Content-Disposition: attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD=" + "D13=2Epng?=\"", + "", L"download", L"\u82b8\u88533.png"}, + {"http://www.example.com/images?id=3", + "Content-Disposition: attachment; filename=caf\xc3\xa9.png", + "iso-8859-1", + L"", + L"caf\u00e9.png"}, + {"http://www.example.com/images?id=3", + "Content-Disposition: attachment; filename=caf\xe5.png", + "windows-1253", + L"", + L"caf\u03b5.png"}, + {"http://www.example.com/file?id=3", + "Content-Disposition: attachment; name=\xcf\xc2\xd4\xd8.zip", + "GBK", + L"", + L"\u4e0b\u8f7d.zip"}, // Invalid C-D header. Extracts filename from url. {"http://www.google.com/test.html", - L"Content-Disposition: attachment; filename==?iiso88591?Q?caf=EG?=", + "Content-Disposition: attachment; filename==?iiso88591?Q?caf=EG?=", + "", L"", L"test.html"}, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { std::wstring filename = net::GetSuggestedFilename( GURL(test_cases[i].url), test_cases[i].content_disp_header, - test_cases[i].default_filename); + test_cases[i].referrer_charset, test_cases[i].default_filename); EXPECT_EQ(std::wstring(test_cases[i].expected_filename), filename); } } diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 8c09c90..29735ac 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -70,6 +70,13 @@ class URLRequestContext : return EmptyString(); } + // In general, referrer_charset is not known when URLRequestContext is + // constructed. So, we need a setter. + const std::string& referrer_charset() const { return referrer_charset_; } + void set_referrer_charset(const std::string& charset) { + referrer_charset_ = charset; + } + protected: friend class base::RefCountedThreadSafe<URLRequestContext>; @@ -85,6 +92,10 @@ class URLRequestContext : net::FtpAuthCache ftp_auth_cache_; std::string accept_language_; std::string accept_charset_; + // The charset of the referrer where this request comes from. It's not + // used in communication with a server but is used to construct a suggested + // filename for file download. + std::string referrer_charset_; private: DISALLOW_COPY_AND_ASSIGN(URLRequestContext); |