1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
// Copyright 2013 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 "chrome/browser/extensions/api/file_handlers/mime_util.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/filename_util.h"
#include "net/base/mime_sniffer.h"
#include "net/base/mime_util.h"
#include "storage/browser/fileapi/file_system_url.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
#endif
using content::BrowserThread;
namespace extensions {
namespace app_file_handler_util {
namespace {
// Detects MIME type by reading initial bytes from the file. If found, then
// writes the MIME type to |result|.
void SniffMimeType(const base::FilePath& local_path, std::string* result) {
std::vector<char> content(net::kMaxBytesToSniff);
const int bytes_read =
base::ReadFile(local_path, &content[0], content.size());
if (bytes_read >= 0) {
net::SniffMimeType(&content[0],
bytes_read,
net::FilePathToFileURL(local_path),
std::string(), // type_hint (passes no hint)
result);
}
}
#if defined(OS_CHROMEOS)
// Converts a result passed as a scoped pointer to a dereferenced value passed
// to |callback|.
void OnGetMimeTypeFromFileForNonNativeLocalPathCompleted(
scoped_ptr<std::string> mime_type,
const base::Callback<void(const std::string&)>& callback) {
callback.Run(*mime_type);
}
// Called when fetching MIME type for a non-native local path is completed.
// If |success| is false, then tries to guess the MIME type by looking at the
// file name.
void OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted(
const base::FilePath& local_path,
const base::Callback<void(const std::string&)>& callback,
bool success,
const std::string& mime_type) {
if (success) {
callback.Run(mime_type);
return;
}
// MIME type not available with metadata, hence try to guess it from the
// file's extension.
scoped_ptr<std::string> mime_type_from_extension(new std::string);
std::string* const mime_type_from_extension_ptr =
mime_type_from_extension.get();
BrowserThread::PostBlockingPoolTaskAndReply(
FROM_HERE,
base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
local_path,
mime_type_from_extension_ptr),
base::Bind(&OnGetMimeTypeFromFileForNonNativeLocalPathCompleted,
base::Passed(&mime_type_from_extension),
callback));
}
#endif
// Called when sniffing for MIME type in the native local file is completed.
void OnSniffMimeTypeForNativeLocalPathCompleted(
scoped_ptr<std::string> mime_type,
const base::Callback<void(const std::string&)>& callback) {
callback.Run(*mime_type);
}
} // namespace
// Handles response of net::GetMimeTypeFromFile for native file systems. If
// MIME type is available, then forwards it to |callback|. Otherwise, fallbacks
// to sniffing.
void OnGetMimeTypeFromFileForNativeLocalPathCompleted(
const base::FilePath& local_path,
scoped_ptr<std::string> mime_type,
const base::Callback<void(const std::string&)>& callback) {
if (!mime_type->empty()) {
callback.Run(*mime_type);
return;
}
scoped_ptr<std::string> sniffed_mime_type(new std::string);
std::string* const sniffed_mime_type_ptr = sniffed_mime_type.get();
BrowserThread::PostBlockingPoolTaskAndReply(
FROM_HERE,
base::Bind(&SniffMimeType, local_path, sniffed_mime_type_ptr),
base::Bind(&OnSniffMimeTypeForNativeLocalPathCompleted,
base::Passed(&sniffed_mime_type),
callback));
}
// Fetches MIME type for a local path and returns it with a |callback|.
void GetMimeTypeForLocalPath(
Profile* profile,
const base::FilePath& local_path,
const base::Callback<void(const std::string&)>& callback) {
#if defined(OS_CHROMEOS)
if (file_manager::util::IsUnderNonNativeLocalPath(profile, local_path)) {
// For non-native files, try to get the MIME type from metadata. If not
// available, then try to guess from the extension. Never sniff (because
// it can be very slow).
file_manager::util::GetNonNativeLocalPathMimeType(
profile,
local_path,
base::Bind(&OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted,
local_path,
callback));
return;
}
#endif
// For native local files, try to guess the mime from the extension. If
// not available, then try to sniff if.
scoped_ptr<std::string> mime_type_from_extension(new std::string);
std::string* const mime_type_from_extension_ptr =
mime_type_from_extension.get();
BrowserThread::PostBlockingPoolTaskAndReply(
FROM_HERE,
base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
local_path,
mime_type_from_extension_ptr),
base::Bind(&OnGetMimeTypeFromFileForNativeLocalPathCompleted,
local_path,
base::Passed(&mime_type_from_extension),
callback));
}
MimeTypeCollector::MimeTypeCollector(Profile* profile)
: profile_(profile), left_(0), weak_ptr_factory_(this) {
}
MimeTypeCollector::~MimeTypeCollector() {
}
void MimeTypeCollector::CollectForURLs(
const std::vector<storage::FileSystemURL>& urls,
const CompletionCallback& callback) {
std::vector<base::FilePath> local_paths;
for (size_t i = 0; i < urls.size(); ++i) {
local_paths.push_back(urls[i].path());
}
CollectForLocalPaths(local_paths, callback);
}
void MimeTypeCollector::CollectForLocalPaths(
const std::vector<base::FilePath>& local_paths,
const CompletionCallback& callback) {
DCHECK(!callback.is_null());
callback_ = callback;
DCHECK(!result_.get());
result_.reset(new std::vector<std::string>(local_paths.size()));
left_ = local_paths.size();
if (!left_) {
// Nothing to process.
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
callback_ = CompletionCallback();
return;
}
for (size_t i = 0; i < local_paths.size(); ++i) {
GetMimeTypeForLocalPath(profile_,
local_paths[i],
base::Bind(&MimeTypeCollector::OnMimeTypeCollected,
weak_ptr_factory_.GetWeakPtr(),
i));
}
}
void MimeTypeCollector::OnMimeTypeCollected(size_t index,
const std::string& mime_type) {
(*result_)[index] = mime_type;
if (!--left_) {
base::MessageLoopProxy::current()->PostTask(
FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
// Release the callback to avoid a circullar reference in case an instance
// of this class is a member of a ref counted class, which instance is bound
// to this callback.
callback_ = CompletionCallback();
}
}
} // namespace app_file_handler_util
} // namespace extensions
|