Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / file_handlers / mime_util.cc
blob76c0534e257ef14342dab992ca11ff6308cc2e85
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "net/base/filename_util.h"
13 #include "net/base/mime_sniffer.h"
14 #include "net/base/mime_util.h"
15 #include "storage/browser/fileapi/file_system_url.h"
17 #if defined(OS_CHROMEOS)
18 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
19 #endif
21 using content::BrowserThread;
23 namespace {
25 const char kMimeTypeApplicationOctetStream[] = "application/octet-stream";
27 } // namespace
29 namespace extensions {
30 namespace app_file_handler_util {
31 namespace {
33 // Detects MIME type by reading initial bytes from the file. If found, then
34 // writes the MIME type to |result|.
35 void SniffMimeType(const base::FilePath& local_path, std::string* result) {
36 std::vector<char> content(net::kMaxBytesToSniff);
38 const int bytes_read =
39 base::ReadFile(local_path, &content[0], content.size());
41 if (bytes_read >= 0) {
42 net::SniffMimeType(&content[0],
43 bytes_read,
44 net::FilePathToFileURL(local_path),
45 std::string(), // type_hint (passes no hint)
46 result);
50 #if defined(OS_CHROMEOS)
51 // Converts a result passed as a scoped pointer to a dereferenced value passed
52 // to |callback|.
53 void OnGetMimeTypeFromFileForNonNativeLocalPathCompleted(
54 scoped_ptr<std::string> mime_type,
55 const base::Callback<void(const std::string&)>& callback) {
56 callback.Run(*mime_type);
59 // Called when fetching MIME type for a non-native local path is completed.
60 // If |success| is false, then tries to guess the MIME type by looking at the
61 // file name.
62 void OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted(
63 const base::FilePath& local_path,
64 const base::Callback<void(const std::string&)>& callback,
65 bool success,
66 const std::string& mime_type) {
67 if (success) {
68 callback.Run(mime_type);
69 return;
72 // MIME type not available with metadata, hence try to guess it from the
73 // file's extension.
74 scoped_ptr<std::string> mime_type_from_extension(new std::string);
75 std::string* const mime_type_from_extension_ptr =
76 mime_type_from_extension.get();
77 BrowserThread::PostBlockingPoolTaskAndReply(
78 FROM_HERE,
79 base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
80 local_path,
81 mime_type_from_extension_ptr),
82 base::Bind(&OnGetMimeTypeFromFileForNonNativeLocalPathCompleted,
83 base::Passed(&mime_type_from_extension),
84 callback));
86 #endif
88 // Called when sniffing for MIME type in the native local file is completed.
89 void OnSniffMimeTypeForNativeLocalPathCompleted(
90 scoped_ptr<std::string> mime_type,
91 const base::Callback<void(const std::string&)>& callback) {
92 // Do not return application/zip as sniffed result. If the file has .zip
93 // extension, it should be already returned as application/zip. If the file
94 // does not have .zip extension and couldn't find mime type from the
95 // extension, it might be unknown internally zipped file.
96 if (*mime_type == "application/zip") {
97 callback.Run(kMimeTypeApplicationOctetStream);
98 return;
101 callback.Run(*mime_type);
104 } // namespace
106 // Handles response of net::GetMimeTypeFromFile for native file systems. If
107 // MIME type is available, then forwards it to |callback|. Otherwise, fallbacks
108 // to sniffing.
109 void OnGetMimeTypeFromFileForNativeLocalPathCompleted(
110 const base::FilePath& local_path,
111 scoped_ptr<std::string> mime_type,
112 const base::Callback<void(const std::string&)>& callback) {
113 if (!mime_type->empty()) {
114 callback.Run(*mime_type);
115 return;
118 scoped_ptr<std::string> sniffed_mime_type(
119 new std::string(kMimeTypeApplicationOctetStream));
120 std::string* const sniffed_mime_type_ptr = sniffed_mime_type.get();
121 BrowserThread::PostBlockingPoolTaskAndReply(
122 FROM_HERE,
123 base::Bind(&SniffMimeType, local_path, sniffed_mime_type_ptr),
124 base::Bind(&OnSniffMimeTypeForNativeLocalPathCompleted,
125 base::Passed(&sniffed_mime_type),
126 callback));
129 // Fetches MIME type for a local path and returns it with a |callback|.
130 void GetMimeTypeForLocalPath(
131 Profile* profile,
132 const base::FilePath& local_path,
133 const base::Callback<void(const std::string&)>& callback) {
134 #if defined(OS_CHROMEOS)
135 if (file_manager::util::IsUnderNonNativeLocalPath(profile, local_path)) {
136 // For non-native files, try to get the MIME type from metadata. If not
137 // available, then try to guess from the extension. Never sniff (because
138 // it can be very slow).
139 file_manager::util::GetNonNativeLocalPathMimeType(
140 profile,
141 local_path,
142 base::Bind(&OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted,
143 local_path,
144 callback));
145 return;
147 #endif
149 // For native local files, try to guess the mime from the extension. If
150 // not available, then try to sniff if.
151 scoped_ptr<std::string> mime_type_from_extension(new std::string);
152 std::string* const mime_type_from_extension_ptr =
153 mime_type_from_extension.get();
154 BrowserThread::PostBlockingPoolTaskAndReply(
155 FROM_HERE,
156 base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
157 local_path,
158 mime_type_from_extension_ptr),
159 base::Bind(&OnGetMimeTypeFromFileForNativeLocalPathCompleted,
160 local_path,
161 base::Passed(&mime_type_from_extension),
162 callback));
165 MimeTypeCollector::MimeTypeCollector(Profile* profile)
166 : profile_(profile), left_(0), weak_ptr_factory_(this) {
169 MimeTypeCollector::~MimeTypeCollector() {
172 void MimeTypeCollector::CollectForURLs(
173 const std::vector<storage::FileSystemURL>& urls,
174 const CompletionCallback& callback) {
175 std::vector<base::FilePath> local_paths;
176 for (size_t i = 0; i < urls.size(); ++i) {
177 local_paths.push_back(urls[i].path());
180 CollectForLocalPaths(local_paths, callback);
183 void MimeTypeCollector::CollectForLocalPaths(
184 const std::vector<base::FilePath>& local_paths,
185 const CompletionCallback& callback) {
186 DCHECK(!callback.is_null());
187 callback_ = callback;
189 DCHECK(!result_.get());
190 result_.reset(new std::vector<std::string>(local_paths.size()));
191 left_ = local_paths.size();
193 if (!left_) {
194 // Nothing to process.
195 base::ThreadTaskRunnerHandle::Get()->PostTask(
196 FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
197 callback_ = CompletionCallback();
198 return;
201 for (size_t i = 0; i < local_paths.size(); ++i) {
202 GetMimeTypeForLocalPath(profile_,
203 local_paths[i],
204 base::Bind(&MimeTypeCollector::OnMimeTypeCollected,
205 weak_ptr_factory_.GetWeakPtr(),
206 i));
210 void MimeTypeCollector::OnMimeTypeCollected(size_t index,
211 const std::string& mime_type) {
212 (*result_)[index] = mime_type;
213 if (!--left_) {
214 base::ThreadTaskRunnerHandle::Get()->PostTask(
215 FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
216 // Release the callback to avoid a circullar reference in case an instance
217 // of this class is a member of a ref counted class, which instance is bound
218 // to this callback.
219 callback_ = CompletionCallback();
223 } // namespace app_file_handler_util
224 } // namespace extensions