Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(299)

Side by Side Diff: net/base/filename_util.cc

Issue 266243004: Clang format slam. Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/filename_util.h" 5 #include "net/base/filename_util.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/files/file_path.h" 8 #include "base/files/file_path.h"
9 #include "base/i18n/file_util_icu.h" 9 #include "base/i18n/file_util_icu.h"
10 #include "base/path_service.h" 10 #include "base/path_service.h"
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 url.ExtractFileName(), 70 url.ExtractFileName(),
71 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); 71 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
72 72
73 // The URL's path should be escaped UTF-8, but may not be. 73 // The URL's path should be escaped UTF-8, but may not be.
74 std::string decoded_filename = unescaped_url_filename; 74 std::string decoded_filename = unescaped_url_filename;
75 if (!IsStringUTF8(decoded_filename)) { 75 if (!IsStringUTF8(decoded_filename)) {
76 // TODO(jshin): this is probably not robust enough. To be sure, we need 76 // TODO(jshin): this is probably not robust enough. To be sure, we need
77 // encoding detection. 77 // encoding detection.
78 base::string16 utf16_output; 78 base::string16 utf16_output;
79 if (!referrer_charset.empty() && 79 if (!referrer_charset.empty() &&
80 net::ConvertToUTF16(unescaped_url_filename, 80 net::ConvertToUTF16(
81 referrer_charset.c_str(), 81 unescaped_url_filename, referrer_charset.c_str(), &utf16_output)) {
82 &utf16_output)) {
83 decoded_filename = base::UTF16ToUTF8(utf16_output); 82 decoded_filename = base::UTF16ToUTF8(utf16_output);
84 } else { 83 } else {
85 decoded_filename = base::WideToUTF8( 84 decoded_filename =
86 base::SysNativeMBToWide(unescaped_url_filename)); 85 base::WideToUTF8(base::SysNativeMBToWide(unescaped_url_filename));
87 } 86 }
88 } 87 }
89 // If the URL contains a (possibly empty) query, assume it is a generator, and 88 // If the URL contains a (possibly empty) query, assume it is a generator, and
90 // allow the determined extension to be overwritten. 89 // allow the determined extension to be overwritten.
91 *should_overwrite_extension = !decoded_filename.empty() && url.has_query(); 90 *should_overwrite_extension = !decoded_filename.empty() && url.has_query();
92 91
93 return decoded_filename; 92 return decoded_filename;
94 } 93 }
95 94
96 // Returns whether the specified extension is automatically integrated into the 95 // Returns whether the specified extension is automatically integrated into the
(...skipping 18 matching lines...) Expand all
115 114
116 // Returns whether the specified file name is a reserved name on windows. 115 // Returns whether the specified file name is a reserved name on windows.
117 // This includes names like "com2.zip" (which correspond to devices) and 116 // This includes names like "com2.zip" (which correspond to devices) and
118 // desktop.ini and thumbs.db which have special meaning to the windows shell. 117 // desktop.ini and thumbs.db which have special meaning to the windows shell.
119 bool IsReservedName(const base::FilePath::StringType& filename) { 118 bool IsReservedName(const base::FilePath::StringType& filename) {
120 // This list is taken from the MSDN article "Naming a file" 119 // This list is taken from the MSDN article "Naming a file"
121 // http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx 120 // http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx
122 // I also added clock$ because GetSaveFileName seems to consider it as a 121 // I also added clock$ because GetSaveFileName seems to consider it as a
123 // reserved name too. 122 // reserved name too.
124 static const char* const known_devices[] = { 123 static const char* const known_devices[] = {
125 "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", 124 "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4",
126 "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", 125 "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
127 "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "clock$" 126 "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "clock$"};
128 };
129 #if defined(OS_WIN) 127 #if defined(OS_WIN)
130 std::string filename_lower = StringToLowerASCII(base::WideToUTF8(filename)); 128 std::string filename_lower = StringToLowerASCII(base::WideToUTF8(filename));
131 #elif defined(OS_POSIX) 129 #elif defined(OS_POSIX)
132 std::string filename_lower = StringToLowerASCII(filename); 130 std::string filename_lower = StringToLowerASCII(filename);
133 #endif 131 #endif
134 132
135 for (size_t i = 0; i < arraysize(known_devices); ++i) { 133 for (size_t i = 0; i < arraysize(known_devices); ++i) {
136 // Exact match. 134 // Exact match.
137 if (filename_lower == known_devices[i]) 135 if (filename_lower == known_devices[i])
138 return true; 136 return true;
139 // Starts with "DEVICE.". 137 // Starts with "DEVICE.".
140 if (filename_lower.find(std::string(known_devices[i]) + ".") == 0) 138 if (filename_lower.find(std::string(known_devices[i]) + ".") == 0)
141 return true; 139 return true;
142 } 140 }
143 141
144 static const char* const magic_names[] = { 142 static const char* const magic_names[] = {// These file names are used by the
145 // These file names are used by the "Customize folder" feature of the shell. 143 // "Customize folder" feature of the
146 "desktop.ini", 144 // shell.
147 "thumbs.db", 145 "desktop.ini", "thumbs.db",
148 }; 146 };
149 147
150 for (size_t i = 0; i < arraysize(magic_names); ++i) { 148 for (size_t i = 0; i < arraysize(magic_names); ++i) {
151 if (filename_lower == magic_names[i]) 149 if (filename_lower == magic_names[i])
152 return true; 150 return true;
153 } 151 }
154 152
155 return false; 153 return false;
156 } 154 }
157 155
158
159 // Examines the current extension in |file_name| and modifies it if necessary in 156 // Examines the current extension in |file_name| and modifies it if necessary in
160 // order to ensure the filename is safe. If |file_name| doesn't contain an 157 // order to ensure the filename is safe. If |file_name| doesn't contain an
161 // extension or if |ignore_extension| is true, then a new extension will be 158 // extension or if |ignore_extension| is true, then a new extension will be
162 // constructed based on the |mime_type|. 159 // constructed based on the |mime_type|.
163 // 160 //
164 // We're addressing two things here: 161 // We're addressing two things here:
165 // 162 //
166 // 1) Usability. If there is no reliable file extension, we want to guess a 163 // 1) Usability. If there is no reliable file extension, we want to guess a
167 // reasonable file extension based on the content type. 164 // reasonable file extension based on the content type.
168 // 165 //
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 url_string.push_back(base::FilePath::kSeparators[0]); 236 url_string.push_back(base::FilePath::kSeparators[0]);
240 } 237 }
241 url_string.append(path.value()); 238 url_string.append(path.value());
242 239
243 // Now do replacement of some characters. Since we assume the input is a 240 // Now do replacement of some characters. Since we assume the input is a
244 // literal filename, anything the URL parser might consider special should 241 // literal filename, anything the URL parser might consider special should
245 // be escaped here. 242 // be escaped here.
246 243
247 // must be the first substitution since others will introduce percents as the 244 // must be the first substitution since others will introduce percents as the
248 // escape character 245 // escape character
249 ReplaceSubstringsAfterOffset(&url_string, 0, 246 ReplaceSubstringsAfterOffset(
250 FILE_PATH_LITERAL("%"), FILE_PATH_LITERAL("%25")); 247 &url_string, 0, FILE_PATH_LITERAL("%"), FILE_PATH_LITERAL("%25"));
251 248
252 // semicolon is supposed to be some kind of separator according to RFC 2396 249 // semicolon is supposed to be some kind of separator according to RFC 2396
253 ReplaceSubstringsAfterOffset(&url_string, 0, 250 ReplaceSubstringsAfterOffset(
254 FILE_PATH_LITERAL(";"), FILE_PATH_LITERAL("%3B")); 251 &url_string, 0, FILE_PATH_LITERAL(";"), FILE_PATH_LITERAL("%3B"));
255 252
256 ReplaceSubstringsAfterOffset(&url_string, 0, 253 ReplaceSubstringsAfterOffset(
257 FILE_PATH_LITERAL("#"), FILE_PATH_LITERAL("%23")); 254 &url_string, 0, FILE_PATH_LITERAL("#"), FILE_PATH_LITERAL("%23"));
258 255
259 ReplaceSubstringsAfterOffset(&url_string, 0, 256 ReplaceSubstringsAfterOffset(
260 FILE_PATH_LITERAL("?"), FILE_PATH_LITERAL("%3F")); 257 &url_string, 0, FILE_PATH_LITERAL("?"), FILE_PATH_LITERAL("%3F"));
261 258
262 #if defined(OS_POSIX) 259 #if defined(OS_POSIX)
263 ReplaceSubstringsAfterOffset(&url_string, 0, 260 ReplaceSubstringsAfterOffset(
264 FILE_PATH_LITERAL("\\"), FILE_PATH_LITERAL("%5C")); 261 &url_string, 0, FILE_PATH_LITERAL("\\"), FILE_PATH_LITERAL("%5C"));
265 #endif 262 #endif
266 263
267 return GURL(url_string); 264 return GURL(url_string);
268 } 265 }
269 266
270 bool FileURLToFilePath(const GURL& url, base::FilePath* file_path) { 267 bool FileURLToFilePath(const GURL& url, base::FilePath* file_path) {
271 *file_path = base::FilePath(); 268 *file_path = base::FilePath();
272 base::FilePath::StringType& file_path_str = 269 base::FilePath::StringType& file_path_str =
273 const_cast<base::FilePath::StringType&>(file_path->value()); 270 const_cast<base::FilePath::StringType&>(file_path->value());
274 file_path_str.clear(); 271 file_path_str.clear();
(...skipping 13 matching lines...) Expand all
288 if (first_non_slash != std::string::npos && first_non_slash > 0) 285 if (first_non_slash != std::string::npos && first_non_slash > 0)
289 path.erase(0, first_non_slash); 286 path.erase(0, first_non_slash);
290 } else { 287 } else {
291 // URL contains a host: this means it's UNC. We keep the preceeding slash 288 // URL contains a host: this means it's UNC. We keep the preceeding slash
292 // on the path. 289 // on the path.
293 path = "\\\\"; 290 path = "\\\\";
294 path.append(host); 291 path.append(host);
295 path.append(url.path()); 292 path.append(url.path());
296 } 293 }
297 std::replace(path.begin(), path.end(), '/', '\\'); 294 std::replace(path.begin(), path.end(), '/', '\\');
298 #else // defined(OS_WIN) 295 #else // defined(OS_WIN)
299 // Firefox seems to ignore the "host" of a file url if there is one. That is, 296 // Firefox seems to ignore the "host" of a file url if there is one. That is,
300 // file://foo/bar.txt maps to /bar.txt. 297 // file://foo/bar.txt maps to /bar.txt.
301 // TODO(dhg): This should probably take into account UNCs which could 298 // TODO(dhg): This should probably take into account UNCs which could
302 // include a hostname other than localhost or blank 299 // include a hostname other than localhost or blank
303 std::string path = url.path(); 300 std::string path = url.path();
304 #endif // !defined(OS_WIN) 301 #endif // !defined(OS_WIN)
305 302
306 if (path.empty()) 303 if (path.empty())
307 return false; 304 return false;
308 305
309 // GURL stores strings as percent-encoded 8-bit, this will undo if possible. 306 // GURL stores strings as percent-encoded 8-bit, this will undo if possible.
310 path = UnescapeURLComponent(path, 307 path = UnescapeURLComponent(
311 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); 308 path, UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
312 309
313 #if defined(OS_WIN) 310 #if defined(OS_WIN)
314 if (IsStringUTF8(path)) { 311 if (IsStringUTF8(path)) {
315 file_path_str.assign(base::UTF8ToWide(path)); 312 file_path_str.assign(base::UTF8ToWide(path));
316 // We used to try too hard and see if |path| made up entirely of 313 // We used to try too hard and see if |path| made up entirely of
317 // the 1st 256 characters in the Unicode was a zero-extended UTF-16. 314 // the 1st 256 characters in the Unicode was a zero-extended UTF-16.
318 // If so, we converted it to 'Latin-1' and checked if the result was UTF-8. 315 // If so, we converted it to 'Latin-1' and checked if the result was UTF-8.
319 // If the check passed, we converted the result to UTF-8. 316 // If the check passed, we converted the result to UTF-8.
320 // Otherwise, we treated the result as the native OS encoding. 317 // Otherwise, we treated the result as the native OS encoding.
321 // However, that led to http://crbug.com/4619 and http://crbug.com/14153 318 // However, that led to http://crbug.com/4619 and http://crbug.com/14153
322 } else { 319 } else {
323 // Not UTF-8, assume encoding is native codepage and we're done. We know we 320 // Not UTF-8, assume encoding is native codepage and we're done. We know we
324 // are giving the conversion function a nonempty string, and it may fail if 321 // are giving the conversion function a nonempty string, and it may fail if
325 // the given string is not in the current encoding and give us an empty 322 // the given string is not in the current encoding and give us an empty
326 // string back. We detect this and report failure. 323 // string back. We detect this and report failure.
327 file_path_str = base::SysNativeMBToWide(path); 324 file_path_str = base::SysNativeMBToWide(path);
328 } 325 }
329 #else // defined(OS_WIN) 326 #else // defined(OS_WIN)
330 // Collapse multiple path slashes into a single path slash. 327 // Collapse multiple path slashes into a single path slash.
331 std::string new_path; 328 std::string new_path;
332 do { 329 do {
333 new_path = path; 330 new_path = path;
334 ReplaceSubstringsAfterOffset(&new_path, 0, "//", "/"); 331 ReplaceSubstringsAfterOffset(&new_path, 0, "//", "/");
335 path.swap(new_path); 332 path.swap(new_path);
336 } while (new_path != path); 333 } while (new_path != path);
337 334
338 file_path_str.assign(path); 335 file_path_str.assign(path);
339 #endif // !defined(OS_WIN) 336 #endif // !defined(OS_WIN)
340 337
341 return !file_path_str.empty(); 338 return !file_path_str.empty();
342 } 339 }
343 340
344 bool IsSafePortablePathComponent(const base::FilePath& component) { 341 bool IsSafePortablePathComponent(const base::FilePath& component) {
345 base::string16 component16; 342 base::string16 component16;
346 base::FilePath::StringType sanitized = component.value(); 343 base::FilePath::StringType sanitized = component.value();
347 SanitizeGeneratedFileName(&sanitized, true); 344 SanitizeGeneratedFileName(&sanitized, true);
348 base::FilePath::StringType extension = component.Extension(); 345 base::FilePath::StringType extension = component.Extension();
349 if (!extension.empty()) 346 if (!extension.empty())
350 extension.erase(extension.begin()); // Erase preceding '.'. 347 extension.erase(extension.begin()); // Erase preceding '.'.
351 return !component.empty() && 348 return !component.empty() && (component == component.BaseName()) &&
352 (component == component.BaseName()) &&
353 (component == component.StripTrailingSeparators()) && 349 (component == component.StripTrailingSeparators()) &&
354 FilePathToString16(component, &component16) && 350 FilePathToString16(component, &component16) &&
355 file_util::IsFilenameLegal(component16) && 351 file_util::IsFilenameLegal(component16) &&
356 !IsShellIntegratedExtension(extension) && 352 !IsShellIntegratedExtension(extension) &&
357 (sanitized == component.value()) && 353 (sanitized == component.value()) && !IsReservedName(component.value());
358 !IsReservedName(component.value());
359 } 354 }
360 355
361 bool IsSafePortableRelativePath(const base::FilePath& path) { 356 bool IsSafePortableRelativePath(const base::FilePath& path) {
362 if (path.empty() || path.IsAbsolute() || path.EndsWithSeparator()) 357 if (path.empty() || path.IsAbsolute() || path.EndsWithSeparator())
363 return false; 358 return false;
364 std::vector<base::FilePath::StringType> components; 359 std::vector<base::FilePath::StringType> components;
365 path.GetComponents(&components); 360 path.GetComponents(&components);
366 if (components.empty()) 361 if (components.empty())
367 return false; 362 return false;
368 for (size_t i = 0; i < components.size() - 1; ++i) { 363 for (size_t i = 0; i < components.size() - 1; ++i) {
(...skipping 30 matching lines...) Expand all
399 const std::string& referrer_charset, 394 const std::string& referrer_charset,
400 const std::string& suggested_name, 395 const std::string& suggested_name,
401 const std::string& mime_type, 396 const std::string& mime_type,
402 const std::string& default_name) { 397 const std::string& default_name) {
403 // TODO: this function to be updated to match the httpbis recommendations. 398 // TODO: this function to be updated to match the httpbis recommendations.
404 // Talk to abarth for the latest news. 399 // Talk to abarth for the latest news.
405 400
406 // We don't translate this fallback string, "download". If localization is 401 // We don't translate this fallback string, "download". If localization is
407 // needed, the caller should provide localized fallback in |default_name|. 402 // needed, the caller should provide localized fallback in |default_name|.
408 static const base::FilePath::CharType kFinalFallbackName[] = 403 static const base::FilePath::CharType kFinalFallbackName[] =
409 FILE_PATH_LITERAL("download"); 404 FILE_PATH_LITERAL("download");
410 std::string filename; // In UTF-8 405 std::string filename; // In UTF-8
411 bool overwrite_extension = false; 406 bool overwrite_extension = false;
412 407
413 // Try to extract a filename from content-disposition first. 408 // Try to extract a filename from content-disposition first.
414 if (!content_disposition.empty()) { 409 if (!content_disposition.empty()) {
415 HttpContentDisposition header(content_disposition, referrer_charset); 410 HttpContentDisposition header(content_disposition, referrer_charset);
416 filename = header.filename(); 411 filename = header.filename();
417 } 412 }
418 413
419 // Then try to use the suggested name. 414 // Then try to use the suggested name.
420 if (filename.empty() && !suggested_name.empty()) 415 if (filename.empty() && !suggested_name.empty())
421 filename = suggested_name; 416 filename = suggested_name;
422 417
423 // Now try extracting the filename from the URL. GetFileNameFromURL() only 418 // Now try extracting the filename from the URL. GetFileNameFromURL() only
424 // looks at the last component of the URL and doesn't return the hostname as a 419 // looks at the last component of the URL and doesn't return the hostname as a
425 // failover. 420 // failover.
426 if (filename.empty()) 421 if (filename.empty())
427 filename = GetFileNameFromURL(url, referrer_charset, &overwrite_extension); 422 filename = GetFileNameFromURL(url, referrer_charset, &overwrite_extension);
428 423
429 // Finally try the URL hostname, but only if there's no default specified in 424 // Finally try the URL hostname, but only if there's no default specified in
430 // |default_name|. Some schemes (e.g.: file:, about:, data:) do not have a 425 // |default_name|. Some schemes (e.g.: file:, about:, data:) do not have a
431 // host name. 426 // host name.
432 if (filename.empty() && 427 if (filename.empty() && default_name.empty() && url.is_valid() &&
433 default_name.empty() &&
434 url.is_valid() &&
435 !url.host().empty()) { 428 !url.host().empty()) {
436 // TODO(jungshik) : Decode a 'punycoded' IDN hostname. (bug 1264451) 429 // TODO(jungshik) : Decode a 'punycoded' IDN hostname. (bug 1264451)
437 filename = url.host(); 430 filename = url.host();
438 } 431 }
439 432
440 bool replace_trailing = false; 433 bool replace_trailing = false;
441 base::FilePath::StringType result_str, default_name_str; 434 base::FilePath::StringType result_str, default_name_str;
442 #if defined(OS_WIN) 435 #if defined(OS_WIN)
443 replace_trailing = true; 436 replace_trailing = true;
444 result_str = base::UTF8ToUTF16(filename); 437 result_str = base::UTF8ToUTF16(filename);
445 default_name_str = base::UTF8ToUTF16(default_name); 438 default_name_str = base::UTF8ToUTF16(default_name);
446 #else 439 #else
447 result_str = filename; 440 result_str = filename;
448 default_name_str = default_name; 441 default_name_str = default_name;
449 #endif 442 #endif
450 SanitizeGeneratedFileName(&result_str, replace_trailing); 443 SanitizeGeneratedFileName(&result_str, replace_trailing);
451 if (result_str.find_last_not_of(FILE_PATH_LITERAL("-_")) == 444 if (result_str.find_last_not_of(FILE_PATH_LITERAL("-_")) ==
452 base::FilePath::StringType::npos) { 445 base::FilePath::StringType::npos) {
453 result_str = !default_name_str.empty() ? default_name_str : 446 result_str = !default_name_str.empty()
454 base::FilePath::StringType(kFinalFallbackName); 447 ? default_name_str
448 : base::FilePath::StringType(kFinalFallbackName);
455 overwrite_extension = false; 449 overwrite_extension = false;
456 } 450 }
457 file_util::ReplaceIllegalCharactersInPath(&result_str, '-'); 451 file_util::ReplaceIllegalCharactersInPath(&result_str, '-');
458 base::FilePath result(result_str); 452 base::FilePath result(result_str);
459 GenerateSafeFileName(mime_type, overwrite_extension, &result); 453 GenerateSafeFileName(mime_type, overwrite_extension, &result);
460 454
461 base::string16 result16; 455 base::string16 result16;
462 if (!FilePathToString16(result, &result16)) { 456 if (!FilePathToString16(result, &result16)) {
463 result = base::FilePath(default_name_str); 457 result = base::FilePath(default_name_str);
464 if (!FilePathToString16(result, &result16)) { 458 if (!FilePathToString16(result, &result16)) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 // utf8 encoded characters in name. 490 // utf8 encoded characters in name.
497 file_util::NormalizeFileNameEncoding(&generated_name); 491 file_util::NormalizeFileNameEncoding(&generated_name);
498 #endif 492 #endif
499 493
500 DCHECK(!generated_name.empty()); 494 DCHECK(!generated_name.empty());
501 495
502 return generated_name; 496 return generated_name;
503 } 497 }
504 498
505 } // namespace net 499 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698