summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormtomasz <mtomasz@chromium.org>2014-09-01 00:56:20 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-01 07:58:26 +0000
commit47501847827d29b4ba148a161a521eb3cd5b0730 (patch)
treea8cf902ba1474430f4bff20df37934fe6ce22cc2 /chrome
parente0ce97e9f1afa1f28c1c1261e5372d03b2af1cdb (diff)
downloadchromium_src-47501847827d29b4ba148a161a521eb3cd5b0730.zip
chromium_src-47501847827d29b4ba148a161a521eb3cd5b0730.tar.gz
chromium_src-47501847827d29b4ba148a161a521eb3cd5b0730.tar.bz2
[fsp] Add support for providing thumbnails.
Previously, thumbnails were generated from full size images, which in case of cloud providers would invoke downloading the entire file. This CL adds an ability to provide a thumbnail as a data URI, so: (1) We can have thumbnails for other file types than images. (2) Thumbnails are shown fast. (3) Resource consumption is significantly reduced. Note, that the thumbnails are not wired to Files app yet. That will be done in a separate patch. TEST=unit_tests: *FileSystemProvider*GetMetadata* BUG=407954 Review URL: https://codereview.chromium.org/513683002 Cr-Commit-Position: refs/heads/master@{#292840}
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/file_manager/filesystem_api_util.cc6
-rw-r--r--chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc84
-rw-r--r--chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h24
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc23
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h5
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc75
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc34
-rw-r--r--chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc33
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc43
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/get_metadata.h4
-rw-r--r--chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc152
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system.cc6
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system.h1
-rw-r--r--chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h24
-rw-r--r--chrome/common/extensions/api/file_system_provider.idl10
-rw-r--r--chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js60
16 files changed, 415 insertions, 169 deletions
diff --git a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
index 259384e..ba44d37 100644
--- a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
+++ b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
@@ -46,7 +46,7 @@ void GetMimeTypeAfterGetResourceEntryForDrive(
// the mime type from the passed metadata from a providing extension.
void GetMimeTypeAfterGetMetadataForProvidedFileSystem(
const base::Callback<void(bool, const std::string&)>& callback,
- const chromeos::file_system_provider::EntryMetadata& metadata,
+ scoped_ptr<chromeos::file_system_provider::EntryMetadata> metadata,
base::File::Error result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -54,7 +54,7 @@ void GetMimeTypeAfterGetMetadataForProvidedFileSystem(
callback.Run(false, std::string());
return;
}
- callback.Run(true, metadata.mime_type);
+ callback.Run(true, metadata->mime_type);
}
// Helper function to converts a callback that takes boolean value to that takes
@@ -170,6 +170,8 @@ void GetNonNativeLocalPathMimeType(
parser.file_system()->GetMetadata(
parser.file_path(),
+ chromeos::file_system_provider::ProvidedFileSystemInterface::
+ METADATA_FIELD_DEFAULT,
base::Bind(&GetMimeTypeAfterGetMetadataForProvidedFileSystem,
callback));
return;
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
index 70f1aa3..1db2ee0 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
+++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
@@ -23,6 +23,17 @@ const char kFakeFileMimeType[] = "text/plain";
const char kFakeFilePath[] = "/hello.txt";
+FakeEntry::FakeEntry() {
+}
+
+FakeEntry::FakeEntry(scoped_ptr<EntryMetadata> metadata,
+ const std::string& contents)
+ : metadata(metadata.Pass()), contents(contents) {
+}
+
+FakeEntry::~FakeEntry() {
+}
+
FakeProvidedFileSystem::FakeProvidedFileSystem(
const ProvidedFileSystemInfo& file_system_info)
: file_system_info_(file_system_info),
@@ -52,25 +63,25 @@ void FakeProvidedFileSystem::AddEntry(const base::FilePath& entry_path,
std::string mime_type,
std::string contents) {
DCHECK(entries_.find(entry_path) == entries_.end());
- EntryMetadata metadata;
+ scoped_ptr<EntryMetadata> metadata(new EntryMetadata);
- metadata.is_directory = is_directory;
- metadata.name = name;
- metadata.size = size;
- metadata.modification_time = modification_time;
- metadata.mime_type = mime_type;
+ metadata->is_directory = is_directory;
+ metadata->name = name;
+ metadata->size = size;
+ metadata->modification_time = modification_time;
+ metadata->mime_type = mime_type;
- entries_[entry_path] = FakeEntry(metadata, contents);
+ entries_[entry_path] =
+ make_linked_ptr(new FakeEntry(metadata.Pass(), contents));
}
-bool FakeProvidedFileSystem::GetEntry(const base::FilePath& entry_path,
- FakeEntry* fake_entry) const {
+const FakeEntry* FakeProvidedFileSystem::GetEntry(
+ const base::FilePath& entry_path) const {
const Entries::const_iterator entry_it = entries_.find(entry_path);
if (entry_it == entries_.end())
- return false;
+ return NULL;
- *fake_entry = entry_it->second;
- return true;
+ return entry_it->second.get();
}
ProvidedFileSystemInterface::AbortCallback
@@ -81,16 +92,27 @@ FakeProvidedFileSystem::RequestUnmount(
ProvidedFileSystemInterface::AbortCallback FakeProvidedFileSystem::GetMetadata(
const base::FilePath& entry_path,
+ ProvidedFileSystemInterface::MetadataFieldMask fields,
const ProvidedFileSystemInterface::GetMetadataCallback& callback) {
const Entries::const_iterator entry_it = entries_.find(entry_path);
if (entry_it == entries_.end()) {
- return PostAbortableTask(base::Bind(
- callback, EntryMetadata(), base::File::FILE_ERROR_NOT_FOUND));
+ return PostAbortableTask(
+ base::Bind(callback,
+ base::Passed(make_scoped_ptr<EntryMetadata>(NULL)),
+ base::File::FILE_ERROR_NOT_FOUND));
}
+ scoped_ptr<EntryMetadata> metadata(new EntryMetadata);
+ metadata->is_directory = entry_it->second->metadata->is_directory;
+ metadata->name = entry_it->second->metadata->name;
+ metadata->size = entry_it->second->metadata->size;
+ metadata->modification_time = entry_it->second->metadata->modification_time;
+ metadata->mime_type = entry_it->second->metadata->mime_type;
+ metadata->thumbnail = entry_it->second->metadata->thumbnail;
+
return PostAbortableTask(
- base::Bind(callback, entry_it->second.metadata, base::File::FILE_OK));
+ base::Bind(callback, base::Passed(&metadata), base::File::FILE_OK));
}
ProvidedFileSystemInterface::AbortCallback
@@ -103,13 +125,13 @@ FakeProvidedFileSystem::ReadDirectory(
++it) {
const base::FilePath file_path = it->first;
if (file_path == directory_path || directory_path.IsParent(file_path)) {
- const EntryMetadata& metadata = it->second.metadata;
+ const EntryMetadata* const metadata = it->second->metadata.get();
entry_list.push_back(storage::DirectoryEntry(
- metadata.name,
- metadata.is_directory ? storage::DirectoryEntry::DIRECTORY
- : storage::DirectoryEntry::FILE,
- metadata.size,
- metadata.modification_time));
+ metadata->name,
+ metadata->is_directory ? storage::DirectoryEntry::DIRECTORY
+ : storage::DirectoryEntry::FILE,
+ metadata->size,
+ metadata->modification_time));
}
}
@@ -182,19 +204,19 @@ ProvidedFileSystemInterface::AbortCallback FakeProvidedFileSystem::ReadFile(
int current_length = length;
// Reading behind EOF is fine, it will just return 0 bytes.
- if (current_offset >= entry_it->second.metadata.size || !current_length) {
+ if (current_offset >= entry_it->second->metadata->size || !current_length) {
return PostAbortableTask(base::Bind(callback,
0 /* chunk_length */,
false /* has_more */,
base::File::FILE_OK));
}
- const FakeEntry& entry = entry_it->second;
+ const FakeEntry* const entry = entry_it->second.get();
std::vector<int> task_ids;
- while (current_offset < entry.metadata.size && current_length) {
- buffer->data()[current_offset - offset] = entry.contents[current_offset];
+ while (current_offset < entry->metadata->size && current_length) {
+ buffer->data()[current_offset - offset] = entry->contents[current_offset];
const bool has_more =
- (current_offset + 1 < entry.metadata.size) && (current_length - 1);
+ (current_offset + 1 < entry->metadata->size) && (current_length - 1);
const int task_id = tracker_.PostTask(
base::MessageLoopProxy::current(),
FROM_HERE,
@@ -283,16 +305,16 @@ ProvidedFileSystemInterface::AbortCallback FakeProvidedFileSystem::WriteFile(
base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
}
- FakeEntry* const entry = &entry_it->second;
- if (offset > entry->metadata.size) {
+ FakeEntry* const entry = entry_it->second.get();
+ if (offset > entry->metadata->size) {
return PostAbortableTask(
base::Bind(callback, base::File::FILE_ERROR_INVALID_OPERATION));
}
// Allocate the string size in advance.
- if (offset + length > entry->metadata.size) {
- entry->metadata.size = offset + length;
- entry->contents.resize(entry->metadata.size);
+ if (offset + length > entry->metadata->size) {
+ entry->metadata->size = offset + length;
+ entry->contents.resize(entry->metadata->size);
}
entry->contents.replace(offset, length, buffer->data(), length);
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
index cf2a02a..f19f176 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
+++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/memory/linked_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
@@ -36,15 +37,15 @@ extern const char kFakeFilePath[];
// Represents a file or a directory on a fake file system.
struct FakeEntry {
- FakeEntry() {}
+ FakeEntry();
+ FakeEntry(scoped_ptr<EntryMetadata> metadata, const std::string& contents);
+ ~FakeEntry();
- FakeEntry(const EntryMetadata& metadata, const std::string& contents)
- : metadata(metadata), contents(contents) {}
-
- virtual ~FakeEntry() {}
-
- EntryMetadata metadata;
+ scoped_ptr<EntryMetadata> metadata;
std::string contents;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeEntry);
};
// Fake provided file system implementation. Does not communicate with target
@@ -65,15 +66,16 @@ class FakeProvidedFileSystem : public ProvidedFileSystemInterface {
std::string contents);
// Fetches a pointer to a fake entry registered in the fake file system. If
- // found, then the result is written to |fake_entry| and true is returned.
- // Otherwise, false is returned. |fake_entry| must not be NULL.
- bool GetEntry(const base::FilePath& entry_path, FakeEntry* fake_entry) const;
+ // not found, then returns NULL. The returned pointes is owned by
+ // FakeProvidedFileSystem.
+ const FakeEntry* GetEntry(const base::FilePath& entry_path) const;
// ProvidedFileSystemInterface overrides.
virtual AbortCallback RequestUnmount(
const storage::AsyncFileUtil::StatusCallback& callback) OVERRIDE;
virtual AbortCallback GetMetadata(
const base::FilePath& entry_path,
+ ProvidedFileSystemInterface::MetadataFieldMask fields,
const ProvidedFileSystemInterface::GetMetadataCallback& callback)
OVERRIDE;
virtual AbortCallback ReadDirectory(
@@ -132,7 +134,7 @@ class FakeProvidedFileSystem : public ProvidedFileSystemInterface {
const ProvidedFileSystemInfo& file_system_info);
private:
- typedef std::map<base::FilePath, FakeEntry> Entries;
+ typedef std::map<base::FilePath, linked_ptr<FakeEntry> > Entries;
typedef std::map<int, base::FilePath> OpenedFilesMap;
// Utility function for posting a task which can be aborted by calling the
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc
index fa3b498..2998628 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.cc
@@ -114,12 +114,15 @@ class FileStreamReader::OperationRunner
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- base::Bind(callback, EntryMetadata(), base::File::FILE_ERROR_ABORT));
+ base::Bind(callback,
+ base::Passed(make_scoped_ptr<EntryMetadata>(NULL)),
+ base::File::FILE_ERROR_ABORT));
return;
}
abort_callback_ = file_system_->GetMetadata(
file_path_,
+ ProvidedFileSystemInterface::METADATA_FIELD_DEFAULT,
base::Bind(&OperationRunner::OnGetMetadataCompletedOnUIThread,
this,
callback));
@@ -166,11 +169,13 @@ class FileStreamReader::OperationRunner
// Forwards a metadata to the IO thread.
void OnGetMetadataCompletedOnUIThread(
const ProvidedFileSystemInterface::GetMetadataCallback& callback,
- const EntryMetadata& metadata,
+ scoped_ptr<EntryMetadata> metadata,
base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE, base::Bind(callback, metadata, result));
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, base::Passed(&metadata), result));
}
// Forwards a response of reading from a file to the IO thread.
@@ -282,7 +287,7 @@ void FileStreamReader::OnOpenFileCompleted(
void FileStreamReader::OnInitializeCompleted(
const base::Closure& pending_closure,
const net::Int64CompletionCallback& error_callback,
- const EntryMetadata& metadata,
+ scoped_ptr<EntryMetadata> metadata,
base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(INITIALIZING, state_);
@@ -296,8 +301,9 @@ void FileStreamReader::OnInitializeCompleted(
// If the file modification time has changed, then abort. Note, that the file
// may be changed without affecting the modification time.
+ DCHECK(metadata.get());
if (!expected_modification_time_.is_null() &&
- metadata.modification_time != expected_modification_time_) {
+ metadata->modification_time != expected_modification_time_) {
state_ = FAILED;
error_callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
return;
@@ -461,7 +467,7 @@ void FileStreamReader::OnReadChunkReceived(
void FileStreamReader::OnGetMetadataForGetLengthReceived(
const net::Int64CompletionCallback& callback,
- const EntryMetadata& metadata,
+ scoped_ptr<EntryMetadata> metadata,
base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(INITIALIZED, state_);
@@ -475,14 +481,15 @@ void FileStreamReader::OnGetMetadataForGetLengthReceived(
// If the file modification time has changed, then abort. Note, that the file
// may be changed without affecting the modification time.
+ DCHECK(metadata.get());
if (!expected_modification_time_.is_null() &&
- metadata.modification_time != expected_modification_time_) {
+ metadata->modification_time != expected_modification_time_) {
callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
return;
}
DCHECK_EQ(base::File::FILE_OK, result);
- callback.Run(metadata.size);
+ callback.Run(metadata->size);
}
} // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h
index 909bb8a..046336a 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "webkit/browser/blob/file_stream_reader.h"
#include "webkit/browser/fileapi/file_system_url.h"
@@ -69,7 +70,7 @@ class FileStreamReader : public storage::FileStreamReader {
// Called when initialization is completed with either a success or an error.
void OnInitializeCompleted(const base::Closure& pending_closure,
const net::Int64CompletionCallback& error_callback,
- const EntryMetadata& metadata,
+ scoped_ptr<EntryMetadata> metadata,
base::File::Error result);
// Called when a file system provider returns chunk of read data. Note, that
@@ -85,7 +86,7 @@ class FileStreamReader : public storage::FileStreamReader {
// or an error.
void OnGetMetadataForGetLengthReceived(
const net::Int64CompletionCallback& callback,
- const EntryMetadata& metadata,
+ scoped_ptr<EntryMetadata> metadata,
base::File::Error result);
// Same as Read(), but called after initializing is completed.
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc
index 70f16fa..2a4f2e7 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc
@@ -81,7 +81,7 @@ KeyedService* CreateService(content::BrowserContext* context) {
class FileSystemProviderFileStreamReader : public testing::Test {
protected:
- FileSystemProviderFileStreamReader() {}
+ FileSystemProviderFileStreamReader() : profile_(NULL), fake_file_(NULL) {}
virtual ~FileSystemProviderFileStreamReader() {}
virtual void SetUp() OVERRIDE {
@@ -105,8 +105,9 @@ class FileSystemProviderFileStreamReader : public testing::Test {
static_cast<FakeProvidedFileSystem*>(
service->GetProvidedFileSystem(kExtensionId, kFileSystemId));
ASSERT_TRUE(provided_file_system);
- ASSERT_TRUE(provided_file_system->GetEntry(
- base::FilePath::FromUTF8Unsafe(kFakeFilePath), &fake_file_));
+ fake_file_ = provided_file_system->GetEntry(
+ base::FilePath::FromUTF8Unsafe(kFakeFilePath));
+ ASSERT_TRUE(fake_file_);
const ProvidedFileSystemInfo& file_system_info =
service->GetProvidedFileSystem(kExtensionId, kFileSystemId)
->GetFileSystemInfo();
@@ -130,8 +131,8 @@ class FileSystemProviderFileStreamReader : public testing::Test {
content::TestBrowserThreadBundle thread_bundle_;
base::ScopedTempDir data_dir_;
scoped_ptr<TestingProfileManager> profile_manager_;
- TestingProfile* profile_; // Owned by TestingProfileManager.
- FakeEntry fake_file_;
+ TestingProfile* profile_; // Owned by TestingProfileManager.
+ const FakeEntry* fake_file_; // Owned by FakePRovidedFileSystem.
storage::FileSystemURL file_url_;
storage::FileSystemURL wrong_file_url_;
};
@@ -141,23 +142,23 @@ TEST_F(FileSystemProviderFileStreamReader, Read_AllAtOnce) {
const int64 initial_offset = 0;
FileStreamReader reader(
- NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
+ NULL, file_url_, initial_offset, fake_file_->metadata->modification_time);
scoped_refptr<net::IOBuffer> io_buffer(
- new net::IOBuffer(fake_file_.metadata.size));
+ new net::IOBuffer(fake_file_->metadata->size));
const int result =
reader.Read(io_buffer.get(),
- fake_file_.metadata.size,
+ fake_file_->metadata->size,
base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
EXPECT_EQ(net::ERR_IO_PENDING, result);
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, logger.results().size());
EXPECT_LT(0, logger.results()[0]);
- EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
+ EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]);
- std::string buffer_as_string(io_buffer->data(), fake_file_.metadata.size);
- EXPECT_EQ(fake_file_.contents, buffer_as_string);
+ std::string buffer_as_string(io_buffer->data(), fake_file_->metadata->size);
+ EXPECT_EQ(fake_file_->contents, buffer_as_string);
}
TEST_F(FileSystemProviderFileStreamReader, Read_WrongFile) {
@@ -167,13 +168,13 @@ TEST_F(FileSystemProviderFileStreamReader, Read_WrongFile) {
FileStreamReader reader(NULL,
wrong_file_url_,
initial_offset,
- fake_file_.metadata.modification_time);
+ fake_file_->metadata->modification_time);
scoped_refptr<net::IOBuffer> io_buffer(
- new net::IOBuffer(fake_file_.metadata.size));
+ new net::IOBuffer(fake_file_->metadata->size));
const int result =
reader.Read(io_buffer.get(),
- fake_file_.metadata.size,
+ fake_file_->metadata->size,
base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
EXPECT_EQ(net::ERR_IO_PENDING, result);
base::RunLoop().RunUntilIdle();
@@ -187,9 +188,9 @@ TEST_F(FileSystemProviderFileStreamReader, Read_InChunks) {
const int64 initial_offset = 0;
FileStreamReader reader(
- NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
+ NULL, file_url_, initial_offset, fake_file_->metadata->modification_time);
- for (int64 offset = 0; offset < fake_file_.metadata.size; ++offset) {
+ for (int64 offset = 0; offset < fake_file_->metadata->size; ++offset) {
scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(1));
const int result =
reader.Read(io_buffer.get(),
@@ -199,7 +200,7 @@ TEST_F(FileSystemProviderFileStreamReader, Read_InChunks) {
base::RunLoop().RunUntilIdle();
ASSERT_EQ(offset + 1, static_cast<int64>(logger.results().size()));
EXPECT_EQ(1, logger.results()[offset]);
- EXPECT_EQ(fake_file_.contents[offset], io_buffer->data()[0]);
+ EXPECT_EQ(fake_file_->contents[offset], io_buffer->data()[0]);
}
}
@@ -208,12 +209,12 @@ TEST_F(FileSystemProviderFileStreamReader, Read_Slice) {
// Trim first 3 and last 3 characters.
const int64 initial_offset = 3;
- const int length = fake_file_.metadata.size - initial_offset - 3;
- ASSERT_GT(fake_file_.metadata.size, initial_offset);
+ const int length = fake_file_->metadata->size - initial_offset - 3;
+ ASSERT_GT(fake_file_->metadata->size, initial_offset);
ASSERT_LT(0, length);
FileStreamReader reader(
- NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
+ NULL, file_url_, initial_offset, fake_file_->metadata->modification_time);
scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length));
const int result =
@@ -227,7 +228,7 @@ TEST_F(FileSystemProviderFileStreamReader, Read_Slice) {
EXPECT_EQ(length, logger.results()[0]);
std::string buffer_as_string(io_buffer->data(), length);
- std::string expected_buffer(fake_file_.contents.data() + initial_offset,
+ std::string expected_buffer(fake_file_->contents.data() + initial_offset,
length);
EXPECT_EQ(expected_buffer, buffer_as_string);
}
@@ -237,10 +238,10 @@ TEST_F(FileSystemProviderFileStreamReader, Read_Beyond) {
// Request reading 1KB more than available.
const int64 initial_offset = 0;
- const int length = fake_file_.metadata.size + 1024;
+ const int length = fake_file_->metadata->size + 1024;
FileStreamReader reader(
- NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
+ NULL, file_url_, initial_offset, fake_file_->metadata->modification_time);
scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length));
const int result =
@@ -252,10 +253,10 @@ TEST_F(FileSystemProviderFileStreamReader, Read_Beyond) {
ASSERT_EQ(1u, logger.results().size());
EXPECT_LT(0, logger.results()[0]);
- EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
+ EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]);
- std::string buffer_as_string(io_buffer->data(), fake_file_.metadata.size);
- EXPECT_EQ(fake_file_.contents, buffer_as_string);
+ std::string buffer_as_string(io_buffer->data(), fake_file_->metadata->size);
+ EXPECT_EQ(fake_file_->contents, buffer_as_string);
}
TEST_F(FileSystemProviderFileStreamReader, Read_ModifiedFile) {
@@ -265,10 +266,10 @@ TEST_F(FileSystemProviderFileStreamReader, Read_ModifiedFile) {
FileStreamReader reader(NULL, file_url_, initial_offset, base::Time::Max());
scoped_refptr<net::IOBuffer> io_buffer(
- new net::IOBuffer(fake_file_.metadata.size));
+ new net::IOBuffer(fake_file_->metadata->size));
const int result =
reader.Read(io_buffer.get(),
- fake_file_.metadata.size,
+ fake_file_->metadata->size,
base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
EXPECT_EQ(net::ERR_IO_PENDING, result);
@@ -285,20 +286,20 @@ TEST_F(FileSystemProviderFileStreamReader, Read_ExpectedModificationTimeNull) {
FileStreamReader reader(NULL, file_url_, initial_offset, base::Time());
scoped_refptr<net::IOBuffer> io_buffer(
- new net::IOBuffer(fake_file_.metadata.size));
+ new net::IOBuffer(fake_file_->metadata->size));
const int result =
reader.Read(io_buffer.get(),
- fake_file_.metadata.size,
+ fake_file_->metadata->size,
base::Bind(&EventLogger::OnRead, logger.GetWeakPtr()));
EXPECT_EQ(net::ERR_IO_PENDING, result);
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, logger.results().size());
- EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
+ EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]);
- std::string buffer_as_string(io_buffer->data(), fake_file_.metadata.size);
- EXPECT_EQ(fake_file_.contents, buffer_as_string);
+ std::string buffer_as_string(io_buffer->data(), fake_file_->metadata->size);
+ EXPECT_EQ(fake_file_->contents, buffer_as_string);
}
TEST_F(FileSystemProviderFileStreamReader, GetLength) {
@@ -306,7 +307,7 @@ TEST_F(FileSystemProviderFileStreamReader, GetLength) {
const int64 initial_offset = 0;
FileStreamReader reader(
- NULL, file_url_, initial_offset, fake_file_.metadata.modification_time);
+ NULL, file_url_, initial_offset, fake_file_->metadata->modification_time);
const int result = reader.GetLength(
base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr()));
@@ -315,7 +316,7 @@ TEST_F(FileSystemProviderFileStreamReader, GetLength) {
ASSERT_EQ(1u, logger.results().size());
EXPECT_LT(0, logger.results()[0]);
- EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
+ EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]);
}
TEST_F(FileSystemProviderFileStreamReader, GetLength_WrongFile) {
@@ -325,7 +326,7 @@ TEST_F(FileSystemProviderFileStreamReader, GetLength_WrongFile) {
FileStreamReader reader(NULL,
wrong_file_url_,
initial_offset,
- fake_file_.metadata.modification_time);
+ fake_file_->metadata->modification_time);
const int result = reader.GetLength(
base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr()));
@@ -365,7 +366,7 @@ TEST_F(FileSystemProviderFileStreamReader,
ASSERT_EQ(1u, logger.results().size());
EXPECT_LT(0, logger.results()[0]);
- EXPECT_EQ(fake_file_.metadata.size, logger.results()[0]);
+ EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]);
}
} // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc
index c1bf2aa..c978c19 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc
@@ -134,10 +134,12 @@ TEST_F(FileSystemProviderFileStreamWriter, Write) {
EXPECT_LT(0, write_log[0]);
EXPECT_EQ(sizeof(kTextToWrite) - 1, static_cast<size_t>(write_log[0]));
- FakeEntry entry;
- ASSERT_TRUE(provided_file_system_->GetEntry(
- base::FilePath::FromUTF8Unsafe(kFakeFilePath), &entry));
- EXPECT_EQ(kTextToWrite, entry.contents.substr(0, sizeof(kTextToWrite) - 1));
+ const FakeEntry* const entry = provided_file_system_->GetEntry(
+ base::FilePath::FromUTF8Unsafe(kFakeFilePath));
+ ASSERT_TRUE(entry);
+
+ EXPECT_EQ(kTextToWrite,
+ entry->contents.substr(0, sizeof(kTextToWrite) - 1));
}
// Write additional data to be sure, that the writer's offset is shifted
@@ -153,15 +155,15 @@ TEST_F(FileSystemProviderFileStreamWriter, Write) {
EXPECT_LT(0, write_log[0]);
EXPECT_EQ(sizeof(kTextToWrite) - 1, static_cast<size_t>(write_log[0]));
- FakeEntry entry;
- ASSERT_TRUE(provided_file_system_->GetEntry(
- base::FilePath::FromUTF8Unsafe(kFakeFilePath), &entry));
+ const FakeEntry* const entry = provided_file_system_->GetEntry(
+ base::FilePath::FromUTF8Unsafe(kFakeFilePath));
+ ASSERT_TRUE(entry);
// The testing text is written twice.
const std::string expected_contents =
std::string(kTextToWrite) + kTextToWrite;
EXPECT_EQ(expected_contents,
- entry.contents.substr(0, expected_contents.size()));
+ entry->contents.substr(0, expected_contents.size()));
}
}
@@ -207,11 +209,12 @@ TEST_F(FileSystemProviderFileStreamWriter, Write_WrongFile) {
TEST_F(FileSystemProviderFileStreamWriter, Write_Append) {
std::vector<int> write_log;
- FakeEntry entry_before;
- ASSERT_TRUE(provided_file_system_->GetEntry(
- base::FilePath::FromUTF8Unsafe(kFakeFilePath), &entry_before));
+ const FakeEntry* const entry = provided_file_system_->GetEntry(
+ base::FilePath::FromUTF8Unsafe(kFakeFilePath));
+ ASSERT_TRUE(entry);
- const int64 initial_offset = entry_before.metadata.size;
+ const std::string original_contents = entry->contents;
+ const int64 initial_offset = entry->metadata->size;
ASSERT_LT(0, initial_offset);
FileStreamWriter writer(file_url_, initial_offset);
@@ -226,11 +229,8 @@ TEST_F(FileSystemProviderFileStreamWriter, Write_Append) {
ASSERT_EQ(1u, write_log.size());
EXPECT_EQ(sizeof(kTextToWrite) - 1, static_cast<size_t>(write_log[0]));
- FakeEntry entry_after;
- ASSERT_TRUE(provided_file_system_->GetEntry(
- base::FilePath::FromUTF8Unsafe(kFakeFilePath), &entry_after));
- const std::string expected_contents = entry_before.contents + kTextToWrite;
- EXPECT_EQ(expected_contents, entry_after.contents);
+ const std::string expected_contents = original_contents + kTextToWrite;
+ EXPECT_EQ(expected_contents, entry->contents);
}
} // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc
index 0c886c9..cb2d2b7 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.cc
@@ -29,31 +29,44 @@ void GetFileInfoOnUIThread(
const ProvidedFileSystemInterface::GetMetadataCallback& callback) {
util::FileSystemURLParser parser(url);
if (!parser.Parse()) {
- callback.Run(EntryMetadata(), base::File::FILE_ERROR_INVALID_OPERATION);
+ callback.Run(make_scoped_ptr<EntryMetadata>(NULL),
+ base::File::FILE_ERROR_INVALID_OPERATION);
return;
}
- parser.file_system()->GetMetadata(parser.file_path(), callback);
+ parser.file_system()->GetMetadata(
+ parser.file_path(),
+ ProvidedFileSystemInterface::METADATA_FIELD_DEFAULT,
+ callback);
}
// Routes the response of GetFileInfo back to the IO thread with a type
// conversion.
void OnGetFileInfo(const storage::AsyncFileUtil::GetFileInfoCallback& callback,
- const EntryMetadata& metadata,
+ scoped_ptr<EntryMetadata> metadata,
base::File::Error result) {
+ if (result != base::File::FILE_OK) {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, result, base::File::Info()));
+ return;
+ }
+
+ DCHECK(metadata.get());
base::File::Info file_info;
// TODO(mtomasz): Add support for last modified time and creation time.
// See: crbug.com/388540.
- file_info.size = metadata.size;
- file_info.is_directory = metadata.is_directory;
+ file_info.size = metadata->size;
+ file_info.is_directory = metadata->is_directory;
file_info.is_symbolic_link = false; // Not supported.
- file_info.last_modified = metadata.modification_time;
- file_info.last_accessed = metadata.modification_time; // Not supported.
- file_info.creation_time = metadata.modification_time; // Not supported.
+ file_info.last_modified = metadata->modification_time;
+ file_info.last_accessed = metadata->modification_time; // Not supported.
+ file_info.creation_time = metadata->modification_time; // Not supported.
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE, base::Bind(callback, result, file_info));
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, base::File::FILE_OK, file_info));
}
// Executes ReadDirectory on the UI thread.
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
index 99a620b..7adab12 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h"
+#include <algorithm>
#include <string>
#include "chrome/common/extensions/api/file_system_provider.h"
@@ -29,9 +30,6 @@ bool ConvertRequestValueToFileInfo(scoped_ptr<RequestValue> value,
output->is_directory = params->metadata.is_directory;
output->size = static_cast<int64>(params->metadata.size);
- if (params->metadata.mime_type.get())
- output->mime_type = *params->metadata.mime_type.get();
-
std::string input_modification_time;
if (!params->metadata.modification_time.additional_properties.GetString(
"value", &input_modification_time)) {
@@ -43,6 +41,27 @@ bool ConvertRequestValueToFileInfo(scoped_ptr<RequestValue> value,
base::Time::FromString(input_modification_time.c_str(),
&output->modification_time);
+ if (params->metadata.mime_type.get())
+ output->mime_type = *params->metadata.mime_type.get();
+
+ if (params->metadata.thumbnail.get()) {
+ // Sanity check for the thumbnail format. Note, that another, more granural
+ // check is done in custom bindings. Note, this is an extra check only for
+ // the security reasons.
+ const std::string expected_prefix = "data:";
+ std::string thumbnail_prefix =
+ params->metadata.thumbnail.get()->substr(0, expected_prefix.size());
+ std::transform(thumbnail_prefix.begin(),
+ thumbnail_prefix.end(),
+ thumbnail_prefix.begin(),
+ ::tolower);
+
+ if (expected_prefix != thumbnail_prefix)
+ return false;
+
+ output->thumbnail = *params->metadata.thumbnail.get();
+ }
+
return true;
}
@@ -52,9 +71,11 @@ GetMetadata::GetMetadata(
extensions::EventRouter* event_router,
const ProvidedFileSystemInfo& file_system_info,
const base::FilePath& entry_path,
+ ProvidedFileSystemInterface::MetadataFieldMask fields,
const ProvidedFileSystemInterface::GetMetadataCallback& callback)
: Operation(event_router, file_system_info),
entry_path_(entry_path),
+ fields_(fields),
callback_(callback) {
}
@@ -64,6 +85,10 @@ GetMetadata::~GetMetadata() {
bool GetMetadata::Execute(int request_id) {
scoped_ptr<base::DictionaryValue> values(new base::DictionaryValue);
values->SetString("entryPath", entry_path_.AsUTF8Unsafe());
+ values->SetBoolean(
+ "thumbnail",
+ (fields_ & ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL) != 0);
+
return SendEvent(
request_id,
extensions::api::file_system_provider::OnGetMetadataRequested::kEventName,
@@ -73,25 +98,25 @@ bool GetMetadata::Execute(int request_id) {
void GetMetadata::OnSuccess(int /* request_id */,
scoped_ptr<RequestValue> result,
bool has_more) {
- EntryMetadata metadata;
+ scoped_ptr<EntryMetadata> metadata(new EntryMetadata);
const bool convert_result =
- ConvertRequestValueToFileInfo(result.Pass(), &metadata);
+ ConvertRequestValueToFileInfo(result.Pass(), metadata.get());
if (!convert_result) {
LOG(ERROR) << "Failed to parse a response for the get metadata operation.";
- callback_.Run(EntryMetadata(), base::File::FILE_ERROR_IO);
+ callback_.Run(make_scoped_ptr<EntryMetadata>(NULL),
+ base::File::FILE_ERROR_IO);
return;
}
- callback_.Run(metadata, base::File::FILE_OK);
+ callback_.Run(metadata.Pass(), base::File::FILE_OK);
}
void GetMetadata::OnError(int /* request_id */,
scoped_ptr<RequestValue> /* result */,
base::File::Error error) {
- callback_.Run(EntryMetadata(), error);
+ callback_.Run(make_scoped_ptr<EntryMetadata>(NULL), error);
}
-
} // namespace operations
} // namespace file_system_provider
} // namespace chromeos
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h
index b679aa6..5d00fdf 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.h
@@ -30,7 +30,8 @@ class GetMetadata : public Operation {
public:
GetMetadata(extensions::EventRouter* event_router,
const ProvidedFileSystemInfo& file_system_info,
- const base::FilePath& directory_path,
+ const base::FilePath& entry_path,
+ ProvidedFileSystemInterface::MetadataFieldMask fields,
const ProvidedFileSystemInterface::GetMetadataCallback& callback);
virtual ~GetMetadata();
@@ -45,6 +46,7 @@ class GetMetadata : public Operation {
private:
base::FilePath entry_path_;
+ ProvidedFileSystemInterface::MetadataFieldMask fields_;
const ProvidedFileSystemInterface::GetMetadataCallback callback_;
DISALLOW_COPY_AND_ASSIGN(GetMetadata);
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
index 33f38d6..cf309a5 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
@@ -30,20 +30,23 @@ const char kMimeType[] = "text/plain";
const int kRequestId = 2;
const base::FilePath::CharType kDirectoryPath[] = "/directory";
+// URLs are case insensitive, so it should pass the sanity check.
+const char kThumbnail[] = "DaTa:ImAgE/pNg;base64,";
+
// Callback invocation logger. Acts as a fileapi end-point.
class CallbackLogger {
public:
class Event {
public:
- Event(const EntryMetadata& metadata, base::File::Error result)
- : metadata_(metadata), result_(result) {}
+ Event(scoped_ptr<EntryMetadata> metadata, base::File::Error result)
+ : metadata_(metadata.Pass()), result_(result) {}
virtual ~Event() {}
- const EntryMetadata& metadata() { return metadata_; }
- base::File::Error result() { return result_; }
+ const EntryMetadata* metadata() const { return metadata_.get(); }
+ base::File::Error result() const { return result_; }
private:
- EntryMetadata metadata_;
+ scoped_ptr<EntryMetadata> metadata_;
base::File::Error result_;
DISALLOW_COPY_AND_ASSIGN(Event);
@@ -52,11 +55,12 @@ class CallbackLogger {
CallbackLogger() {}
virtual ~CallbackLogger() {}
- void OnGetMetadata(const EntryMetadata& metadata, base::File::Error result) {
- events_.push_back(new Event(metadata, result));
+ void OnGetMetadata(scoped_ptr<EntryMetadata> metadata,
+ base::File::Error result) {
+ events_.push_back(new Event(metadata.Pass(), result));
}
- ScopedVector<Event>& events() { return events_; }
+ const ScopedVector<Event>& events() const { return events_; }
private:
ScopedVector<Event> events_;
@@ -88,11 +92,13 @@ TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute) {
util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
CallbackLogger callback_logger;
- GetMetadata get_metadata(NULL,
- file_system_info_,
- base::FilePath::FromUTF8Unsafe(kDirectoryPath),
- base::Bind(&CallbackLogger::OnGetMetadata,
- base::Unretained(&callback_logger)));
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL,
+ base::Bind(&CallbackLogger::OnGetMetadata,
+ base::Unretained(&callback_logger)));
get_metadata.SetDispatchEventImplForTesting(
base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl,
base::Unretained(&dispatcher)));
@@ -121,17 +127,23 @@ TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute) {
std::string event_entry_path;
EXPECT_TRUE(options->GetString("entryPath", &event_entry_path));
EXPECT_EQ(kDirectoryPath, event_entry_path);
+
+ bool event_thumbnail;
+ EXPECT_TRUE(options->GetBoolean("thumbnail", &event_thumbnail));
+ EXPECT_TRUE(event_thumbnail);
}
TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute_NoListener) {
util::LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */);
CallbackLogger callback_logger;
- GetMetadata get_metadata(NULL,
- file_system_info_,
- base::FilePath::FromUTF8Unsafe(kDirectoryPath),
- base::Bind(&CallbackLogger::OnGetMetadata,
- base::Unretained(&callback_logger)));
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL,
+ base::Bind(&CallbackLogger::OnGetMetadata,
+ base::Unretained(&callback_logger)));
get_metadata.SetDispatchEventImplForTesting(
base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl,
base::Unretained(&dispatcher)));
@@ -146,11 +158,13 @@ TEST_F(FileSystemProviderOperationsGetMetadataTest, OnSuccess) {
util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
CallbackLogger callback_logger;
- GetMetadata get_metadata(NULL,
- file_system_info_,
- base::FilePath::FromUTF8Unsafe(kDirectoryPath),
- base::Bind(&CallbackLogger::OnGetMetadata,
- base::Unretained(&callback_logger)));
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL,
+ base::Bind(&CallbackLogger::OnGetMetadata,
+ base::Unretained(&callback_logger)));
get_metadata.SetDispatchEventImplForTesting(
base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl,
base::Unretained(&dispatcher)));
@@ -171,7 +185,8 @@ TEST_F(FileSystemProviderOperationsGetMetadataTest, OnSuccess) {
" \"modificationTime\": {\n"
" \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
" },\n"
- " \"mimeType\": \"text/plain\"\n" // kMimeType
+ " \"mimeType\": \"text/plain\",\n" // kMimeType
+ " \"thumbnail\": \"DaTa:ImAgE/pNg;base64,\"\n" // kThumbnail
" },\n"
" 0\n" // execution_time
"]\n";
@@ -197,25 +212,94 @@ TEST_F(FileSystemProviderOperationsGetMetadataTest, OnSuccess) {
CallbackLogger::Event* event = callback_logger.events()[0];
EXPECT_EQ(base::File::FILE_OK, event->result());
- const EntryMetadata& metadata = event->metadata();
- EXPECT_FALSE(metadata.is_directory);
- EXPECT_EQ(4096, metadata.size);
+ const EntryMetadata* metadata = event->metadata();
+ EXPECT_FALSE(metadata->is_directory);
+ EXPECT_EQ(4096, metadata->size);
base::Time expected_time;
EXPECT_TRUE(
base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014", &expected_time));
- EXPECT_EQ(expected_time, metadata.modification_time);
- EXPECT_EQ(kMimeType, metadata.mime_type);
+ EXPECT_EQ(expected_time, metadata->modification_time);
+ EXPECT_EQ(kMimeType, metadata->mime_type);
+ EXPECT_EQ(kThumbnail, metadata->thumbnail);
+}
+
+TEST_F(FileSystemProviderOperationsGetMetadataTest,
+ OnSuccess_InvalidThumbnail) {
+ using extensions::api::file_system_provider_internal::
+ GetMetadataRequestedSuccess::Params;
+
+ util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
+ CallbackLogger callback_logger;
+
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL,
+ base::Bind(&CallbackLogger::OnGetMetadata,
+ base::Unretained(&callback_logger)));
+ get_metadata.SetDispatchEventImplForTesting(
+ base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl,
+ base::Unretained(&dispatcher)));
+
+ EXPECT_TRUE(get_metadata.Execute(kRequestId));
+
+ // Sample input as JSON. Keep in sync with file_system_provider_api.idl.
+ // As for now, it is impossible to create *::Params class directly, not from
+ // base::Value.
+ const std::string input =
+ "[\n"
+ " \"testing-file-system\",\n" // kFileSystemId
+ " 2,\n" // kRequestId
+ " {\n"
+ " \"isDirectory\": false,\n"
+ " \"name\": \"blueberries.txt\",\n"
+ " \"size\": 4096,\n"
+ " \"modificationTime\": {\n"
+ " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
+ " },\n"
+ " \"mimeType\": \"text/plain\",\n" // kMimeType
+ " \"thumbnail\": \"http://www.foobar.com/evil\"\n" // kThumbnail
+ " },\n"
+ " 0\n" // execution_time
+ "]\n";
+
+ int json_error_code;
+ std::string json_error_msg;
+ scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
+ input, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg));
+ ASSERT_TRUE(value.get()) << json_error_msg;
+
+ base::ListValue* value_as_list;
+ ASSERT_TRUE(value->GetAsList(&value_as_list));
+ scoped_ptr<Params> params(Params::Create(*value_as_list));
+ ASSERT_TRUE(params.get());
+ scoped_ptr<RequestValue> request_value(
+ RequestValue::CreateForGetMetadataSuccess(params.Pass()));
+ ASSERT_TRUE(request_value.get());
+
+ const bool has_more = false;
+ get_metadata.OnSuccess(kRequestId, request_value.Pass(), has_more);
+
+ ASSERT_EQ(1u, callback_logger.events().size());
+ CallbackLogger::Event* event = callback_logger.events()[0];
+ EXPECT_EQ(base::File::FILE_ERROR_IO, event->result());
+
+ const EntryMetadata* metadata = event->metadata();
+ EXPECT_FALSE(metadata);
}
TEST_F(FileSystemProviderOperationsGetMetadataTest, OnError) {
util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */);
CallbackLogger callback_logger;
- GetMetadata get_metadata(NULL,
- file_system_info_,
- base::FilePath::FromUTF8Unsafe(kDirectoryPath),
- base::Bind(&CallbackLogger::OnGetMetadata,
- base::Unretained(&callback_logger)));
+ GetMetadata get_metadata(
+ NULL,
+ file_system_info_,
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL,
+ base::Bind(&CallbackLogger::OnGetMetadata,
+ base::Unretained(&callback_logger)));
get_metadata.SetDispatchEventImplForTesting(
base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl,
base::Unretained(&dispatcher)));
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
index dc0de56..9f8450c 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.cc
@@ -78,13 +78,15 @@ ProvidedFileSystem::AbortCallback ProvidedFileSystem::RequestUnmount(
ProvidedFileSystem::AbortCallback ProvidedFileSystem::GetMetadata(
const base::FilePath& entry_path,
+ MetadataFieldMask fields,
const GetMetadataCallback& callback) {
const int request_id = request_manager_.CreateRequest(
GET_METADATA,
scoped_ptr<RequestManager::HandlerInterface>(new operations::GetMetadata(
- event_router_, file_system_info_, entry_path, callback)));
+ event_router_, file_system_info_, entry_path, fields, callback)));
if (!request_id) {
- callback.Run(EntryMetadata(), base::File::FILE_ERROR_SECURITY);
+ callback.Run(make_scoped_ptr<EntryMetadata>(NULL),
+ base::File::FILE_ERROR_SECURITY);
return AbortCallback();
}
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system.h b/chrome/browser/chromeos/file_system_provider/provided_file_system.h
index 7b7105b..5ecdbf9 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system.h
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system.h
@@ -43,6 +43,7 @@ class ProvidedFileSystem : public ProvidedFileSystemInterface {
const storage::AsyncFileUtil::StatusCallback& callback) OVERRIDE;
virtual AbortCallback GetMetadata(
const base::FilePath& entry_path,
+ MetadataFieldMask fields,
const GetMetadataCallback& callback) OVERRIDE;
virtual AbortCallback ReadDirectory(
const base::FilePath& directory_path,
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h b/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h
index 064276f..fb92a8f 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "webkit/browser/fileapi/async_file_util.h"
@@ -40,6 +41,10 @@ struct EntryMetadata {
int64 size;
base::Time modification_time;
std::string mime_type;
+ std::string thumbnail;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EntryMetadata);
};
// Interface for a provided file system. Acts as a proxy between providers
@@ -49,6 +54,15 @@ struct EntryMetadata {
// fails synchronously.
class ProvidedFileSystemInterface {
public:
+ // Mode of opening a file. Used by OpenFile().
+ enum OpenFileMode { OPEN_FILE_MODE_READ, OPEN_FILE_MODE_WRITE };
+
+ // Extra fields to be fetched with metadata.
+ enum MetadataField {
+ METADATA_FIELD_DEFAULT = 0,
+ METADATA_FIELD_THUMBNAIL = 1 << 0
+ };
+
typedef base::Callback<void(int file_handle, base::File::Error result)>
OpenFileCallback;
@@ -56,14 +70,14 @@ class ProvidedFileSystemInterface {
void(int chunk_length, bool has_more, base::File::Error result)>
ReadChunkReceivedCallback;
- typedef base::Callback<void(const EntryMetadata& entry_metadata,
+ typedef base::Callback<void(scoped_ptr<EntryMetadata> entry_metadata,
base::File::Error result)> GetMetadataCallback;
typedef base::Callback<void(
const storage::AsyncFileUtil::StatusCallback& callback)> AbortCallback;
- // Mode of opening a file. Used by OpenFile().
- enum OpenFileMode { OPEN_FILE_MODE_READ, OPEN_FILE_MODE_WRITE };
+ // Mask of fields requested from the GetMetadata() call.
+ typedef int MetadataFieldMask;
virtual ~ProvidedFileSystemInterface() {}
@@ -73,8 +87,10 @@ class ProvidedFileSystemInterface {
const storage::AsyncFileUtil::StatusCallback& callback) = 0;
// Requests metadata of the passed |entry_path|. It can be either a file
- // or a directory.
+ // or a directory. All |fields| will be returned if supported. Note, that
+ // default fields are always returned.
virtual AbortCallback GetMetadata(const base::FilePath& entry_path,
+ MetadataFieldMask fields,
const GetMetadataCallback& callback) = 0;
// Requests enumerating entries from the passed |directory_path|. The callback
diff --git a/chrome/common/extensions/api/file_system_provider.idl b/chrome/common/extensions/api/file_system_provider.idl
index 155c7da..bbc6bc6 100644
--- a/chrome/common/extensions/api/file_system_provider.idl
+++ b/chrome/common/extensions/api/file_system_provider.idl
@@ -49,7 +49,12 @@ namespace fileSystemProvider {
[instanceOf=Date] object modificationTime;
// Mime type for the entry.
- DOMString? mimeType;
+ DOMString? mimeType;
+
+ // Thumbnail image as a data URI in either PNG, JPEG or WEBP format, at most
+ // 32 KB in size. Optional, but can be provided only when explicitly
+ // requested by the <code>onGetMetadataRequested</code> event.
+ DOMString? thumbnail;
};
// Represents a mounted file system.
@@ -82,6 +87,9 @@ namespace fileSystemProvider {
DOMString fileSystemId;
long requestId;
DOMString entryPath;
+
+ // Set to <code>true</code> if the thumbnail is requested.
+ boolean thumbnail;
};
// Options for the <code>onReadDirectoryRequested()</code> event.
diff --git a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
index 020c772..86a07b6 100644
--- a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
@@ -12,6 +12,22 @@ var fileSystemNatives = requireNative('file_system_natives');
var GetDOMError = fileSystemNatives.GetDOMError;
/**
+ * Maximum size of the thumbnail in bytes.
+ * @type {number}
+ * @const
+ */
+var METADATA_THUMBNAIL_SIZE_LIMIT = 32 * 1024 * 1024;
+
+/**
+ * Regular expression to validate if the thumbnail URI is a valid data URI,
+ * taking into account allowed formats.
+ * @type {RegExp}
+ * @const
+ */
+var METADATA_THUMBNAIL_FORMAT = new RegExp(
+ '^data:image/(png|jpeg|webp);', 'i');
+
+/**
* Annotates a date with its serialized value.
* @param {Date} date Input date.
* @return {Date} Date with an extra <code>value</code> attribute.
@@ -24,6 +40,19 @@ function annotateDate(date) {
}
/**
+ * Verifies if the passed image URI is valid.
+ * @param {*} uri Image URI.
+ * @return {boolean} True if valid, valse otherwise.
+ */
+function verifyImageURI(uri) {
+ // The URI is specified by a user, so the type may be incorrect.
+ if (typeof uri != 'string' && !(uri instanceof String))
+ return false;
+
+ return METADATA_THUMBNAIL_FORMAT.test(uri);
+}
+
+/**
* Annotates an entry metadata by serializing its modifiedTime value.
* @param {EntryMetadata} metadata Input metadata.
* @return {EntryMetadata} metadata Annotated metadata, which can be passed
@@ -38,6 +67,8 @@ function annotateMetadata(metadata) {
};
if ('mimeType' in metadata)
result.mimeType = metadata.mimeType;
+ if ('thumbnail' in metadata)
+ result.thumbnail = metadata.thumbnail;
return result;
}
@@ -141,6 +172,25 @@ eventBindings.registerArgumentMassager(
var executionStart = Date.now();
var options = args[0];
var onSuccessCallback = function(metadata) {
+ // It is invalid to return a thumbnail when it's not requested. The
+ // restriction is added in order to avoid fetching the thumbnail while
+ // it's not needed.
+ if (!options.thumbnail && metadata.thumbnail) {
+ fileSystemProviderInternal.operationRequestedError(
+ options.fileSystemId, options.requestId, 'FAILED',
+ Date.now() - executionStart);
+ throw new Error('Thumbnail data provided, but not requested.');
+ }
+
+ // Check the format and size. Note, that in the C++ layer, there is
+ // another sanity check to avoid passing any evil URL.
+ if ('thumbnail' in metadata && !verifyImageURI(metadata.thumbnail))
+ throw new Error('Thumbnail format invalid.');
+ if ('thumbnail' in metadata &&
+ metadata.thumbnail.length > METADATA_THUMBNAIL_SIZE_LIMIT) {
+ throw new Error('Thumbnail data too large.');
+ }
+
fileSystemProviderInternal.getMetadataRequestedSuccess(
options.fileSystemId,
options.requestId,
@@ -162,6 +212,16 @@ eventBindings.registerArgumentMassager(
var options = args[0];
var onSuccessCallback = function(entries, hasNext) {
var annotatedEntries = entries.map(annotateMetadata);
+ // It is invalid to return a thumbnail when it's not requested.
+ annotatedEntries.forEach(function(metadata) {
+ if (metadata.thumbnail) {
+ fileSystemProviderInternal.operationRequestedError(
+ options.fileSystemId, options.requestId, 'FAILED',
+ Date.now() - executionStart);
+ throw new Error(
+ 'Thumbnails must not be provided when reading a directory.');
+ }
+ });
fileSystemProviderInternal.readDirectoryRequestedSuccess(
options.fileSystemId, options.requestId, annotatedEntries, hasNext,
Date.now() - executionStart);