diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/services/data_decoder | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/services/data_decoder')
32 files changed, 543 insertions, 357 deletions
diff --git a/chromium/services/data_decoder/BUILD.gn b/chromium/services/data_decoder/BUILD.gn index c59d28d13c1..fa455db7aa3 100644 --- a/chromium/services/data_decoder/BUILD.gn +++ b/chromium/services/data_decoder/BUILD.gn @@ -14,6 +14,8 @@ source_set("lib") { "web_bundle_parser.h", "web_bundle_parser_factory.cc", "web_bundle_parser_factory.h", + "web_bundler.cc", + "web_bundler.h", "xml_parser.cc", "xml_parser.h", ] @@ -38,9 +40,7 @@ source_set("lib") { "//ui/gfx/geometry", ] - public_deps = [ - "//services/data_decoder/public/mojom", - ] + public_deps = [ "//services/data_decoder/public/mojom" ] if (!is_ios) { sources += [ @@ -88,9 +88,7 @@ source_set("tests") { "//gin:gin_test", "//third_party/blink/public:blink", ] - data_deps = [ - "//tools/v8_context_snapshot", - ] + data_deps = [ "//tools/v8_context_snapshot" ] configs += [ "//tools/v8_context_snapshot:use_v8_context_snapshot", "//v8:external_startup_data", @@ -99,9 +97,7 @@ source_set("tests") { } fuzzer_test("web_bundle_parser_fuzzer") { - sources = [ - "web_bundle_parser_fuzzer.cc", - ] + sources = [ "web_bundle_parser_fuzzer.cc" ] deps = [ ":lib", "//base", @@ -111,9 +107,7 @@ fuzzer_test("web_bundle_parser_fuzzer") { } fuzzer_test("xml_parser_fuzzer") { - sources = [ - "xml_parser_fuzzer.cc", - ] + sources = [ "xml_parser_fuzzer.cc" ] deps = [ ":lib", "//base", @@ -126,11 +120,7 @@ fuzzer_test("xml_parser_fuzzer") { if (is_chromeos) { fuzzer_test("ble_scan_parser_fuzzer") { - sources = [ - "ble_scan_parser_impl_fuzzer.cc", - ] - deps = [ - ":lib", - ] + sources = [ "ble_scan_parser_impl_fuzzer.cc" ] + deps = [ ":lib" ] } } diff --git a/chromium/services/data_decoder/data_decoder_service.cc b/chromium/services/data_decoder/data_decoder_service.cc index 837a7c5d254..f841ce45bfa 100644 --- a/chromium/services/data_decoder/data_decoder_service.cc +++ b/chromium/services/data_decoder/data_decoder_service.cc @@ -16,6 +16,7 @@ #include "services/data_decoder/json_parser_impl.h" #include "services/data_decoder/public/mojom/image_decoder.mojom.h" #include "services/data_decoder/web_bundle_parser_factory.h" +#include "services/data_decoder/web_bundler.h" #include "services/data_decoder/xml_parser.h" #if defined(OS_CHROMEOS) @@ -78,6 +79,16 @@ void DataDecoderService::BindWebBundleParserFactory( } } +void DataDecoderService::BindWebBundler( + mojo::PendingReceiver<mojom::WebBundler> receiver) { + if (web_bundler_binder_) { + web_bundler_binder_.Run(std::move(receiver)); + } else { + mojo::MakeSelfOwnedReceiver(std::make_unique<WebBundler>(), + std::move(receiver)); + } +} + #ifdef OS_CHROMEOS void DataDecoderService::BindBleScanParser( mojo::PendingReceiver<mojom::BleScanParser> receiver) { diff --git a/chromium/services/data_decoder/data_decoder_service.h b/chromium/services/data_decoder/data_decoder_service.h index dd7349588f7..b3999002ffe 100644 --- a/chromium/services/data_decoder/data_decoder_service.h +++ b/chromium/services/data_decoder/data_decoder_service.h @@ -14,6 +14,7 @@ #include "services/data_decoder/public/mojom/image_decoder.mojom.h" #include "services/data_decoder/public/mojom/json_parser.mojom.h" #include "services/data_decoder/public/mojom/web_bundle_parser.mojom.h" +#include "services/data_decoder/public/mojom/web_bundler.mojom.h" #include "services/data_decoder/public/mojom/xml_parser.mojom.h" #ifdef OS_CHROMEOS @@ -54,6 +55,14 @@ class DataDecoderService : public mojom::DataDecoderService { web_bundle_parser_factory_binder_ = binder; } + // Configures the service to use |binder| to bind WebBundler in subsequent + // BindWebBundler() calls. + void SetWebBundlerBinderForTesting( + base::RepeatingCallback<void(mojo::PendingReceiver<mojom::WebBundler>)> + binder) { + web_bundler_binder_ = binder; + } + private: // mojom::DataDecoderService implementation: void BindImageDecoder( @@ -63,6 +72,8 @@ class DataDecoderService : public mojom::DataDecoderService { void BindXmlParser(mojo::PendingReceiver<mojom::XmlParser> receiver) override; void BindWebBundleParserFactory( mojo::PendingReceiver<mojom::WebBundleParserFactory> receiver) override; + void BindWebBundler( + mojo::PendingReceiver<mojom::WebBundler> receiver) override; #ifdef OS_CHROMEOS void BindBleScanParser( @@ -78,6 +89,8 @@ class DataDecoderService : public mojom::DataDecoderService { base::RepeatingCallback<void( mojo::PendingReceiver<mojom::WebBundleParserFactory>)> web_bundle_parser_factory_binder_; + base::RepeatingCallback<void(mojo::PendingReceiver<mojom::WebBundler>)> + web_bundler_binder_; DISALLOW_COPY_AND_ASSIGN(DataDecoderService); }; diff --git a/chromium/services/data_decoder/image_decoder_impl.cc b/chromium/services/data_decoder/image_decoder_impl.cc index b19e57ca96e..e65dc0d2c97 100644 --- a/chromium/services/data_decoder/image_decoder_impl.cc +++ b/chromium/services/data_decoder/image_decoder_impl.cc @@ -17,7 +17,6 @@ #include "third_party/skia/include/core/SkBitmap.h" #if defined(OS_CHROMEOS) -#include "ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h" #include "ui/gfx/codec/png_codec.h" #endif @@ -25,13 +24,6 @@ namespace data_decoder { namespace { -#if defined(OS_CHROMEOS) -// NOTE: This 1 GB limit is arbitrary and may be subject to change. The purpose -// of limiting image decode size is to avoid OOM crashes caused by very large -// image data being thrown at the service. -constexpr size_t kJpegMaxDecodedNumBytes = 1024 * 1024 * 1024; -#endif - int64_t kPadding = 64; void ResizeImage(SkBitmap* decoded_image, @@ -82,15 +74,7 @@ void ImageDecoderImpl::DecodeImage(const std::vector<uint8_t>& encoded_data, SkBitmap decoded_image; #if defined(OS_CHROMEOS) - if (codec == mojom::ImageCodec::ROBUST_JPEG) { - // Our robust jpeg decoding is using IJG libjpeg. - if (encoded_data.size()) { - std::unique_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodecRobustSlow::Decode( - encoded_data, kJpegMaxDecodedNumBytes)); - if (decoded_jpeg.get() && !decoded_jpeg->empty()) - decoded_image = *decoded_jpeg; - } - } else if (codec == mojom::ImageCodec::ROBUST_PNG) { + if (codec == mojom::ImageCodec::ROBUST_PNG) { // Our robust PNG decoding is using libpng. if (encoded_data.size()) { SkBitmap decoded_png; diff --git a/chromium/services/data_decoder/image_decoder_impl_unittest.cc b/chromium/services/data_decoder/image_decoder_impl_unittest.cc index 08669eed733..ffa4445b51d 100644 --- a/chromium/services/data_decoder/image_decoder_impl_unittest.cc +++ b/chromium/services/data_decoder/image_decoder_impl_unittest.cc @@ -62,7 +62,7 @@ class Request { decoder_->DecodeImage( image, mojom::ImageCodec::DEFAULT, shrink, kTestMaxImageSize, gfx::Size(), // Take the smallest frame (there's only one frame). - base::Bind(&Request::OnRequestDone, base::Unretained(this))); + base::BindOnce(&Request::OnRequestDone, base::Unretained(this))); } const SkBitmap& bitmap() const { return bitmap_; } diff --git a/chromium/services/data_decoder/public/cpp/BUILD.gn b/chromium/services/data_decoder/public/cpp/BUILD.gn index a2e051577f1..4dd89896df9 100644 --- a/chromium/services/data_decoder/public/cpp/BUILD.gn +++ b/chromium/services/data_decoder/public/cpp/BUILD.gn @@ -8,13 +8,9 @@ import("//mojo/public/tools/bindings/mojom.gni") # converted to a component target. A component target is necessary for # ServiceProvider because it exposes global storage. component("service_provider") { - public = [ - "service_provider.h", - ] + public = [ "service_provider.h" ] - sources = [ - "service_provider.cc", - ] + sources = [ "service_provider.cc" ] public_deps = [ "//base", @@ -51,9 +47,8 @@ source_set("cpp") { if (is_android) { sources += [ "json_sanitizer_android.cc" ] - deps = [ - "//services/data_decoder/public/cpp/android:safe_json_jni_headers", - ] + deps = + [ "//services/data_decoder/public/cpp/android:safe_json_jni_headers" ] } else { sources += [ "json_sanitizer_non_android.cc" ] } @@ -62,9 +57,7 @@ source_set("cpp") { # NOTE: We depend on this target here for iOS only, to support in-process # use of the service. Non-test targets in this directory should otherwise # NEVER depend on this target. - deps = [ - "//services/data_decoder:lib", - ] + deps = [ "//services/data_decoder:lib" ] } else { public += [ "decode_image.h", @@ -84,8 +77,12 @@ source_set("test_support") { sources = [ "test_support/in_process_data_decoder.cc", "test_support/in_process_data_decoder.h", + "test_support/web_bundle_builder.cc", + "test_support/web_bundle_builder.h", ] + deps = [ "//components/cbor" ] + public_deps = [ ":cpp", "//base", diff --git a/chromium/services/data_decoder/public/cpp/android/BUILD.gn b/chromium/services/data_decoder/public/cpp/android/BUILD.gn index 8db1e96c850..266012dba9f 100644 --- a/chromium/services/data_decoder/public/cpp/android/BUILD.gn +++ b/chromium/services/data_decoder/public/cpp/android/BUILD.gn @@ -18,6 +18,6 @@ if (current_toolchain == default_toolchain) { "//base:jni_java", ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] - java_files = [] + _jni_sources + sources = [] + _jni_sources } } diff --git a/chromium/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java b/chromium/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java index f398f4115d3..868cb60c850 100644 --- a/chromium/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java +++ b/chromium/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java @@ -148,7 +148,7 @@ public class JsonSanitizer { /** * Checks whether a given String is well-formed UTF-16, i.e. all surrogates appear in high-low - * pairs and each code point is a valid character. + * pairs, in other words: each character is a valid Unicode code point. * * @param string The string to check. * @return Whether the given string is well-formed UTF-16. @@ -159,7 +159,7 @@ public class JsonSanitizer { char c = string.charAt(i); // Check that surrogates only appear in pairs of a high surrogate followed by a low // surrogate. - // A lone low surrogate is not allowed. + // A lone surrogate is not allowed. if (Character.isLowSurrogate(c)) return false; int codePoint; @@ -174,22 +174,14 @@ public class JsonSanitizer { // Decode the high-low pair into a code point. codePoint = Character.toCodePoint(high, low); } else { - // The code point is neither a low surrogate nor a high surrogate, so we just need - // to check that it's a valid character. + // The code point is neither a low surrogate nor a high surrogate, so + // it's a valid Unicode character. codePoint = c; } - - if (!isUnicodeCharacter(codePoint)) return false; } return true; } - private static boolean isUnicodeCharacter(int codePoint) { - // See the native method base::IsValidCharacter(). - return codePoint < 0xD800 || (codePoint >= 0xE000 && codePoint < 0xFDD0) - || (codePoint > 0xFDEF && codePoint <= 0x10FFFF && (codePoint & 0xFFFE) != 0xFFFE); - } - @NativeMethods interface Natives { void onSuccess(long id, String json); diff --git a/chromium/services/data_decoder/public/cpp/data_decoder.cc b/chromium/services/data_decoder/public/cpp/data_decoder.cc index 9ba33ff47e2..29ad02fe4c7 100644 --- a/chromium/services/data_decoder/public/cpp/data_decoder.cc +++ b/chromium/services/data_decoder/public/cpp/data_decoder.cc @@ -6,6 +6,7 @@ #include "base/memory/ref_counted.h" #include "base/no_destructor.h" +#include "base/task/thread_pool.h" #include "base/time/time.h" #include "build/build_config.h" #include "services/data_decoder/public/mojom/json_parser.mojom.h" @@ -105,7 +106,7 @@ class ValueParseRequest : public base::RefCounted<ValueParseRequest<T>> { void BindInProcessService( mojo::PendingReceiver<mojom::DataDecoderService> receiver) { static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>> - task_runner{base::CreateSequencedTaskRunner({base::ThreadPool()})}; + task_runner{base::ThreadPool::CreateSequencedTaskRunner({})}; if (!(*task_runner)->RunsTasksInCurrentSequence()) { (*task_runner) ->PostTask(FROM_HERE, diff --git a/chromium/services/data_decoder/public/cpp/decode_image.cc b/chromium/services/data_decoder/public/cpp/decode_image.cc index 5707600c8c4..b395086b35f 100644 --- a/chromium/services/data_decoder/public/cpp/decode_image.cc +++ b/chromium/services/data_decoder/public/cpp/decode_image.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/callback_helpers.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/data_decoder/public/cpp/data_decoder.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -104,8 +105,8 @@ void DecodeAnimation(DataDecoder* data_decoder, // |call_once| runs |callback| on its first invocation. auto call_once = base::AdaptCallbackForRepeating(std::move(callback)); - decoder.set_disconnect_handler(base::BindOnce( - call_once, base::Passed(std::vector<mojom::AnimationFramePtr>()))); + decoder.set_disconnect_handler( + base::BindOnce(call_once, std::vector<mojom::AnimationFramePtr>())); mojom::ImageDecoder* raw_decoder = decoder.get(); raw_decoder->DecodeAnimation( diff --git a/chromium/services/data_decoder/public/cpp/json_sanitizer_android.cc b/chromium/services/data_decoder/public/cpp/json_sanitizer_android.cc index 5ed2b7aed63..b4e7efb1ba5 100644 --- a/chromium/services/data_decoder/public/cpp/json_sanitizer_android.cc +++ b/chromium/services/data_decoder/public/cpp/json_sanitizer_android.cc @@ -35,7 +35,7 @@ namespace data_decoder { // static void JsonSanitizer::Sanitize(const std::string& json, Callback callback) { // The JSON parser only accepts wellformed UTF-8. - if (!base::IsStringUTF8(json)) { + if (!base::IsStringUTF8AllowingNoncharacters(json)) { base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), Result::Error("Unsupported encoding"))); diff --git a/chromium/services/data_decoder/public/cpp/json_sanitizer_unittest.cc b/chromium/services/data_decoder/public/cpp/json_sanitizer_unittest.cc index b3d53dc38de..cbc0d7da423 100644 --- a/chromium/services/data_decoder/public/cpp/json_sanitizer_unittest.cc +++ b/chromium/services/data_decoder/public/cpp/json_sanitizer_unittest.cc @@ -46,7 +46,7 @@ void CheckSuccess(const std::string& json) { EXPECT_TRUE(result_received); } -// Verifies that |json| is rejected by the sanitizer as an invlid string. +// Verifies that |json| is rejected by the sanitizer as an invalid string. void CheckError(const std::string& json) { base::RunLoop loop; bool result_received = false; @@ -135,10 +135,44 @@ TEST_F(DataDecoderJsonSanitizerTest, Unicode) { // A low surrogate followed by a high surrogate. CheckError("[\"\\ude03\\ud83d\"]"); - // Valid escaped UTF-16 that encodes non-characters: - CheckError("[\"\\ufdd0\"]"); - CheckError("[\"\\ufffe\"]"); - CheckError("[\"\\ud83f\\udffe\"]"); + // Valid escaped UTF-16 that encodes non-characters. + CheckSuccess("[\"\\uFDD0\"]"); // U+FDD0 + CheckSuccess("[\"\\uFDDF\"]"); // U+FDDF + CheckSuccess("[\"\\uFDEF\"]"); // U+FDEF + CheckSuccess("[\"\\uFFFE\"]"); // U+FFFE + CheckSuccess("[\"\\uFFFF\"]"); // U+FFFF + CheckSuccess("[\"\\uD83F\\uDFFE\"]"); // U+01FFFE + CheckSuccess("[\"\\uD83F\\uDFFF\"]"); // U+01FFFF + CheckSuccess("[\"\\uD87F\\uDFFE\"]"); // U+02FFFE + CheckSuccess("[\"\\uD87F\\uDFFF\"]"); // U+02FFFF + CheckSuccess("[\"\\uD8BF\\uDFFE\"]"); // U+03FFFE + CheckSuccess("[\"\\uD8BF\\uDFFF\"]"); // U+03FFFF + CheckSuccess("[\"\\uD8FF\\uDFFE\"]"); // U+04FFFE + CheckSuccess("[\"\\uD8FF\\uDFFF\"]"); // U+04FFFF + CheckSuccess("[\"\\uD93F\\uDFFE\"]"); // U+05FFFE + CheckSuccess("[\"\\uD93F\\uDFFF\"]"); // U+05FFFF + CheckSuccess("[\"\\uD97F\\uDFFE\"]"); // U+06FFFE + CheckSuccess("[\"\\uD97F\\uDFFF\"]"); // U+06FFFF + CheckSuccess("[\"\\uD9BF\\uDFFE\"]"); // U+07FFFE + CheckSuccess("[\"\\uD9BF\\uDFFF\"]"); // U+07FFFF + CheckSuccess("[\"\\uD9FF\\uDFFE\"]"); // U+08FFFE + CheckSuccess("[\"\\uD9FF\\uDFFF\"]"); // U+08FFFF + CheckSuccess("[\"\\uDA3F\\uDFFE\"]"); // U+09FFFE + CheckSuccess("[\"\\uDA3F\\uDFFF\"]"); // U+09FFFF + CheckSuccess("[\"\\uDA7F\\uDFFE\"]"); // U+0AFFFE + CheckSuccess("[\"\\uDA7F\\uDFFF\"]"); // U+0AFFFF + CheckSuccess("[\"\\uDABF\\uDFFE\"]"); // U+0BFFFE + CheckSuccess("[\"\\uDABF\\uDFFF\"]"); // U+0BFFFF + CheckSuccess("[\"\\uDAFF\\uDFFE\"]"); // U+0CFFFE + CheckSuccess("[\"\\uDAFF\\uDFFF\"]"); // U+0CFFFF + CheckSuccess("[\"\\uDB3F\\uDFFE\"]"); // U+0DFFFE + CheckSuccess("[\"\\uDB3F\\uDFFF\"]"); // U+0DFFFF + CheckSuccess("[\"\\uDB7F\\uDFFE\"]"); // U+0EFFFE + CheckSuccess("[\"\\uDB7F\\uDFFF\"]"); // U+0EFFFF + CheckSuccess("[\"\\uDBBF\\uDFFE\"]"); // U+0FFFFE + CheckSuccess("[\"\\uDBBF\\uDFFF\"]"); // U+0FFFFF + CheckSuccess("[\"\\uDBFF\\uDFFE\"]"); // U+10FFFE + CheckSuccess("[\"\\uDBFF\\uDFFF\"]"); // U+10FFFF } } // namespace diff --git a/chromium/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc b/chromium/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc index f82ddc7dd5a..8709166d18b 100644 --- a/chromium/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc +++ b/chromium/services/data_decoder/public/cpp/safe_web_bundle_parser_unittest.cc @@ -101,7 +101,6 @@ class MockDataSource final : public mojom::BundleDataSource { private: // Implements mojom::BundledDataSource. - void GetSize(GetSizeCallback callback) override {} void Read(uint64_t offset, uint64_t length, ReadCallback callback) override {} mojo::Receiver<mojom::BundleDataSource> receiver_; @@ -140,7 +139,7 @@ TEST_F(SafeWebBundleParserTest, ParseGoldenFile) { { base::RunLoop run_loop; parser.ParseMetadata(base::BindOnce( - [](base::Closure quit_closure, + [](base::OnceClosure quit_closure, mojom::BundleMetadataPtr* metadata_result, mojom::BundleMetadataPtr metadata, mojom::BundleMetadataParseErrorPtr error) { @@ -164,7 +163,7 @@ TEST_F(SafeWebBundleParserTest, ParseGoldenFile) { entry.second->response_locations[0]->offset, entry.second->response_locations[0]->length, base::BindOnce( - [](base::Closure quit_closure, const std::string url, + [](base::OnceClosure quit_closure, const std::string url, std::map<std::string, mojom::BundleResponsePtr>* responses, mojom::BundleResponsePtr response, mojom::BundleResponseParseErrorPtr error) { @@ -260,7 +259,7 @@ TEST_F(SafeWebBundleParserTest, ConnectionError) { base::RunLoop run_loop; bool parsed = false; parser.ParseMetadata(base::BindOnce( - [](base::Closure quit_closure, bool* parsed, + [](base::OnceClosure quit_closure, bool* parsed, mojom::BundleMetadataPtr metadata, mojom::BundleMetadataParseErrorPtr error) { EXPECT_FALSE(metadata); diff --git a/chromium/services/data_decoder/public/cpp/test_support/web_bundle_builder.cc b/chromium/services/data_decoder/public/cpp/test_support/web_bundle_builder.cc new file mode 100644 index 00000000000..8155e97d512 --- /dev/null +++ b/chromium/services/data_decoder/public/cpp/test_support/web_bundle_builder.cc @@ -0,0 +1,149 @@ +// Copyright 2020 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 "services/data_decoder/public/cpp/test_support/web_bundle_builder.h" + +namespace data_decoder { +namespace test { + +namespace { + +cbor::Value CreateByteString(base::StringPiece s) { + return cbor::Value(base::as_bytes(base::make_span(s))); +} + +cbor::Value CreateHeaderMap(const WebBundleBuilder::Headers& headers) { + cbor::Value::MapValue map; + for (const auto& pair : headers) + map.insert({CreateByteString(pair.first), CreateByteString(pair.second)}); + return cbor::Value(std::move(map)); +} + +} // namespace + +WebBundleBuilder::WebBundleBuilder(const std::string& fallback_url, + const std::string& manifest_url) + : fallback_url_(fallback_url) { + writer_config_.allow_invalid_utf8_for_testing = true; + if (!manifest_url.empty()) { + AddSection("manifest", + cbor::Value::InvalidUTF8StringValueForTesting(manifest_url)); + } +} + +WebBundleBuilder::~WebBundleBuilder() = default; + +void WebBundleBuilder::AddExchange(base::StringPiece url, + const Headers& response_headers, + base::StringPiece payload) { + AddIndexEntry(url, "", {AddResponse(response_headers, payload)}); +} + +WebBundleBuilder::ResponseLocation WebBundleBuilder::AddResponse( + const Headers& headers, + base::StringPiece payload) { + // We assume that the size of the CBOR header of the responses array is 1, + // which is true only if the responses array has no more than 23 elements. + DCHECK_LT(responses_.size(), 23u) + << "WebBundleBuilder cannot create bundles with more than 23 responses"; + + cbor::Value::ArrayValue response_array; + response_array.emplace_back(Encode(CreateHeaderMap(headers))); + response_array.emplace_back(CreateByteString(payload)); + cbor::Value response(response_array); + int64_t response_length = EncodedLength(response); + ResponseLocation result = {current_responses_offset_, response_length}; + current_responses_offset_ += response_length; + responses_.emplace_back(std::move(response)); + return result; +} + +void WebBundleBuilder::AddIndexEntry( + base::StringPiece url, + base::StringPiece variants_value, + std::vector<ResponseLocation> response_locations) { + cbor::Value::ArrayValue index_value_array; + index_value_array.emplace_back(CreateByteString(variants_value)); + for (const auto& location : response_locations) { + index_value_array.emplace_back(location.offset); + index_value_array.emplace_back(location.length); + } + index_.insert({cbor::Value::InvalidUTF8StringValueForTesting(url), + cbor::Value(index_value_array)}); +} + +void WebBundleBuilder::AddSection(base::StringPiece name, cbor::Value section) { + section_lengths_.emplace_back(name); + section_lengths_.emplace_back(EncodedLength(section)); + sections_.emplace_back(std::move(section)); +} + +void WebBundleBuilder::AddAuthority(cbor::Value::MapValue authority) { + authorities_.emplace_back(std::move(authority)); +} + +void WebBundleBuilder::AddVouchedSubset(cbor::Value::MapValue vouched_subset) { + vouched_subsets_.emplace_back(std::move(vouched_subset)); +} + +std::vector<uint8_t> WebBundleBuilder::CreateBundle() { + AddSection("index", cbor::Value(index_)); + if (!authorities_.empty() || !vouched_subsets_.empty()) { + cbor::Value::ArrayValue signatures_section; + signatures_section.emplace_back(std::move(authorities_)); + signatures_section.emplace_back(std::move(vouched_subsets_)); + AddSection("signatures", cbor::Value(std::move(signatures_section))); + } + AddSection("responses", cbor::Value(responses_)); + return Encode(CreateTopLevel()); +} + +cbor::Value WebBundleBuilder::CreateEncodedSigned( + base::StringPiece validity_url, + base::StringPiece auth_sha256, + int64_t date, + int64_t expires, + base::StringPiece url, + base::StringPiece header_sha256, + base::StringPiece payload_integrity_header) { + cbor::Value::ArrayValue subset_hash_value; + subset_hash_value.emplace_back(CreateByteString("")); // variants-value + subset_hash_value.emplace_back(CreateByteString(header_sha256)); + subset_hash_value.emplace_back(payload_integrity_header); + + cbor::Value::MapValue subset_hashes; + subset_hashes.emplace(url, std::move(subset_hash_value)); + + cbor::Value::MapValue signed_subset; + signed_subset.emplace("validity-url", validity_url); + signed_subset.emplace("auth-sha256", CreateByteString(auth_sha256)); + signed_subset.emplace("date", date); + signed_subset.emplace("expires", expires); + signed_subset.emplace("subset-hashes", std::move(subset_hashes)); + return cbor::Value(Encode(cbor::Value(signed_subset))); +} + +cbor::Value WebBundleBuilder::CreateTopLevel() { + cbor::Value::ArrayValue toplevel_array; + toplevel_array.emplace_back( + CreateByteString(u8"\U0001F310\U0001F4E6")); // "🌐📦" + toplevel_array.emplace_back(CreateByteString(base::StringPiece("b1\0\0", 4))); + toplevel_array.emplace_back( + cbor::Value::InvalidUTF8StringValueForTesting(fallback_url_)); + toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_))); + toplevel_array.emplace_back(sections_); + toplevel_array.emplace_back(CreateByteString("")); // length (ignored) + return cbor::Value(toplevel_array); +} + +std::vector<uint8_t> WebBundleBuilder::Encode(const cbor::Value& value) { + return *cbor::Writer::Write(value, writer_config_); +} + +int64_t WebBundleBuilder::EncodedLength(const cbor::Value& value) { + return Encode(value).size(); +} + +} // namespace test +} // namespace data_decoder diff --git a/chromium/services/data_decoder/public/cpp/test_support/web_bundle_builder.h b/chromium/services/data_decoder/public/cpp/test_support/web_bundle_builder.h new file mode 100644 index 00000000000..71267ac3ec7 --- /dev/null +++ b/chromium/services/data_decoder/public/cpp/test_support/web_bundle_builder.h @@ -0,0 +1,80 @@ +// Copyright 2020 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. + +#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_TEST_SUPPORT_WEB_BUNDLE_BUILDER_H_ +#define SERVICES_DATA_DECODER_PUBLIC_CPP_TEST_SUPPORT_WEB_BUNDLE_BUILDER_H_ + +#include <string> +#include <utility> +#include <vector> + +#include "base/strings/string_piece.h" +#include "components/cbor/writer.h" + +namespace data_decoder { +namespace test { + +// This class can be used to create a Web Bundle binary in tests. +class WebBundleBuilder { + public: + using Headers = std::vector<std::pair<std::string, std::string>>; + struct ResponseLocation { + // /components/cbor uses int64_t for integer types. + int64_t offset; + int64_t length; + }; + + WebBundleBuilder(const std::string& fallback_url, + const std::string& manifest_url); + ~WebBundleBuilder(); + + void AddExchange(base::StringPiece url, + const Headers& response_headers, + base::StringPiece payload); + + ResponseLocation AddResponse(const Headers& headers, + base::StringPiece payload); + + void AddIndexEntry(base::StringPiece url, + base::StringPiece variants_value, + std::vector<ResponseLocation> response_locations); + void AddSection(base::StringPiece name, cbor::Value section); + void AddAuthority(cbor::Value::MapValue authority); + void AddVouchedSubset(cbor::Value::MapValue vouched_subset); + + std::vector<uint8_t> CreateBundle(); + + // Creates a signed-subset structure with single subset-hashes entry, + // and returns it as a CBOR bytestring. + cbor::Value CreateEncodedSigned(base::StringPiece validity_url, + base::StringPiece auth_sha256, + int64_t date, + int64_t expires, + base::StringPiece url, + base::StringPiece header_sha256, + base::StringPiece payload_integrity_header); + + private: + cbor::Value CreateTopLevel(); + std::vector<uint8_t> Encode(const cbor::Value& value); + + int64_t EncodedLength(const cbor::Value& value); + + cbor::Writer::Config writer_config_; + std::string fallback_url_; + cbor::Value::ArrayValue section_lengths_; + cbor::Value::ArrayValue sections_; + cbor::Value::MapValue index_; + cbor::Value::ArrayValue responses_; + cbor::Value::ArrayValue authorities_; + cbor::Value::ArrayValue vouched_subsets_; + + // 1 for the CBOR header byte. See the comment at the top of AddResponse(). + int64_t current_responses_offset_ = 1; +}; + +} // namespace test +} // namespace data_decoder + +#endif // SERVICES_DATA_DECODER_PUBLIC_CPP_TEST_SUPPORT_WEB_BUNDLE_BUILDER_H_ diff --git a/chromium/services/data_decoder/public/mojom/BUILD.gn b/chromium/services/data_decoder/public/mojom/BUILD.gn index 435acd818f3..ee6240f24a1 100644 --- a/chromium/services/data_decoder/public/mojom/BUILD.gn +++ b/chromium/services/data_decoder/public/mojom/BUILD.gn @@ -10,11 +10,12 @@ mojom("mojom") { "image_decoder.mojom", "json_parser.mojom", "web_bundle_parser.mojom", + "web_bundler.mojom", "xml_parser.mojom", ] public_deps = [ - ":constants", + ":mojom_resource_snapshot_for_web_bundle", "//mojo/public/mojom/base", "//skia/public/mojom", "//ui/gfx/geometry/mojom", @@ -27,8 +28,18 @@ mojom("mojom") { } } -mojom("constants") { - sources = [ - "constants.mojom", +mojom("mojom_resource_snapshot_for_web_bundle") { + generate_java = true + sources = [ "resource_snapshot_for_web_bundle.mojom" ] + + public_deps = [ + "//mojo/public/mojom/base", + "//url/mojom:url_mojom_gurl", ] + + if (!is_ios) { + export_class_attribute_blink = "BLINK_PLATFORM_EXPORT" + export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1" + export_header_blink = "third_party/blink/public/platform/web_common.h" + } } diff --git a/chromium/services/data_decoder/public/mojom/constants.mojom b/chromium/services/data_decoder/public/mojom/constants.mojom deleted file mode 100644 index 60a96f275bd..00000000000 --- a/chromium/services/data_decoder/public/mojom/constants.mojom +++ /dev/null @@ -1,7 +0,0 @@ -// 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. - -module data_decoder.mojom; - -const string kServiceName = "data_decoder"; diff --git a/chromium/services/data_decoder/public/mojom/data_decoder_service.mojom b/chromium/services/data_decoder/public/mojom/data_decoder_service.mojom index 420b6d1552b..120ba37e7d4 100644 --- a/chromium/services/data_decoder/public/mojom/data_decoder_service.mojom +++ b/chromium/services/data_decoder/public/mojom/data_decoder_service.mojom @@ -6,6 +6,7 @@ module data_decoder.mojom; import "services/data_decoder/public/mojom/image_decoder.mojom"; import "services/data_decoder/public/mojom/json_parser.mojom"; +import "services/data_decoder/public/mojom/web_bundler.mojom"; import "services/data_decoder/public/mojom/web_bundle_parser.mojom"; import "services/data_decoder/public/mojom/xml_parser.mojom"; @@ -27,6 +28,9 @@ interface DataDecoderService { BindWebBundleParserFactory( pending_receiver<WebBundleParserFactory> receiver); + // Binds an interface which can be used to generate a Web Bundle. + BindWebBundler(pending_receiver<WebBundler> receiver); + // Binds an interface which can be used to parse raw BLE advertising packet // data. [EnableIf=is_chromeos] diff --git a/chromium/services/data_decoder/public/mojom/image_decoder.mojom b/chromium/services/data_decoder/public/mojom/image_decoder.mojom index 59f6a28ad1a..741e39c629f 100644 --- a/chromium/services/data_decoder/public/mojom/image_decoder.mojom +++ b/chromium/services/data_decoder/public/mojom/image_decoder.mojom @@ -10,7 +10,6 @@ import "ui/gfx/geometry/mojom/geometry.mojom"; enum ImageCodec { DEFAULT, - ROBUST_JPEG, ROBUST_PNG, }; diff --git a/chromium/services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom b/chromium/services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom new file mode 100644 index 00000000000..13408416fb0 --- /dev/null +++ b/chromium/services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom @@ -0,0 +1,26 @@ +// Copyright 2020 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. + +module data_decoder.mojom; + +import "mojo/public/mojom/base/big_buffer.mojom"; +import "url/mojom/url.mojom"; + +struct SerializedResourceInfo { + url.mojom.Url url; + string mime_type; + uint64 size; +}; + +// An interface to get resource snapshot of a frame to generate a web bundle. +// This interface is implemented by renderer processes. Its end point is set-up +// by the browser process and then passed to the utility process. +interface ResourceSnapshotForWebBundle { + // Returns the resource count. + GetResourceCount() => (uint64 count); + // Returns the resource info at the index. + GetResourceInfo(uint64 index) => (SerializedResourceInfo? info); + // Returns the body of the resource at the index. + GetResourceBody(uint64 index) => (mojo_base.mojom.BigBuffer? data); +}; diff --git a/chromium/services/data_decoder/public/mojom/web_bundle_parser.mojom b/chromium/services/data_decoder/public/mojom/web_bundle_parser.mojom index b912e5bd526..ca4c1be70a5 100644 --- a/chromium/services/data_decoder/public/mojom/web_bundle_parser.mojom +++ b/chromium/services/data_decoder/public/mojom/web_bundle_parser.mojom @@ -34,7 +34,8 @@ interface WebBundleParser { // Data source that provides application/webbundle data to the parser. interface BundleDataSource { - GetSize() => (uint64 size); + // Reads up to |length| bytes starting with |offset|. Returns a non-null + // buffer shorter than |length| iff the end of the stream is reached. Read(uint64 offset, uint64 length) => (array<uint8>? buffer); }; diff --git a/chromium/services/data_decoder/public/mojom/web_bundler.mojom b/chromium/services/data_decoder/public/mojom/web_bundler.mojom new file mode 100644 index 00000000000..879e0f7b860 --- /dev/null +++ b/chromium/services/data_decoder/public/mojom/web_bundler.mojom @@ -0,0 +1,24 @@ +// Copyright 2020 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. + +module data_decoder.mojom; + +import "services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom"; +import "mojo/public/mojom/base/file.mojom"; + +enum WebBundlerError { + kOK, + kNotImplemented, + kFileOpenFailed, + kWebBundlerConnectionError, +}; + +// Bundler interface to generate a web bundle from snapshots. +interface WebBundler { + // Generates a web bundle from |snapshots| and writes to the passed |file|. + Generate( + array<pending_remote<ResourceSnapshotForWebBundle>> snapshots, + mojo_base.mojom.File file) + => (uint64 file_size, WebBundlerError error); +}; diff --git a/chromium/services/data_decoder/web_bundle_parser.cc b/chromium/services/data_decoder/web_bundle_parser.cc index f140da1842c..e354823ca31 100644 --- a/chromium/services/data_decoder/web_bundle_parser.cc +++ b/chromium/services/data_decoder/web_bundle_parser.cc @@ -311,30 +311,22 @@ class WebBundleParser::MetadataParser ~MetadataParser() override { data_source_->RemoveObserver(this); } void Start() { - data_source_->GetSize(base::BindOnce(&MetadataParser::DidGetSize, - weak_factory_.GetWeakPtr())); - } - - private: - void DidGetSize(uint64_t size) { - size_ = size; - - // In the next step, we will parse `magic`, `version`, and the CBOR - // header of `primary-url`. + // First, we will parse `magic`, `version`, and the CBOR header of + // `primary-url`. // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#top-level - const uint64_t length = std::min(size, sizeof(kBundleMagicBytes) + - sizeof(kVersionB1MagicBytes) + - kMaxCBORItemHeaderSize); + const uint64_t length = sizeof(kBundleMagicBytes) + + sizeof(kVersionB1MagicBytes) + + kMaxCBORItemHeaderSize; data_source_->Read(0, length, base::BindOnce(&MetadataParser::ParseMagicBytes, - weak_factory_.GetWeakPtr(), length)); + weak_factory_.GetWeakPtr())); } + private: // Step 1-4 of // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#load-metadata - void ParseMagicBytes(uint64_t expected_data_length, - const base::Optional<std::vector<uint8_t>>& data) { - if (!data || data->size() != expected_data_length) { + void ParseMagicBytes(const base::Optional<std::vector<uint8_t>>& data) { + if (!data) { RunErrorCallbackAndDestroy("Error reading bundle magic bytes."); return; } @@ -381,22 +373,20 @@ class WebBundleParser::MetadataParser // In the next step, we will parse the content of `primary-url`, // `section-lengths`, and the CBOR header of `sections`. - const uint64_t length = std::min( - size_ - input.CurrentOffset(), - *url_length + kMaxSectionLengthsCBORSize + kMaxCBORItemHeaderSize * 2); + const uint64_t length = + *url_length + kMaxSectionLengthsCBORSize + kMaxCBORItemHeaderSize * 2; data_source_->Read(input.CurrentOffset(), length, base::BindOnce(&MetadataParser::ParseBundleHeader, - weak_factory_.GetWeakPtr(), length, - *url_length, input.CurrentOffset())); + weak_factory_.GetWeakPtr(), *url_length, + input.CurrentOffset())); } // Step 5-21 of // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#load-metadata - void ParseBundleHeader(uint64_t expected_data_length, - uint64_t url_length, + void ParseBundleHeader(uint64_t url_length, uint64_t offset_in_stream, const base::Optional<std::vector<uint8_t>>& data) { - if (!data || data->size() != expected_data_length) { + if (!data) { RunErrorCallbackAndDestroy("Error reading bundle header."); return; } @@ -534,9 +524,9 @@ class WebBundleParser::MetadataParser // Step 19.4. "Set currentOffset to currentOffset + length." if (!base::CheckAdd(current_offset, length) - .AssignIfValid(¤t_offset) || - current_offset > size_) { - RunErrorCallbackAndDestroy("Section doesn't fit in the bundle."); + .AssignIfValid(¤t_offset)) { + RunErrorCallbackAndDestroy( + "Integer overflow calculating section offsets."); return; } } @@ -1098,7 +1088,6 @@ class WebBundleParser::MetadataParser scoped_refptr<SharedBundleDataSource> data_source_; ParseMetadataCallback callback_; - uint64_t size_; bool version_mismatch_ = false; GURL fallback_url_; SectionOffsets section_offsets_; @@ -1325,11 +1314,6 @@ void WebBundleParser::SharedBundleDataSource::OnDisconnect() { observer->OnDisconnect(); } -void WebBundleParser::SharedBundleDataSource::GetSize( - GetSizeCallback callback) { - data_source_->GetSize(std::move(callback)); -} - void WebBundleParser::SharedBundleDataSource::Read(uint64_t offset, uint64_t length, ReadCallback callback) { diff --git a/chromium/services/data_decoder/web_bundle_parser.h b/chromium/services/data_decoder/web_bundle_parser.h index 3be1cb99385..81fe780badc 100644 --- a/chromium/services/data_decoder/web_bundle_parser.h +++ b/chromium/services/data_decoder/web_bundle_parser.h @@ -39,7 +39,6 @@ class WebBundleParser : public mojom::WebBundleParser { void RemoveObserver(Observer* observer); // Implements mojom::BundleDataSource. - void GetSize(GetSizeCallback callback) override; void Read(uint64_t offset, uint64_t length, ReadCallback callback) override; private: diff --git a/chromium/services/data_decoder/web_bundle_parser_factory.cc b/chromium/services/data_decoder/web_bundle_parser_factory.cc index 413d97f2c0f..1ead65ea90c 100644 --- a/chromium/services/data_decoder/web_bundle_parser_factory.cc +++ b/chromium/services/data_decoder/web_bundle_parser_factory.cc @@ -24,17 +24,15 @@ class FileDataSource final : public mojom::BundleDataSource { private: // Implements mojom::BundleDataSource. - void GetSize(GetSizeCallback callback) override { - std::move(callback).Run(file_.GetLength()); - } void Read(uint64_t offset, uint64_t length, ReadCallback callback) override { std::vector<uint8_t> buf(length); - uint64_t bytes = - file_.Read(offset, reinterpret_cast<char*>(buf.data()), length); - if (bytes != length) - std::move(callback).Run(base::nullopt); - else + int bytes = file_.Read(offset, reinterpret_cast<char*>(buf.data()), length); + if (bytes > 0) { + buf.resize(bytes); std::move(callback).Run(std::move(buf)); + } else { + std::move(callback).Run(base::nullopt); + } } mojo::Receiver<mojom::BundleDataSource> receiver_; diff --git a/chromium/services/data_decoder/web_bundle_parser_factory_unittest.cc b/chromium/services/data_decoder/web_bundle_parser_factory_unittest.cc index 72728db3050..c6cecfa12f1 100644 --- a/chromium/services/data_decoder/web_bundle_parser_factory_unittest.cc +++ b/chromium/services/data_decoder/web_bundle_parser_factory_unittest.cc @@ -53,31 +53,7 @@ class WebBundleParserFactoryTest : public testing::Test { base::test::TaskEnvironment task_environment_; }; -TEST_F(WebBundleParserFactoryTest, GetSize) { - base::FilePath test_file = base::FilePath(FILE_PATH_LITERAL("hello.wbn")); - - base::File file(GetTestFilePath(test_file), - base::File::FLAG_OPEN | base::File::FLAG_READ); - ASSERT_TRUE(file.IsValid()); - uint64_t file_size = file.GetLength(); - - mojo::PendingRemote<mojom::BundleDataSource> remote; - auto data_source = CreateFileDataSource( - remote.InitWithNewPipeAndPassReceiver(), std::move(file)); - - uint64_t result_size; - base::RunLoop run_loop; - data_source->GetSize( - base::BindLambdaForTesting([&result_size, &run_loop](uint64_t size) { - result_size = size; - run_loop.QuitClosure().Run(); - })); - run_loop.Run(); - - EXPECT_EQ(file_size, result_size); -} - -TEST_F(WebBundleParserFactoryTest, Read) { +TEST_F(WebBundleParserFactoryTest, FileDataSource) { base::FilePath test_file = GetTestFilePath(base::FilePath(FILE_PATH_LITERAL("hello.wbn"))); @@ -141,6 +117,21 @@ TEST_F(WebBundleParserFactoryTest, Read) { })); run_loop.Run(); } + ASSERT_TRUE(result_data); + EXPECT_EQ(last16b, *result_data); + + { + base::RunLoop run_loop; + data_source->Read( + file_length + 1, test_length, + base::BindLambdaForTesting( + [&result_data, + &run_loop](const base::Optional<std::vector<uint8_t>>& data) { + result_data = data; + run_loop.QuitClosure().Run(); + })); + run_loop.Run(); + } ASSERT_FALSE(result_data); } diff --git a/chromium/services/data_decoder/web_bundle_parser_fuzzer.cc b/chromium/services/data_decoder/web_bundle_parser_fuzzer.cc index 6d2aeba145e..df56a878f86 100644 --- a/chromium/services/data_decoder/web_bundle_parser_fuzzer.cc +++ b/chromium/services/data_decoder/web_bundle_parser_fuzzer.cc @@ -23,16 +23,13 @@ class DataSource : public data_decoder::mojom::BundleDataSource { public: DataSource(const uint8_t* data, size_t size) : data_(data), size_(size) {} - void GetSize(GetSizeCallback callback) override { - std::move(callback).Run(size_); - } - void Read(uint64_t offset, uint64_t length, ReadCallback callback) override { - if (offset + length > size_) { + if (offset >= size_) { std::move(callback).Run(base::nullopt); return; } const uint8_t* start = data_ + offset; + length = std::min(length, size_ - offset); std::move(callback).Run(std::vector<uint8_t>(start, start + length)); } @@ -64,8 +61,8 @@ class WebBundleParserFuzzer { std::move(data_source_remote)); quit_loop_ = run_loop->QuitClosure(); - parser_->ParseMetadata(base::Bind(&WebBundleParserFuzzer::OnParseMetadata, - base::Unretained(this))); + parser_->ParseMetadata(base::BindOnce( + &WebBundleParserFuzzer::OnParseMetadata, base::Unretained(this))); } void OnParseMetadata(data_decoder::mojom::BundleMetadataPtr metadata, @@ -87,9 +84,10 @@ class WebBundleParserFuzzer { return; } - parser_->ParseResponse(locations_[index]->offset, locations_[index]->length, - base::Bind(&WebBundleParserFuzzer::OnParseResponse, - base::Unretained(this), index)); + parser_->ParseResponse( + locations_[index]->offset, locations_[index]->length, + base::BindOnce(&WebBundleParserFuzzer::OnParseResponse, + base::Unretained(this), index)); } void OnParseResponse(size_t index, @@ -101,7 +99,7 @@ class WebBundleParserFuzzer { private: mojo::Remote<data_decoder::mojom::WebBundleParser> parser_; DataSource data_source_; - base::Closure quit_loop_; + base::OnceClosure quit_loop_; std::vector<data_decoder::mojom::BundleResponseLocationPtr> locations_; }; diff --git a/chromium/services/data_decoder/web_bundle_parser_unittest.cc b/chromium/services/data_decoder/web_bundle_parser_unittest.cc index 34d940c6548..eb637bacf9e 100644 --- a/chromium/services/data_decoder/web_bundle_parser_unittest.cc +++ b/chromium/services/data_decoder/web_bundle_parser_unittest.cc @@ -12,6 +12,7 @@ #include "base/test/task_environment.h" #include "components/cbor/writer.h" #include "mojo/public/cpp/bindings/receiver_set.h" +#include "services/data_decoder/public/cpp/test_support/web_bundle_builder.h" #include "testing/gtest/include/gtest/gtest.h" namespace data_decoder { @@ -43,16 +44,14 @@ class TestDataSource : public mojom::BundleDataSource { explicit TestDataSource(const std::vector<uint8_t>& data) : data_(reinterpret_cast<const char*>(data.data()), data.size()) {} - void GetSize(GetSizeCallback callback) override { - std::move(callback).Run(data_.size()); - } - void Read(uint64_t offset, uint64_t length, ReadCallback callback) override { - if (offset + length > data_.size()) + if (offset >= data_.size()) std::move(callback).Run(base::nullopt); const uint8_t* start = reinterpret_cast<const uint8_t*>(data_.data()) + offset; - std::move(callback).Run(std::vector<uint8_t>(start, start + length)); + uint64_t available_length = std::min(length, data_.size() - offset); + std::move(callback).Run( + std::vector<uint8_t>(start, start + available_length)); } base::StringPiece GetPayload(const mojom::BundleResponsePtr& response) { @@ -151,157 +150,6 @@ std::string AsString(const std::vector<uint8_t>& data) { return std::string(reinterpret_cast<const char*>(data.data()), data.size()); } -class BundleBuilder { - public: - using Headers = std::vector<std::pair<std::string, std::string>>; - struct ResponseLocation { - // /components/cbor uses int64_t for integer types. - int64_t offset; - int64_t length; - }; - - BundleBuilder(const std::string& fallback_url, - const std::string& manifest_url) - : fallback_url_(fallback_url) { - writer_config_.allow_invalid_utf8_for_testing = true; - if (!manifest_url.empty()) { - AddSection("manifest", - cbor::Value::InvalidUTF8StringValueForTesting(manifest_url)); - } - } - - void AddExchange(base::StringPiece url, - const Headers& response_headers, - base::StringPiece payload) { - AddIndexEntry(url, "", {AddResponse(response_headers, payload)}); - } - - ResponseLocation AddResponse(const Headers& headers, - base::StringPiece payload) { - // We assume that the size of the CBOR header of the responses array is 1, - // which is true only if the responses array has no more than 23 elements. - EXPECT_LT(responses_.size(), 23u) - << "BundleBuilder cannot create bundles with more than 23 responses"; - - cbor::Value::ArrayValue response_array; - response_array.emplace_back(Encode(CreateHeaderMap(headers))); - response_array.emplace_back(CreateByteString(payload)); - cbor::Value response(response_array); - int64_t response_length = EncodedLength(response); - ResponseLocation result = {current_responses_offset_, response_length}; - current_responses_offset_ += response_length; - responses_.emplace_back(std::move(response)); - return result; - } - - void AddIndexEntry(base::StringPiece url, - base::StringPiece variants_value, - std::vector<ResponseLocation> response_locations) { - cbor::Value::ArrayValue index_value_array; - index_value_array.emplace_back(CreateByteString(variants_value)); - for (const auto& location : response_locations) { - index_value_array.emplace_back(location.offset); - index_value_array.emplace_back(location.length); - } - index_.insert({cbor::Value::InvalidUTF8StringValueForTesting(url), - cbor::Value(index_value_array)}); - } - - void AddSection(base::StringPiece name, cbor::Value section) { - section_lengths_.emplace_back(name); - section_lengths_.emplace_back(EncodedLength(section)); - sections_.emplace_back(std::move(section)); - } - - void AddAuthority(cbor::Value::MapValue authority) { - authorities_.emplace_back(std::move(authority)); - } - - void AddVouchedSubset(cbor::Value::MapValue vouched_subset) { - vouched_subsets_.emplace_back(std::move(vouched_subset)); - } - - std::vector<uint8_t> CreateBundle() { - AddSection("index", cbor::Value(index_)); - if (!authorities_.empty() || !vouched_subsets_.empty()) { - cbor::Value::ArrayValue signatures_section; - signatures_section.emplace_back(std::move(authorities_)); - signatures_section.emplace_back(std::move(vouched_subsets_)); - AddSection("signatures", cbor::Value(std::move(signatures_section))); - } - AddSection("responses", cbor::Value(responses_)); - return Encode(CreateTopLevel()); - } - - // Creates a signed-subset structure with single subset-hashes entry, - // and returns it as a CBOR bytestring. - cbor::Value CreateEncodedSigned(base::StringPiece validity_url, - base::StringPiece auth_sha256, - int64_t date, - int64_t expires, - base::StringPiece url, - base::StringPiece header_sha256, - base::StringPiece payload_integrity_header) { - cbor::Value::ArrayValue subset_hash_value; - subset_hash_value.emplace_back(CreateByteString("")); // variants-value - subset_hash_value.emplace_back(CreateByteString(header_sha256)); - subset_hash_value.emplace_back(payload_integrity_header); - - cbor::Value::MapValue subset_hashes; - subset_hashes.emplace(url, std::move(subset_hash_value)); - - cbor::Value::MapValue signed_subset; - signed_subset.emplace("validity-url", validity_url); - signed_subset.emplace("auth-sha256", CreateByteString(auth_sha256)); - signed_subset.emplace("date", date); - signed_subset.emplace("expires", expires); - signed_subset.emplace("subset-hashes", std::move(subset_hashes)); - return cbor::Value(Encode(cbor::Value(signed_subset))); - } - - private: - static cbor::Value CreateHeaderMap(const Headers& headers) { - cbor::Value::MapValue map; - for (const auto& pair : headers) - map.insert({CreateByteString(pair.first), CreateByteString(pair.second)}); - return cbor::Value(std::move(map)); - } - - cbor::Value CreateTopLevel() { - cbor::Value::ArrayValue toplevel_array; - toplevel_array.emplace_back( - CreateByteString(u8"\U0001F310\U0001F4E6")); // "🌐📦" - toplevel_array.emplace_back( - CreateByteString(base::StringPiece("b1\0\0", 4))); - toplevel_array.emplace_back( - cbor::Value::InvalidUTF8StringValueForTesting(fallback_url_)); - toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_))); - toplevel_array.emplace_back(sections_); - toplevel_array.emplace_back(CreateByteString("")); // length (ignored) - return cbor::Value(toplevel_array); - } - - std::vector<uint8_t> Encode(const cbor::Value& value) { - return *cbor::Writer::Write(value, writer_config_); - } - - int64_t EncodedLength(const cbor::Value& value) { - return Encode(value).size(); - } - - cbor::Writer::Config writer_config_; - std::string fallback_url_; - cbor::Value::ArrayValue section_lengths_; - cbor::Value::ArrayValue sections_; - cbor::Value::MapValue index_; - cbor::Value::ArrayValue responses_; - cbor::Value::ArrayValue authorities_; - cbor::Value::ArrayValue vouched_subsets_; - - // 1 for the CBOR header byte. See the comment at the top of AddResponse(). - int64_t current_responses_offset_ = 1; -}; - } // namespace class WebBundleParserTest : public testing::Test { @@ -310,7 +158,7 @@ class WebBundleParserTest : public testing::Test { }; TEST_F(WebBundleParserTest, WrongMagic) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); std::vector<uint8_t> bundle = builder.CreateBundle(); bundle[3] ^= 1; TestDataSource data_source(bundle); @@ -322,7 +170,7 @@ TEST_F(WebBundleParserTest, WrongMagic) { } TEST_F(WebBundleParserTest, UnknownVersion) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); std::vector<uint8_t> bundle = builder.CreateBundle(); // Modify the version string from "b1\0\0" to "q1\0\0". ASSERT_EQ(bundle[11], 'b'); @@ -336,7 +184,7 @@ TEST_F(WebBundleParserTest, UnknownVersion) { } TEST_F(WebBundleParserTest, FallbackURLIsNotUTF8) { - BundleBuilder builder("https://test.example.com/\xcc", kManifestUrl); + test::WebBundleBuilder builder("https://test.example.com/\xcc", kManifestUrl); std::vector<uint8_t> bundle = builder.CreateBundle(); TestDataSource data_source(bundle); @@ -347,7 +195,8 @@ TEST_F(WebBundleParserTest, FallbackURLIsNotUTF8) { } TEST_F(WebBundleParserTest, FallbackURLHasFragment) { - BundleBuilder builder("https://test.example.com/#fragment", kManifestUrl); + test::WebBundleBuilder builder("https://test.example.com/#fragment", + kManifestUrl); std::vector<uint8_t> bundle = builder.CreateBundle(); TestDataSource data_source(bundle); @@ -358,7 +207,7 @@ TEST_F(WebBundleParserTest, FallbackURLHasFragment) { } TEST_F(WebBundleParserTest, SectionLengthsTooLarge) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); std::string too_long_section_name(8192, 'x'); builder.AddSection(too_long_section_name, cbor::Value(0)); TestDataSource data_source(builder.CreateBundle()); @@ -367,7 +216,7 @@ TEST_F(WebBundleParserTest, SectionLengthsTooLarge) { } TEST_F(WebBundleParserTest, DuplicateSectionName) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddSection("foo", cbor::Value(0)); builder.AddSection("foo", cbor::Value(0)); TestDataSource data_source(builder.CreateBundle()); @@ -376,7 +225,7 @@ TEST_F(WebBundleParserTest, DuplicateSectionName) { } TEST_F(WebBundleParserTest, SingleEntry) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -396,7 +245,7 @@ TEST_F(WebBundleParserTest, SingleEntry) { } TEST_F(WebBundleParserTest, InvalidRequestURL) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); TestDataSource data_source(builder.CreateBundle()); @@ -405,7 +254,7 @@ TEST_F(WebBundleParserTest, InvalidRequestURL) { } TEST_F(WebBundleParserTest, RequestURLIsNotUTF8) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/\xcc", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -415,7 +264,7 @@ TEST_F(WebBundleParserTest, RequestURLIsNotUTF8) { } TEST_F(WebBundleParserTest, RequestURLHasBadScheme) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("file:///tmp/foo", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -425,7 +274,7 @@ TEST_F(WebBundleParserTest, RequestURLHasBadScheme) { } TEST_F(WebBundleParserTest, RequestURLHasCredentials) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://user:passwd@test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -435,7 +284,7 @@ TEST_F(WebBundleParserTest, RequestURLHasCredentials) { } TEST_F(WebBundleParserTest, RequestURLHasFragment) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/#fragment", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -445,7 +294,7 @@ TEST_F(WebBundleParserTest, RequestURLHasFragment) { } TEST_F(WebBundleParserTest, NoStatusInResponseHeaders) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{"content-type", "text/plain"}}, "payload"); // ":status" is missing. @@ -459,7 +308,7 @@ TEST_F(WebBundleParserTest, NoStatusInResponseHeaders) { } TEST_F(WebBundleParserTest, InvalidResponseStatus) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "0200"}, {"content-type", "text/plain"}}, "payload"); @@ -473,7 +322,7 @@ TEST_F(WebBundleParserTest, InvalidResponseStatus) { } TEST_F(WebBundleParserTest, ExtraPseudoInResponseHeaders) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange( "https://test.example.com/", {{":status", "200"}, {":foo", ""}, {"content-type", "text/plain"}}, @@ -488,7 +337,7 @@ TEST_F(WebBundleParserTest, ExtraPseudoInResponseHeaders) { } TEST_F(WebBundleParserTest, UpperCaseCharacterInHeaderName) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"Content-Type", "text/plain"}}, "payload"); @@ -502,7 +351,7 @@ TEST_F(WebBundleParserTest, UpperCaseCharacterInHeaderName) { } TEST_F(WebBundleParserTest, InvalidHeaderValue) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "\n"}}, "payload"); TestDataSource data_source(builder.CreateBundle()); @@ -515,7 +364,7 @@ TEST_F(WebBundleParserTest, InvalidHeaderValue) { } TEST_F(WebBundleParserTest, NoContentTypeWithNonEmptyContent) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}}, "payload"); TestDataSource data_source(builder.CreateBundle()); @@ -528,7 +377,7 @@ TEST_F(WebBundleParserTest, NoContentTypeWithNonEmptyContent) { } TEST_F(WebBundleParserTest, NoContentTypeWithEmptyContent) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "301"}}, ""); TestDataSource data_source(builder.CreateBundle()); @@ -540,7 +389,7 @@ TEST_F(WebBundleParserTest, NoContentTypeWithEmptyContent) { } TEST_F(WebBundleParserTest, Variants) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); auto location1 = builder.AddResponse( {{":status", "200"}, {"content-type", "text/html"}}, "payload1"); auto location2 = builder.AddResponse( @@ -569,7 +418,7 @@ TEST_F(WebBundleParserTest, Variants) { } TEST_F(WebBundleParserTest, EmptyIndexEntry) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddIndexEntry("https://test.example.com/", "", {}); TestDataSource data_source(builder.CreateBundle()); @@ -577,7 +426,7 @@ TEST_F(WebBundleParserTest, EmptyIndexEntry) { } TEST_F(WebBundleParserTest, EmptyIndexEntryWithVariants) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddIndexEntry("https://test.example.com/", "Accept;text/html;text/plain", {}); TestDataSource data_source(builder.CreateBundle()); @@ -586,7 +435,7 @@ TEST_F(WebBundleParserTest, EmptyIndexEntryWithVariants) { } TEST_F(WebBundleParserTest, MultipleResponsesWithoutVariantsValue) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); auto location1 = builder.AddResponse( {{":status", "200"}, {"content-type", "text/html"}}, "payload1"); auto location2 = builder.AddResponse( @@ -599,7 +448,7 @@ TEST_F(WebBundleParserTest, MultipleResponsesWithoutVariantsValue) { } TEST_F(WebBundleParserTest, AllKnownSectionInCritical) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -616,7 +465,7 @@ TEST_F(WebBundleParserTest, AllKnownSectionInCritical) { } TEST_F(WebBundleParserTest, UnknownSectionInCritical) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -629,7 +478,7 @@ TEST_F(WebBundleParserTest, UnknownSectionInCritical) { } TEST_F(WebBundleParserTest, NoManifest) { - BundleBuilder builder(kFallbackUrl, std::string()); + test::WebBundleBuilder builder(kFallbackUrl, std::string()); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -640,7 +489,7 @@ TEST_F(WebBundleParserTest, NoManifest) { } TEST_F(WebBundleParserTest, InvalidManifestURL) { - BundleBuilder builder(kFallbackUrl, "not-an-absolute-url"); + test::WebBundleBuilder builder(kFallbackUrl, "not-an-absolute-url"); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -650,11 +499,12 @@ TEST_F(WebBundleParserTest, InvalidManifestURL) { } TEST_F(WebBundleParserTest, EmptySignaturesSection) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); - // BundleBuilder omits signatures section if empty, so create it ourselves. + // test::WebBundleBuilder omits signatures section if empty, so create it + // ourselves. cbor::Value::ArrayValue signatures_section; signatures_section.emplace_back(cbor::Value::ArrayValue()); // authorities signatures_section.emplace_back( @@ -669,7 +519,7 @@ TEST_F(WebBundleParserTest, EmptySignaturesSection) { } TEST_F(WebBundleParserTest, SignaturesSection) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); @@ -728,7 +578,7 @@ TEST_F(WebBundleParserTest, SignaturesSection) { } TEST_F(WebBundleParserTest, MultipleSignatures) { - BundleBuilder builder(kFallbackUrl, kManifestUrl); + test::WebBundleBuilder builder(kFallbackUrl, kManifestUrl); builder.AddExchange("https://test.example.com/", {{":status", "200"}, {"content-type", "text/plain"}}, "payload"); diff --git a/chromium/services/data_decoder/web_bundler.cc b/chromium/services/data_decoder/web_bundler.cc new file mode 100644 index 00000000000..dd4537fd8da --- /dev/null +++ b/chromium/services/data_decoder/web_bundler.cc @@ -0,0 +1,19 @@ +// Copyright 2020 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 "services/data_decoder/web_bundler.h" + +namespace data_decoder { + +void WebBundler::Generate( + std::vector<mojo::PendingRemote<mojom::ResourceSnapshotForWebBundle>> + snapshots, + base::File file, + GenerateCallback callback) { + // The Web Bundle generation logic is not implemented yet. + // TODO(crbug.com/1040752): Implement this. + std::move(callback).Run(0, mojom::WebBundlerError::kNotImplemented); +} + +} // namespace data_decoder diff --git a/chromium/services/data_decoder/web_bundler.h b/chromium/services/data_decoder/web_bundler.h new file mode 100644 index 00000000000..36be2141048 --- /dev/null +++ b/chromium/services/data_decoder/web_bundler.h @@ -0,0 +1,37 @@ +// Copyright 2020 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. + +#ifndef SERVICES_DATA_DECODER_WEB_BUNDLER_H_ +#define SERVICES_DATA_DECODER_WEB_BUNDLER_H_ + +#include <vector> + +#include "base/files/file.h" +#include "mojo/public/cpp/base/big_buffer.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "services/data_decoder/public/mojom/resource_snapshot_for_web_bundle.mojom.h" +#include "services/data_decoder/public/mojom/web_bundler.mojom.h" + +namespace data_decoder { + +class WebBundler : public mojom::WebBundler { + public: + WebBundler() = default; + ~WebBundler() override = default; + + WebBundler(const WebBundler&) = delete; + WebBundler& operator=(const WebBundler&) = delete; + + private: + // mojom::WebBundler implementation. + void Generate( + std::vector<mojo::PendingRemote<mojom::ResourceSnapshotForWebBundle>> + snapshots, + base::File file, + GenerateCallback callback) override; +}; + +} // namespace data_decoder + +#endif // SERVICES_DATA_DECODER_WEB_BUNDLER_H_ diff --git a/chromium/services/data_decoder/xml_parser_fuzzer.cc b/chromium/services/data_decoder/xml_parser_fuzzer.cc index 8cd6f62dba4..7b23ff63a50 100644 --- a/chromium/services/data_decoder/xml_parser_fuzzer.cc +++ b/chromium/services/data_decoder/xml_parser_fuzzer.cc @@ -15,7 +15,7 @@ namespace { -void OnParseXml(base::Closure quit_loop, +void OnParseXml(base::OnceClosure quit_loop, base::Optional<base::Value> value, const base::Optional<std::string>& error) { std::move(quit_loop).Run(); @@ -38,7 +38,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { base::SingleThreadTaskExecutor main_thread_task_executor; base::RunLoop run_loop; xml_parser.Parse(std::string(data_ptr, size), - base::Bind(&OnParseXml, run_loop.QuitClosure())); + base::BindOnce(&OnParseXml, run_loop.QuitClosure())); run_loop.Run(); return 0; diff --git a/chromium/services/data_decoder/xml_parser_unittest.cc b/chromium/services/data_decoder/xml_parser_unittest.cc index f0d7868e406..561826d2b52 100644 --- a/chromium/services/data_decoder/xml_parser_unittest.cc +++ b/chromium/services/data_decoder/xml_parser_unittest.cc @@ -35,7 +35,8 @@ void TestParseXml(const std::string& xml, const std::string& json) { std::unique_ptr<base::Value> actual_value; base::Optional<std::string> error; - parser.Parse(xml, base::Bind(&TestParseXmlCallback, &actual_value, &error)); + parser.Parse(xml, + base::BindOnce(&TestParseXmlCallback, &actual_value, &error)); if (json.empty()) { EXPECT_TRUE(error); EXPECT_FALSE(actual_value) |