blob: fd3ce7cc7cd0600b3ad99a9685c3cee54a14e18a [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media_galleries/fileapi/supported_image_type_validator.h"
#include <memory>
#include <utility>
#include "base/check_op.h"
#include "base/files/file.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "chrome/browser/image_decoder/image_decoder.h"
#include "components/download/public/common/quarantine_connection.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace {
// Arbitrary limit to sanity check the file size.
const int kMaxImageFileSize = 50*1014*1024;
std::unique_ptr<std::string> ReadOnFileThread(const base::FilePath& path) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
std::unique_ptr<std::string> result;
base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid())
return result;
base::File::Info file_info;
if (!file.GetInfo(&file_info) ||
file_info.size > kMaxImageFileSize) {
return result;
}
result = std::make_unique<std::string>();
result->resize(file_info.size);
if (file.Read(0, std::data(*result), file_info.size) != file_info.size) {
result.reset();
}
return result;
}
class ImageDecoderDelegateAdapter : public ImageDecoder::ImageRequest {
public:
explicit ImageDecoderDelegateAdapter(
storage::CopyOrMoveFileValidator::ResultCallback callback)
: callback_(std::move(callback)) {}
ImageDecoderDelegateAdapter(const ImageDecoderDelegateAdapter&) = delete;
ImageDecoderDelegateAdapter& operator=(const ImageDecoderDelegateAdapter&) =
delete;
// ImageDecoder::ImageRequest methods.
void OnImageDecoded(const SkBitmap& /*decoded_image*/) override {
std::move(callback_).Run(base::File::FILE_OK);
delete this;
}
void OnDecodeImageFailed() override {
std::move(callback_).Run(base::File::FILE_ERROR_SECURITY);
delete this;
}
private:
storage::CopyOrMoveFileValidator::ResultCallback callback_;
};
} // namespace
SupportedImageTypeValidator::~SupportedImageTypeValidator() {}
// static
bool SupportedImageTypeValidator::SupportsFileType(const base::FilePath& path) {
base::FilePath::StringType extension = path.Extension();
return extension == FILE_PATH_LITERAL(".bmp") ||
extension == FILE_PATH_LITERAL(".gif") ||
extension == FILE_PATH_LITERAL(".jfif") ||
extension == FILE_PATH_LITERAL(".jpeg") ||
extension == FILE_PATH_LITERAL(".jpg") ||
extension == FILE_PATH_LITERAL(".pjp") ||
extension == FILE_PATH_LITERAL(".pjpeg") ||
extension == FILE_PATH_LITERAL(".png") ||
extension == FILE_PATH_LITERAL(".webp");
}
void SupportedImageTypeValidator::StartPreWriteValidation(
ResultCallback result_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(callback_.is_null());
callback_ = std::move(result_callback);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&ReadOnFileThread, path_),
base::BindOnce(&SupportedImageTypeValidator::OnFileOpen,
weak_factory_.GetWeakPtr()));
}
SupportedImageTypeValidator::SupportedImageTypeValidator(
const base::FilePath& path,
download::QuarantineConnectionCallback quarantine_connection_callback)
: AVScanningFileValidator(quarantine_connection_callback), path_(path) {}
void SupportedImageTypeValidator::OnFileOpen(
std::unique_ptr<std::string> data) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!data.get()) {
std::move(callback_).Run(base::File::FILE_ERROR_SECURITY);
return;
}
// |adapter| will delete itself after a completion message is received.
ImageDecoderDelegateAdapter* adapter =
new ImageDecoderDelegateAdapter(std::move(callback_));
ImageDecoder::Start(adapter, std::move(*data));
}