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"
21 using content::BrowserThread
;
25 const char kMimeTypeApplicationOctetStream
[] = "application/octet-stream";
29 namespace extensions
{
30 namespace app_file_handler_util
{
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],
44 net::FilePathToFileURL(local_path
),
45 std::string(), // type_hint (passes no hint)
50 #if defined(OS_CHROMEOS)
51 // Converts a result passed as a scoped pointer to a dereferenced value passed
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
62 void OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted(
63 const base::FilePath
& local_path
,
64 const base::Callback
<void(const std::string
&)>& callback
,
66 const std::string
& mime_type
) {
68 callback
.Run(mime_type
);
72 // MIME type not available with metadata, hence try to guess it from the
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(
79 base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile
),
81 mime_type_from_extension_ptr
),
82 base::Bind(&OnGetMimeTypeFromFileForNonNativeLocalPathCompleted
,
83 base::Passed(&mime_type_from_extension
),
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
);
101 callback
.Run(*mime_type
);
106 // Handles response of net::GetMimeTypeFromFile for native file systems. If
107 // MIME type is available, then forwards it to |callback|. Otherwise, fallbacks
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
);
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(
123 base::Bind(&SniffMimeType
, local_path
, sniffed_mime_type_ptr
),
124 base::Bind(&OnSniffMimeTypeForNativeLocalPathCompleted
,
125 base::Passed(&sniffed_mime_type
),
129 // Fetches MIME type for a local path and returns it with a |callback|.
130 void GetMimeTypeForLocalPath(
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(
142 base::Bind(&OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted
,
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(
156 base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile
),
158 mime_type_from_extension_ptr
),
159 base::Bind(&OnGetMimeTypeFromFileForNativeLocalPathCompleted
,
161 base::Passed(&mime_type_from_extension
),
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();
194 // Nothing to process.
195 base::ThreadTaskRunnerHandle::Get()->PostTask(
196 FROM_HERE
, base::Bind(callback_
, base::Passed(&result_
)));
197 callback_
= CompletionCallback();
201 for (size_t i
= 0; i
< local_paths
.size(); ++i
) {
202 GetMimeTypeForLocalPath(profile_
,
204 base::Bind(&MimeTypeCollector::OnMimeTypeCollected
,
205 weak_ptr_factory_
.GetWeakPtr(),
210 void MimeTypeCollector::OnMimeTypeCollected(size_t index
,
211 const std::string
& mime_type
) {
212 (*result_
)[index
] = mime_type
;
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
219 callback_
= CompletionCallback();
223 } // namespace app_file_handler_util
224 } // namespace extensions