| Index: net/base/net_util.cc
|
| diff --git a/net/base/net_util.cc b/net/base/net_util.cc
|
| index ef8eb534d12792c4ae76978f1425470acce9cd00..0be8daa9932f5bdda87cb0dd4de2406a5ce2a771 100644
|
| --- a/net/base/net_util.cc
|
| +++ b/net/base/net_util.cc
|
| @@ -922,6 +922,52 @@ char* do_strdup(const char* src) {
|
| #endif
|
| }
|
|
|
| +void SanitizeGeneratedFileName(std::string& filename) {
|
| + if (!filename.empty()) {
|
| + // Remove "." from the beginning and end of the file name to avoid tricks
|
| + // with hidden files, "..", and "."
|
| + TrimString(filename, ".", &filename);
|
| +#if defined(OS_WIN)
|
| + // Handle CreateFile() stripping trailing dots and spaces on filenames
|
| + // http://support.microsoft.com/kb/115827
|
| + std::string::size_type pos = filename.find_last_not_of(" .");
|
| + if (pos == std::string::npos)
|
| + filename.resize(0);
|
| + else
|
| + filename.resize(++pos);
|
| +#endif
|
| + // Replace any path information by changing path separators with
|
| + // underscores.
|
| + ReplaceSubstringsAfterOffset(&filename, 0, "/", "_");
|
| + ReplaceSubstringsAfterOffset(&filename, 0, "\\", "_");
|
| + }
|
| +}
|
| +
|
| +std::string GetFileNameFromURL(const GURL& url,
|
| + const std::string& referrer_charset) {
|
| + // about: and data: URLs don't have file names, but esp. data: URLs may
|
| + // contain parts that look like ones (i.e., contain a slash). Therefore we
|
| + // don't attempt to divine a file name out of them.
|
| + if (!url.is_valid() || url.SchemeIs("about") || url.SchemeIs("data"))
|
| + return std::string();
|
| +
|
| + const std::string unescaped_url_filename = UnescapeURLComponent(
|
| + url.ExtractFileName(),
|
| + UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
|
| +
|
| + // The URL's path should be escaped UTF-8, but may not be.
|
| + std::string decoded_filename = unescaped_url_filename;
|
| + if (!IsStringASCII(decoded_filename)) {
|
| + bool ignore;
|
| + // TODO(jshin): this is probably not robust enough. To be sure, we need
|
| + // encoding detection.
|
| + DecodeWord(unescaped_url_filename, referrer_charset, &ignore,
|
| + &decoded_filename);
|
| + }
|
| +
|
| + return decoded_filename;
|
| +}
|
| +
|
| #if defined(OS_WIN)
|
| // Returns whether the specified extension is automatically integrated into the
|
| // windows shell.
|
| @@ -1379,99 +1425,57 @@ string16 GetSuggestedFilename(const GURL& url,
|
| const std::string& content_disposition,
|
| const std::string& referrer_charset,
|
| const std::string& suggested_name,
|
| + const std::string& mime_type,
|
| const string16& default_name) {
|
| // TODO: this function to be updated to match the httpbis recommendations.
|
| // Talk to abarth for the latest news.
|
|
|
| // We don't translate this fallback string, "download". If localization is
|
| - // needed, the caller should provide localized fallback default_name.
|
| + // needed, the caller should provide localized fallback in |default_name|.
|
| static const char* kFinalFallbackName = "download";
|
| + std::string filename; // In UTF-8
|
|
|
| - std::string filename;
|
| -
|
| - // Try to extract from content-disposition first.
|
| + // Try to extract a filename from content-disposition first.
|
| if (!content_disposition.empty())
|
| filename = GetFileNameFromCD(content_disposition, referrer_charset);
|
|
|
| - // Then try to use suggested name.
|
| + // Then try to use the suggested name.
|
| if (filename.empty() && !suggested_name.empty())
|
| filename = suggested_name;
|
|
|
| - if (!filename.empty()) {
|
| - // Replace any path information the server may have sent, by changing
|
| - // path separators with underscores.
|
| - ReplaceSubstringsAfterOffset(&filename, 0, "/", "_");
|
| - ReplaceSubstringsAfterOffset(&filename, 0, "\\", "_");
|
| -
|
| - // Next, remove "." from the beginning and end of the file name to avoid
|
| - // tricks with hidden files, "..", and "."
|
| - TrimString(filename, ".", &filename);
|
| - }
|
| -
|
| - if (filename.empty()) {
|
| - // about: and data: URLs don't have file names, but esp. data: URLs may
|
| - // contain parts that look like ones (i.e., contain a slash).
|
| - // Therefore we don't attempt to divine a file name out of them.
|
| - if (url.SchemeIs("about") || url.SchemeIs("data")) {
|
| - return default_name.empty() ? ASCIIToUTF16(kFinalFallbackName)
|
| - : default_name;
|
| - }
|
| -
|
| - if (url.is_valid()) {
|
| - const std::string unescaped_url_filename = UnescapeURLComponent(
|
| - url.ExtractFileName(),
|
| - UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
|
| -
|
| - // The URL's path should be escaped UTF-8, but may not be.
|
| - std::string decoded_filename = unescaped_url_filename;
|
| - if (!IsStringASCII(decoded_filename)) {
|
| - bool ignore;
|
| - // TODO(jshin): this is probably not robust enough. To be sure, we
|
| - // need encoding detection.
|
| - DecodeWord(unescaped_url_filename, referrer_charset, &ignore,
|
| - &decoded_filename);
|
| - }
|
| + // Now try extracting the filename from the URL. GetFileNameFromURL() only
|
| + // looks at the last component of the URL and doesn't return the hostname as a
|
| + // failover.
|
| + if (filename.empty())
|
| + filename = GetFileNameFromURL(url, referrer_charset);
|
|
|
| - filename = decoded_filename;
|
| - }
|
| + // Finally try the URL hostname, but only if there's no default specified in
|
| + // |default_name|. Some schemes (e.g.: file:, about:, data:) do not have a
|
| + // host name.
|
| + if (filename.empty() && default_name.empty() &&
|
| + url.is_valid() && !url.host().empty()) {
|
| + // TODO(jungshik) : Decode a 'punycoded' IDN hostname. (bug 1264451)
|
| + filename = url.host();
|
| }
|
|
|
| -#if defined(OS_WIN)
|
| - { // Handle CreateFile() stripping trailing dots and spaces on filenames
|
| - // http://support.microsoft.com/kb/115827
|
| - std::string::size_type pos = filename.find_last_not_of(" .");
|
| - if (pos == std::string::npos)
|
| - filename.resize(0);
|
| - else
|
| - filename.resize(++pos);
|
| - }
|
| -#endif
|
| - // Trim '.' once more.
|
| - TrimString(filename, ".", &filename);
|
| -
|
| - // If there's no filename or it gets trimed to be empty, use
|
| - // the URL hostname or default_name
|
| - if (filename.empty()) {
|
| - if (!default_name.empty()) {
|
| - return default_name;
|
| - } else if (url.is_valid()) {
|
| - // Some schemes (e.g. file) do not have a hostname. Even though it's
|
| - // not likely to reach here, let's hardcode the last fallback name.
|
| - // TODO(jungshik) : Decode a 'punycoded' IDN hostname. (bug 1264451)
|
| - filename = url.host().empty() ? kFinalFallbackName : url.host();
|
| - } else {
|
| - NOTREACHED();
|
| - }
|
| - }
|
| + SanitizeGeneratedFileName(filename);
|
| + // Sanitization can cause the filename to disappear (e.g.: if the filename
|
| + // consisted entirely of spaces and '.'s), in which case we use the default.
|
| + if (filename.empty() && default_name.empty())
|
| + filename = kFinalFallbackName;
|
|
|
| #if defined(OS_WIN)
|
| - string16 path = UTF8ToUTF16(filename);
|
| + string16 path = (filename.empty())? default_name : UTF8ToUTF16(filename);
|
| file_util::ReplaceIllegalCharactersInPath(&path, '-');
|
| - return path;
|
| + FilePath result(path);
|
| + GenerateSafeFileName(mime_type, &result);
|
| + return result.value();
|
| #else
|
| - std::string path = filename;
|
| + std::string path = (filename.empty())? UTF16ToUTF8(default_name) : filename;
|
| file_util::ReplaceIllegalCharactersInPath(&path, '-');
|
| - return UTF8ToUTF16(path);
|
| + FilePath result(path);
|
| + GenerateSafeFileName(mime_type, &result);
|
| + return UTF8ToUTF16(result.value());
|
| #endif
|
| }
|
|
|
| @@ -1481,26 +1485,20 @@ FilePath GenerateFileName(const GURL& url,
|
| const std::string& suggested_name,
|
| const std::string& mime_type,
|
| const string16& default_file_name) {
|
| - string16 new_name = GetSuggestedFilename(GURL(url),
|
| - content_disposition,
|
| - referrer_charset,
|
| - suggested_name,
|
| - default_file_name);
|
| -
|
| - // TODO(evan): this code is totally wrong -- we should just generate
|
| - // Unicode filenames and do all this encoding switching at the end.
|
| - // However, I'm just shuffling wrong code around, at least not adding
|
| - // to it.
|
| + string16 file_name = GetSuggestedFilename(url,
|
| + content_disposition,
|
| + referrer_charset,
|
| + suggested_name,
|
| + mime_type,
|
| + default_file_name);
|
| +
|
| #if defined(OS_WIN)
|
| - FilePath generated_name = FilePath(new_name);
|
| + FilePath generated_name(file_name);
|
| #else
|
| - FilePath generated_name = FilePath(
|
| - base::SysWideToNativeMB(UTF16ToWide(new_name)));
|
| + FilePath generated_name(base::SysWideToNativeMB(UTF16ToWide(file_name)));
|
| #endif
|
| -
|
| DCHECK(!generated_name.empty());
|
|
|
| - GenerateSafeFileName(mime_type, &generated_name);
|
| return generated_name;
|
| }
|
|
|
|
|