blob: 85483b8129bc283b485adae8b673f3ec41ad21c0 [file] [log] [blame]
// Copyright 2016 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/android/webapk/webapk_icon_hasher.h"
#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/data_url.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "third_party/smhasher/src/MurmurHash2.h"
namespace {
// The seed to use when taking the murmur2 hash of the icon.
const uint64_t kMurmur2HashSeed = 0;
// The default number of milliseconds to wait for the icon download to complete.
const int kDownloadTimeoutInMilliseconds = 60000;
// Computes Murmur2 hash of |raw_image_data|.
std::string ComputeMurmur2Hash(const std::string& raw_image_data) {
// WARNING: We are running in the browser process. |raw_image_data| is the
// image's raw, unsanitized bytes from the web. |raw_image_data| may contain
// malicious data. Decoding unsanitized bitmap data to an SkBitmap in the
// browser process is a security bug.
uint64_t hash = MurmurHash64A(&raw_image_data.front(), raw_image_data.size(),
kMurmur2HashSeed);
return base::NumberToString(hash);
}
} // anonymous namespace
// static
void WebApkIconHasher::DownloadAndComputeMurmur2Hash(
network::mojom::URLLoaderFactory* url_loader_factory,
const GURL& icon_url,
const Murmur2HashCallback& callback) {
DownloadAndComputeMurmur2HashWithTimeout(
url_loader_factory, icon_url, kDownloadTimeoutInMilliseconds, callback);
}
// static
void WebApkIconHasher::DownloadAndComputeMurmur2HashWithTimeout(
network::mojom::URLLoaderFactory* url_loader_factory,
const GURL& icon_url,
int timeout_ms,
const Murmur2HashCallback& callback) {
if (!icon_url.is_valid()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
base::Bind(callback, ""));
return;
}
if (icon_url.SchemeIs(url::kDataScheme)) {
std::string mime_type, char_set, data;
std::string hash;
if (net::DataURL::Parse(icon_url, &mime_type, &char_set, &data) &&
!data.empty()) {
hash = ComputeMurmur2Hash(data);
}
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
base::Bind(callback, hash));
return;
}
// The icon hasher will delete itself when it is done.
new WebApkIconHasher(url_loader_factory, icon_url, timeout_ms, callback);
}
WebApkIconHasher::WebApkIconHasher(
network::mojom::URLLoaderFactory* url_loader_factory,
const GURL& icon_url,
int timeout_ms,
const Murmur2HashCallback& callback)
: callback_(callback) {
DCHECK(url_loader_factory);
download_timeout_timer_.Start(
FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_ms),
base::Bind(&WebApkIconHasher::OnDownloadTimedOut,
base::Unretained(this)));
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = icon_url;
simple_url_loader_ = network::SimpleURLLoader::Create(
std::move(resource_request),
TRAFFIC_ANNOTATION_WITHOUT_PROTO("webapk icon hasher"));
simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
url_loader_factory,
base::BindOnce(&WebApkIconHasher::OnSimpleLoaderComplete,
base::Unretained(this)));
}
WebApkIconHasher::~WebApkIconHasher() {}
void WebApkIconHasher::OnSimpleLoaderComplete(
std::unique_ptr<std::string> response_body) {
download_timeout_timer_.Stop();
// Check for non-empty body in case of HTTP 204 (no content) response.
if (!response_body || response_body->empty()) {
RunCallback("");
return;
}
// WARNING: We are running in the browser process. |*response_body| is the
// image's raw, unsanitized bytes from the web. |*response_body| may contain
// malicious data. Decoding unsanitized bitmap data to an SkBitmap in the
// browser process is a security bug.
RunCallback(ComputeMurmur2Hash(*response_body));
}
void WebApkIconHasher::OnDownloadTimedOut() {
simple_url_loader_.reset();
RunCallback("");
}
void WebApkIconHasher::RunCallback(const std::string& icon_murmur2_hash) {
callback_.Run(icon_murmur2_hash);
delete this;
}