mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@329 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
		
			
				
	
	
		
			190 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
 | 
						|
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
 | 
						|
#include "download_util.h"
 | 
						|
 | 
						|
#include "base/file_path.h"
 | 
						|
#include "base/string16.h"
 | 
						|
#include "base/string_util.h"
 | 
						|
#include "base/sys_string_conversions.h"
 | 
						|
#include "base/utf_string_conversions.h"
 | 
						|
#include "base/threading/thread.h"
 | 
						|
#include "base/threading/thread_restrictions.h"
 | 
						|
#include "googleurl/src/gurl.h"
 | 
						|
#include "net/base/mime_util.h"
 | 
						|
#include "net/base/net_util.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
#if defined(OS_WIN)
 | 
						|
// Returns whether the specified extension is automatically integrated into the
 | 
						|
// windows shell.
 | 
						|
// From chrome/browser/download/download_util.cc
 | 
						|
bool IsShellIntegratedExtension(const string16& extension) {
 | 
						|
  string16 extension_lower = StringToLowerASCII(extension);
 | 
						|
  
 | 
						|
  static const wchar_t* const integrated_extensions[] = {
 | 
						|
    // See <http://msdn.microsoft.com/en-us/library/ms811694.aspx>.
 | 
						|
    L"local",
 | 
						|
    // Right-clicking on shortcuts can be magical.
 | 
						|
    L"lnk",
 | 
						|
  };
 | 
						|
  
 | 
						|
  for (int i = 0; i < arraysize(integrated_extensions); ++i) {
 | 
						|
    if (extension_lower == integrated_extensions[i])
 | 
						|
      return true;
 | 
						|
  }
 | 
						|
  
 | 
						|
  // See <http://www.juniper.net/security/auto/vulnerabilities/vuln2612.html>.
 | 
						|
  // That vulnerability report is not exactly on point, but files become magical
 | 
						|
  // if their end in a CLSID.  Here we block extensions that look like CLSIDs.
 | 
						|
  if (extension_lower.size() > 0 && extension_lower.at(0) == L'{' &&
 | 
						|
      extension_lower.at(extension_lower.length() - 1) == L'}')
 | 
						|
    return true;
 | 
						|
  
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
// Returns whether the specified file name is a reserved name on windows.
 | 
						|
// This includes names like "com2.zip" (which correspond to devices) and
 | 
						|
// desktop.ini and thumbs.db which have special meaning to the windows shell.
 | 
						|
// From chrome/browser/download/download_util.cc
 | 
						|
bool IsReservedName(const string16& filename) {
 | 
						|
  // This list is taken from the MSDN article "Naming a file"
 | 
						|
  // http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx
 | 
						|
  // I also added clock$ because GetSaveFileName seems to consider it as a
 | 
						|
  // reserved name too.
 | 
						|
  static const wchar_t* const known_devices[] = {
 | 
						|
    L"con", L"prn", L"aux", L"nul", L"com1", L"com2", L"com3", L"com4", L"com5",
 | 
						|
    L"com6", L"com7", L"com8", L"com9", L"lpt1", L"lpt2", L"lpt3", L"lpt4",
 | 
						|
    L"lpt5", L"lpt6", L"lpt7", L"lpt8", L"lpt9", L"clock$"
 | 
						|
  };
 | 
						|
  string16 filename_lower = StringToLowerASCII(filename);
 | 
						|
  
 | 
						|
  for (int i = 0; i < arraysize(known_devices); ++i) {
 | 
						|
    // Exact match.
 | 
						|
    if (filename_lower == known_devices[i])
 | 
						|
      return true;
 | 
						|
    // Starts with "DEVICE.".
 | 
						|
    if (filename_lower.find(string16(known_devices[i]) + L".") == 0)
 | 
						|
      return true;
 | 
						|
  }
 | 
						|
  
 | 
						|
  static const wchar_t* const magic_names[] = {
 | 
						|
    // These file names are used by the "Customize folder" feature of the shell.
 | 
						|
    L"desktop.ini",
 | 
						|
    L"thumbs.db",
 | 
						|
  };
 | 
						|
  
 | 
						|
  for (int i = 0; i < arraysize(magic_names); ++i) {
 | 
						|
    if (filename_lower == magic_names[i])
 | 
						|
      return true;
 | 
						|
  }
 | 
						|
  
 | 
						|
  return false;
 | 
						|
}
 | 
						|
#endif  // OS_WIN
 | 
						|
 | 
						|
// Create an extension based on the file name and mime type.
 | 
						|
// From chrome/browser/download/download_util.cc
 | 
						|
void GenerateExtension(const FilePath& file_name,
 | 
						|
                       const std::string& mime_type,
 | 
						|
                       FilePath::StringType* generated_extension) {
 | 
						|
  // We're worried about two things here:
 | 
						|
  //
 | 
						|
  // 1) Usability.  If the site fails to provide a file extension, we want to
 | 
						|
  //    guess a reasonable file extension based on the content type.
 | 
						|
  //
 | 
						|
  // 2) Shell integration.  Some file extensions automatically integrate with
 | 
						|
  //    the shell.  We block these extensions to prevent a malicious web site
 | 
						|
  //    from integrating with the user's shell.
 | 
						|
  
 | 
						|
  // See if our file name already contains an extension.
 | 
						|
  FilePath::StringType extension = file_name.Extension();
 | 
						|
  if (!extension.empty())
 | 
						|
    extension.erase(extension.begin());  // Erase preceding '.'.
 | 
						|
  
 | 
						|
#if defined(OS_WIN)
 | 
						|
  static const FilePath::CharType default_extension[] =
 | 
						|
  FILE_PATH_LITERAL("download");
 | 
						|
  
 | 
						|
  // Rename shell-integrated extensions.
 | 
						|
  if (IsShellIntegratedExtension(extension))
 | 
						|
    extension.assign(default_extension);
 | 
						|
#endif
 | 
						|
  
 | 
						|
  if (extension.empty()) {
 | 
						|
    // The GetPreferredExtensionForMimeType call will end up going to disk.  Do
 | 
						|
    // this on another thread to avoid slowing the IO thread.
 | 
						|
    // http://crbug.com/61827
 | 
						|
    base::ThreadRestrictions::ScopedAllowIO allow_io;
 | 
						|
    net::GetPreferredExtensionForMimeType(mime_type, &extension);
 | 
						|
  }
 | 
						|
  
 | 
						|
  generated_extension->swap(extension);
 | 
						|
}
 | 
						|
 | 
						|
// Used to make sure we have a safe file extension and filename for a
 | 
						|
// download.  |file_name| can either be just the file name or it can be a
 | 
						|
// full path to a file.
 | 
						|
// From chrome/browser/download/download_util.cc
 | 
						|
void GenerateSafeFileName(const std::string& mime_type, FilePath* file_name) {
 | 
						|
  // Make sure we get the right file extension
 | 
						|
  FilePath::StringType extension;
 | 
						|
  GenerateExtension(*file_name, mime_type, &extension);
 | 
						|
  *file_name = file_name->ReplaceExtension(extension);
 | 
						|
  
 | 
						|
#if defined(OS_WIN)
 | 
						|
  // Prepend "_" to the file name if it's a reserved name
 | 
						|
  FilePath::StringType leaf_name = file_name->BaseName().value();
 | 
						|
  DCHECK(!leaf_name.empty());
 | 
						|
  if (IsReservedName(leaf_name)) {
 | 
						|
    leaf_name = FilePath::StringType(FILE_PATH_LITERAL("_")) + leaf_name;
 | 
						|
    *file_name = file_name->DirName();
 | 
						|
    if (file_name->value() == FilePath::kCurrentDirectory) {
 | 
						|
      *file_name = FilePath(leaf_name);
 | 
						|
    } else {
 | 
						|
      *file_name = file_name->Append(leaf_name);
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
}
 | 
						|
  
 | 
						|
} // namespace
 | 
						|
 | 
						|
namespace download_util {
 | 
						|
 | 
						|
// Create a file name based on the response from the server.
 | 
						|
// From chrome/browser/download/download_util.cc
 | 
						|
void GenerateFileName(const GURL& url,
 | 
						|
                      const std::string& content_disposition,
 | 
						|
                      const std::string& referrer_charset,
 | 
						|
                      const std::string& mime_type,
 | 
						|
                      const std::string& suggested_name,
 | 
						|
                      FilePath* generated_name) {
 | 
						|
  string16 new_name = net::GetSuggestedFilename(GURL(url),
 | 
						|
                                                content_disposition,
 | 
						|
                                                referrer_charset,
 | 
						|
                                                suggested_name,
 | 
						|
                                                mime_type,
 | 
						|
                                                "download");
 | 
						|
  
 | 
						|
  // 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.
 | 
						|
#if defined(OS_WIN)
 | 
						|
  *generated_name = FilePath(new_name);
 | 
						|
#else
 | 
						|
  *generated_name = FilePath(base::SysWideToNativeMB(UTF16ToWide(new_name)));
 | 
						|
#endif
 | 
						|
  
 | 
						|
  DCHECK(!generated_name->empty());
 | 
						|
  
 | 
						|
  GenerateSafeFileName(mime_type, generated_name);
 | 
						|
}
 | 
						|
 | 
						|
} // namespace download_util
 |