diff --git a/chromium_edits/120.0.6099.200/chrome/browser/BUILD.gn.patch b/chromium_edits/120.0.6099.200/chrome/browser/BUILD.gn.patch new file mode 100644 index 00000000..1c014908 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/BUILD.gn.patch @@ -0,0 +1,27 @@ +diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn +index 44d3b5e543101..35bbe5da7daf8 100644 +--- a/chrome/browser/BUILD.gn ++++ b/chrome/browser/BUILD.gn +@@ -40,6 +40,7 @@ import("//rlz/buildflags/buildflags.gni") + import("//sandbox/features.gni") + import("//testing/libfuzzer/fuzzer_test.gni") + import("//third_party/blink/public/public_features.gni") ++import("//third_party/ipfs_client/args.gni") + import("//third_party/protobuf/proto_library.gni") + import("//third_party/webrtc/webrtc.gni") + import("//third_party/widevine/cdm/widevine.gni") +@@ -2660,6 +2661,14 @@ static_library("browser") { + ] + } + ++ if (enable_ipfs) { ++ sources += [ ++ "ipfs_extra_parts.cc", ++ "ipfs_extra_parts.h", ++ ] ++ deps += [ "//components/ipfs" ] ++ } ++ + if (is_chromeos_ash) { + deps += [ "//chrome/browser/screen_ai:screen_ai_dlc_installer" ] + } diff --git a/chromium_edits/120.0.6099.200/chrome/browser/about_flags.cc.patch b/chromium_edits/120.0.6099.200/chrome/browser/about_flags.cc.patch new file mode 100644 index 00000000..bec369fa --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/about_flags.cc.patch @@ -0,0 +1,38 @@ +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +index 8736a91998f6b..da556109dcbb1 100644 +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -213,6 +213,7 @@ + #include "third_party/blink/public/common/features_generated.h" + #include "third_party/blink/public/common/forcedark/forcedark_switches.h" + #include "third_party/blink/public/common/switches.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + #include "ui/accessibility/accessibility_features.h" + #include "ui/accessibility/accessibility_switches.h" + #include "ui/base/ui_base_features.h" +@@ -314,6 +315,10 @@ + #include "extensions/common/switches.h" + #endif // BUILDFLAG(ENABLE_EXTENSIONS) + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#endif ++ + #if BUILDFLAG(ENABLE_PDF) + #include "pdf/pdf_features.h" + #endif +@@ -9922,6 +9927,14 @@ const FeatureEntry kFeatureEntries[] = { + flag_descriptions::kOmitCorsClientCertDescription, kOsAll, + FEATURE_VALUE_TYPE(network::features::kOmitCorsClientCert)}, + ++#if BUILDFLAG(ENABLE_IPFS) ++ {"enable-ipfs", ++ flag_descriptions::kEnableIpfsName, ++ flag_descriptions::kEnableIpfsDescription, ++ kOsMac | kOsWin | kOsLinux,//TODO: These are the only variants currently getting built, but that is not likely to remain the case ++ FEATURE_VALUE_TYPE(ipfs::kEnableIpfs)}, ++#endif ++ + {"use-idna2008-non-transitional", + flag_descriptions::kUseIDNA2008NonTransitionalName, + flag_descriptions::kUseIDNA2008NonTransitionalDescription, kOsAll, diff --git a/chromium_edits/120.0.6099.200/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch b/chromium_edits/120.0.6099.200/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch new file mode 100644 index 00000000..4d172311 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch @@ -0,0 +1,50 @@ +diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc +index 4c88614c68c25..f8bb12a3b0c2e 100644 +--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc ++++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc +@@ -10,6 +10,8 @@ + #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" + #include "chrome/browser/external_protocol/external_protocol_handler.h" + #include "chrome/browser/profiles/profile.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" ++ + #if BUILDFLAG(IS_ANDROID) + #include "chrome/browser/profiles/profile_android.h" + #endif +@@ -18,6 +20,9 @@ + #include "chrome/browser/ui/android/omnibox/jni_headers/ChromeAutocompleteSchemeClassifier_jni.h" + #endif + #include "components/custom_handlers/protocol_handler_registry.h" ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#endif + #include "content/public/common/url_constants.h" + #include "url/url_util.h" + +@@ -55,12 +60,20 @@ ChromeAutocompleteSchemeClassifier::GetInputTypeForScheme( + if (scheme.empty()) { + return metrics::OmniboxInputType::EMPTY; + } +- if (base::IsStringASCII(scheme) && +- (ProfileIOData::IsHandledProtocol(scheme) || +- base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) || +- base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) || +- base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme))) { +- return metrics::OmniboxInputType::URL; ++ if (base::IsStringASCII(scheme)) { ++ if (ProfileIOData::IsHandledProtocol(scheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme)) { ++ return metrics::OmniboxInputType::URL; ++ } ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs) && ++ (base::EqualsCaseInsensitiveASCII(scheme, "ipfs") || base::EqualsCaseInsensitiveASCII(scheme, "ipns")) ++ ) { ++ return metrics::OmniboxInputType::URL; ++ } ++#endif + } + + // Also check for schemes registered via registerProtocolHandler(), which diff --git a/chromium_edits/120.0.6099.200/chrome/browser/chrome_content_browser_client.cc.patch b/chromium_edits/120.0.6099.200/chrome/browser/chrome_content_browser_client.cc.patch new file mode 100644 index 00000000..fcd5a818 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/chrome_content_browser_client.cc.patch @@ -0,0 +1,78 @@ +diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc +index d9c675c8aca73..8fbea741919d8 100644 +--- a/chrome/browser/chrome_content_browser_client.cc ++++ b/chrome/browser/chrome_content_browser_client.cc +@@ -364,6 +364,7 @@ + #include "third_party/blink/public/common/switches.h" + #include "third_party/blink/public/mojom/browsing_topics/browsing_topics.mojom.h" + #include "third_party/blink/public/public_buildflags.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + #include "third_party/widevine/cdm/buildflags.h" + #include "ui/base/clipboard/clipboard_format_type.h" + #include "ui/base/l10n/l10n_util.h" +@@ -487,6 +488,13 @@ + #include "chrome/browser/fuchsia/chrome_browser_main_parts_fuchsia.h" + #endif + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "chrome/browser/ipfs_extra_parts.h" ++#include "components/ipfs/interceptor.h" ++#include "components/ipfs/ipfs_features.h" ++#include "components/ipfs/url_loader_factory.h" ++#endif ++ + #if BUILDFLAG(IS_CHROMEOS) + #include "base/debug/leak_annotations.h" + #include "chrome/browser/apps/intent_helper/chromeos_disabled_apps_throttle.h" +@@ -1816,6 +1824,11 @@ ChromeContentBrowserClient::CreateBrowserMainParts(bool is_integration_test) { + main_parts->AddParts( + std::make_unique()); + ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ main_parts->AddParts(std::make_unique()); ++ } ++#endif + return main_parts; + } + +@@ -6180,12 +6193,25 @@ void ChromeContentBrowserClient:: + const absl::optional& request_initiator_origin, + NonNetworkURLLoaderFactoryMap* factories) { + #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ +- !BUILDFLAG(IS_ANDROID) ++ !BUILDFLAG(IS_ANDROID) || BUILDFLAG(ENABLE_IPFS) + content::RenderFrameHost* frame_host = + RenderFrameHost::FromID(render_process_id, render_frame_id); + WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host); + #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ +- // !BUILDFLAG(IS_ANDROID) ++ // !BUILDFLAG(IS_ANDROID) || BUILDFLAG(ENABLE_IPFS) ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ network::mojom::URLLoaderFactory* default_factory = g_browser_process->system_network_context_manager()->GetURLLoaderFactory(); ++ auto* context = web_contents->GetBrowserContext(); ++ ipfs::IpfsURLLoaderFactory::Create( ++ factories, ++ context, ++ default_factory, ++ GetSystemNetworkContext(), ++ Profile::FromBrowserContext(context)->GetPrefs() ++ ); ++ } ++#endif // BUILDFLAG(ENABLE_IPFS) + + #if BUILDFLAG(IS_CHROMEOS_ASH) + if (web_contents) { +@@ -6327,6 +6353,11 @@ ChromeContentBrowserClient::WillCreateURLLoaderRequestInterceptors( + scoped_refptr navigation_response_task_runner) { + std::vector> + interceptors; ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ interceptors.push_back(std::make_unique(g_browser_process->system_network_context_manager()->GetURLLoaderFactory(), GetSystemNetworkContext())); ++ } ++#endif + #if BUILDFLAG(ENABLE_OFFLINE_PAGES) + interceptors.push_back( + std::make_unique( diff --git a/chromium_edits/120.0.6099.200/chrome/browser/flag-metadata.json.patch b/chromium_edits/120.0.6099.200/chrome/browser/flag-metadata.json.patch new file mode 100644 index 00000000..f7c408d8 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/flag-metadata.json.patch @@ -0,0 +1,16 @@ +diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json +index 400505f9d64e6..320b730d894c6 100644 +--- a/chrome/browser/flag-metadata.json ++++ b/chrome/browser/flag-metadata.json +@@ -2868,6 +2868,11 @@ + "owners": [ "hanxi@chromium.org", "wychen@chromium.org" ], + "expiry_milestone": 130 + }, ++ { ++ "name": "enable-ipfs", ++ "owners": [ "//components/ipfs/OWNERS" ], ++ "expiry_milestone": 150 ++ }, + { + "name": "enable-isolated-sandboxed-iframes", + "owners": [ "wjmaclean@chromium.org", "alexmos@chromium.org", "creis@chromium.org" ], diff --git a/chromium_edits/120.0.6099.200/chrome/browser/flag_descriptions.cc.patch b/chromium_edits/120.0.6099.200/chrome/browser/flag_descriptions.cc.patch new file mode 100644 index 00000000..d021535f --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/flag_descriptions.cc.patch @@ -0,0 +1,16 @@ +diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc +index f92c5df0fc600..e131baa70cce2 100644 +--- a/chrome/browser/flag_descriptions.cc ++++ b/chrome/browser/flag_descriptions.cc +@@ -248,6 +248,11 @@ const char kEnableBenchmarkingDescription[] = + "after 3 restarts. On the third restart, the flag will appear to be off " + "but the effect is still active."; + ++#if BUILDFLAG(ENABLE_IPFS) ++extern const char kEnableIpfsName[] = "Enable IPFS"; ++extern const char kEnableIpfsDescription[] = "Enable ipfs:// and ipns:// URLs"; ++#endif ++ + const char kPreloadingOnPerformancePageName[] = + "Preloading Settings on Performance Page"; + const char kPreloadingOnPerformancePageDescription[] = diff --git a/chromium_edits/120.0.6099.200/chrome/browser/flag_descriptions.h.patch b/chromium_edits/120.0.6099.200/chrome/browser/flag_descriptions.h.patch new file mode 100644 index 00000000..e7d95550 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/flag_descriptions.h.patch @@ -0,0 +1,24 @@ +diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h +index 71eae84724eab..a8e4b29ee3cc5 100644 +--- a/chrome/browser/flag_descriptions.h ++++ b/chrome/browser/flag_descriptions.h +@@ -22,6 +22,7 @@ + #include "pdf/buildflags.h" + #include "printing/buildflags/buildflags.h" + #include "third_party/blink/public/common/buildflags.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + + // This file declares strings used in chrome://flags. These messages are not + // translated, because instead of end-users they target Chromium developers and +@@ -165,6 +166,11 @@ extern const char kDownloadWarningImprovementsDescription[]; + extern const char kEnableBenchmarkingName[]; + extern const char kEnableBenchmarkingDescription[]; + ++#if BUILDFLAG(ENABLE_IPFS) ++extern const char kEnableIpfsName[]; ++extern const char kEnableIpfsDescription[]; ++#endif ++ + #if BUILDFLAG(USE_FONTATIONS_BACKEND) + extern const char kFontationsFontBackendName[]; + extern const char kFontationsFontBackendDescription[]; diff --git a/chromium_edits/120.0.6099.200/chrome/browser/ipfs_extra_parts.cc b/chromium_edits/120.0.6099.200/chrome/browser/ipfs_extra_parts.cc new file mode 100644 index 00000000..90d2596f --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/ipfs_extra_parts.cc @@ -0,0 +1,10 @@ +#include "ipfs_extra_parts.h" + +#include "profiles/profile.h" + +#include + +void IpfsExtraParts::PostProfileInit(Profile* profile, bool /* is_initial_profile */ ) { + DCHECK(profile); + ipfs::InterRequestState::CreateForBrowserContext(profile, profile->GetPrefs()); +} diff --git a/chromium_edits/120.0.6099.200/chrome/browser/ipfs_extra_parts.h b/chromium_edits/120.0.6099.200/chrome/browser/ipfs_extra_parts.h new file mode 100644 index 00000000..2059c437 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/ipfs_extra_parts.h @@ -0,0 +1,10 @@ +#ifndef IPFS_EXTRA_PART_H_ +#define IPFS_EXTRA_PART_H_ + +#include + +class IpfsExtraParts : public ChromeBrowserMainExtraParts { + void PostProfileInit(Profile* profile, bool is_initial_profile) override; +}; + +#endif // IPFS_EXTRA_PART_H_ diff --git a/chromium_edits/120.0.6099.200/chrome/browser/prefs/browser_prefs.cc.patch b/chromium_edits/120.0.6099.200/chrome/browser/prefs/browser_prefs.cc.patch new file mode 100644 index 00000000..74d8f674 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/browser/prefs/browser_prefs.cc.patch @@ -0,0 +1,36 @@ +diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc +index 0af94fd3059cf..60a20373ed748 100644 +--- a/chrome/browser/prefs/browser_prefs.cc ++++ b/chrome/browser/prefs/browser_prefs.cc +@@ -184,6 +184,7 @@ + #include "printing/buildflags/buildflags.h" + #include "rlz/buildflags/buildflags.h" + #include "third_party/abseil-cpp/absl/types/optional.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + + #if BUILDFLAG(ENABLE_BACKGROUND_MODE) + #include "chrome/browser/background/background_mode_manager.h" +@@ -234,6 +235,11 @@ + #include "chrome/browser/pdf/pdf_pref_names.h" + #endif // BUILDFLAG(ENABLE_PDF) + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#include "components/ipfs/preferences.h" ++#endif ++ + #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) + #include "chrome/browser/screen_ai/pref_names.h" + #endif +@@ -1662,6 +1668,11 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry, + IncognitoModePrefs::RegisterProfilePrefs(registry); + invalidation::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry); + invalidation::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry); ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ ipfs::RegisterPreferences(registry); ++ } ++#endif + language::LanguagePrefs::RegisterProfilePrefs(registry); + login_detection::prefs::RegisterProfilePrefs(registry); + lookalikes::RegisterProfilePrefs(registry); diff --git a/chromium_edits/120.0.6099.200/chrome/common/chrome_content_client.cc.patch b/chromium_edits/120.0.6099.200/chrome/common/chrome_content_client.cc.patch new file mode 100644 index 00000000..5bd09f16 --- /dev/null +++ b/chromium_edits/120.0.6099.200/chrome/common/chrome_content_client.cc.patch @@ -0,0 +1,17 @@ +diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc +index 246ec9c5c911f..5d66d133a7907 100644 +--- a/chrome/common/chrome_content_client.cc ++++ b/chrome/common/chrome_content_client.cc +@@ -296,6 +296,12 @@ void ChromeContentClient::AddAdditionalSchemes(Schemes* schemes) { + #if BUILDFLAG(IS_ANDROID) + schemes->local_schemes.push_back(url::kContentScheme); + #endif ++ for ( const char* ip_s : {"ipfs", "ipns"} ) { ++ schemes->standard_schemes.push_back(ip_s); ++ schemes->cors_enabled_schemes.push_back(ip_s); ++ schemes->secure_schemes.push_back(ip_s); ++ schemes->csp_bypassing_schemes.push_back(ip_s); ++ } + } + + std::u16string ChromeContentClient::GetLocalizedString(int message_id) { diff --git a/chromium_edits/120.0.6099.200/components/cbor/reader.cc.patch b/chromium_edits/120.0.6099.200/components/cbor/reader.cc.patch new file mode 100644 index 00000000..aed86452 --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/reader.cc.patch @@ -0,0 +1,44 @@ +diff --git a/components/cbor/reader.cc b/components/cbor/reader.cc +index 306ba52fa4944..6b13b3a679a65 100644 +--- a/components/cbor/reader.cc ++++ b/components/cbor/reader.cc +@@ -22,7 +22,7 @@ + namespace cbor { + + namespace constants { +-const char kUnsupportedMajorType[] = "Unsupported major type."; ++const char kUnsupportedMajorType[] = "Unsupported major type operation."; + } + + namespace { +@@ -156,7 +156,11 @@ absl::optional Reader::DecodeCompleteDataItem(const Config& config, + case Value::Type::FLOAT_VALUE: + // Floating point values also go here since they are also type 7. + return DecodeToSimpleValueOrFloat(*header, config); +- case Value::Type::TAG: // We explicitly don't support TAG. ++ case Value::Type::TAG: ++ if (config.parse_tags) { ++ return ReadTagContent(*header, config, max_nesting_level); ++ } ++ break; + case Value::Type::NONE: + case Value::Type::INVALID_UTF8: + break; +@@ -347,6 +351,17 @@ absl::optional Reader::ReadByteStringContent( + return Value(std::move(cbor_byte_string)); + } + ++absl::optional Reader::ReadTagContent( ++ const Reader::DataItemHeader& header, ++ const Config& config, ++ int max_nesting_level) { ++ auto tagged_content = DecodeCompleteDataItem(config, max_nesting_level); ++ if (tagged_content.has_value()) { ++ tagged_content.value().SetTag(header.value); ++ } ++ return tagged_content; ++} ++ + absl::optional Reader::ReadArrayContent( + const Reader::DataItemHeader& header, + const Config& config, diff --git a/chromium_edits/120.0.6099.200/components/cbor/reader.h.patch b/chromium_edits/120.0.6099.200/components/cbor/reader.h.patch new file mode 100644 index 00000000..fb821165 --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/reader.h.patch @@ -0,0 +1,26 @@ +diff --git a/components/cbor/reader.h b/components/cbor/reader.h +index f0b43a5517528..a57e277a1bc66 100644 +--- a/components/cbor/reader.h ++++ b/components/cbor/reader.h +@@ -130,6 +130,11 @@ class CBOR_EXPORT Reader { + // during decoding will set raise the `UNSUPPORTED_FLOATING_POINT_VALUE` + // error. + bool allow_floating_point = false; ++ ++ // If the parser encounters a TAG element, should it be parsed out and ++ // the tag value saved (true), or should the entire node and its content ++ // be discarded (false) ++ bool parse_tags = false; + }; + + Reader(const Reader&) = delete; +@@ -204,6 +209,9 @@ class CBOR_EXPORT Reader { + absl::optional ReadMapContent(const DataItemHeader& header, + const Config& config, + int max_nesting_level); ++ absl::optional ReadTagContent(const DataItemHeader& header, ++ const Config& config, ++ int max_nesting_level); + absl::optional ReadByte(); + absl::optional> ReadBytes(uint64_t num_bytes); + bool IsKeyInOrder(const Value& new_key, diff --git a/chromium_edits/120.0.6099.200/components/cbor/reader_unittest.cc.patch b/chromium_edits/120.0.6099.200/components/cbor/reader_unittest.cc.patch new file mode 100644 index 00000000..3f657dc3 --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/reader_unittest.cc.patch @@ -0,0 +1,47 @@ +diff --git a/components/cbor/reader_unittest.cc b/components/cbor/reader_unittest.cc +index 83d44a48d6dfa..a6ec5299b3241 100644 +--- a/components/cbor/reader_unittest.cc ++++ b/components/cbor/reader_unittest.cc +@@ -1451,5 +1451,42 @@ TEST(CBORReaderTest, AllowInvalidUTF8) { + EXPECT_FALSE(cbor); + EXPECT_EQ(Reader::DecoderError::INVALID_UTF8, error); + } ++TEST(CBORReaderTest, RejectsTagUnderDefaultConfig) { ++ static const uint8_t kTaggedCbor[] = { ++ 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x71, 0x12, 0x20, 0x69, 0xea, 0x07, ++ 0x40, 0xf9, 0x80, 0x7a, 0x28, 0xf4, 0xd9, 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, 0x07, 0x2c, 0x90, 0x26, 0x6a, 0xb3, 0xe7, ++ 0x9d, 0xf6, 0x3a, 0x36, 0x5b ++ }; ++ Reader::Config config; ++ absl::optional cbor = Reader::Read(kTaggedCbor, config); ++ EXPECT_FALSE(cbor.has_value()); ++} ++TEST(CBORReaderTest, ReadsTagWhenConfiguredToDoSo) { ++ static const uint8_t kTaggedCbor[] = { ++ 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x71, 0x12, 0x20, 0x69, 0xea, 0x07, ++ 0x40, 0xf9, 0x80, 0x7a, 0x28, 0xf4, 0xd9, 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, 0x07, 0x2c, 0x90, 0x26, 0x6a, 0xb3, 0xe7, ++ 0x9d, 0xf6, 0x3a, 0x36, 0x5b ++ }; ++ Reader::Config config; ++ config.parse_tags = true; ++ absl::optional cbor = Reader::Read(kTaggedCbor, config); ++ EXPECT_TRUE(cbor.has_value()); ++ auto& v = cbor.value(); ++ EXPECT_TRUE(v.has_tag()); ++ EXPECT_EQ(v.GetTag(),42UL); ++ EXPECT_TRUE(v.is_bytestring()); ++ EXPECT_EQ(v.type(), Value::Type::BYTE_STRING); ++ auto& bytes = v.GetBytestring(); ++ EXPECT_EQ(bytes.size(), 37UL); ++ EXPECT_EQ(bytes.at(0), 0x00);//identity multibase (e.g. not base-encoded, bytes are themselves) ++ EXPECT_EQ(bytes.at(1), 0x01);//CID version 1 ++ EXPECT_EQ(bytes.at(2), 0x71);//codec = dag-cbor ++ EXPECT_EQ(bytes.at(3), 0x12);//multihash = 18 = sha2-256 ++ EXPECT_EQ(bytes.at(4), 0x20);//hash length = 32 bytes ++ EXPECT_EQ(bytes.at(5), 0x69);//first byte of hash digest ++ EXPECT_EQ(bytes.at(36),0x5b);//last byte of hash digest ++} + + } // namespace cbor diff --git a/chromium_edits/120.0.6099.200/components/cbor/values.cc.patch b/chromium_edits/120.0.6099.200/components/cbor/values.cc.patch new file mode 100644 index 00000000..ddbab2b3 --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/values.cc.patch @@ -0,0 +1,145 @@ +diff --git a/components/cbor/values.cc b/components/cbor/values.cc +index 02498209c820e..34055aef24cfe 100644 +--- a/components/cbor/values.cc ++++ b/components/cbor/values.cc +@@ -66,32 +66,34 @@ Value::Value(Type type) : type_(type) { + NOTREACHED(); + } + +-Value::Value(SimpleValue in_simple) +- : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) { ++Value::Value(SimpleValue in_simple, uint64_t tag) ++ : type_(Type::SIMPLE_VALUE), simple_value_(in_simple), tag_(tag) { + CHECK(static_cast(in_simple) >= 20 && static_cast(in_simple) <= 23); + } + +-Value::Value(bool boolean_value) : type_(Type::SIMPLE_VALUE) { ++Value::Value(bool boolean_value, uint64_t tag) : type_(Type::SIMPLE_VALUE), tag_(tag) { + simple_value_ = boolean_value ? Value::SimpleValue::TRUE_VALUE + : Value::SimpleValue::FALSE_VALUE; + } + +-Value::Value(double float_value) +- : type_(Type::FLOAT_VALUE), float_value_(float_value) {} ++Value::Value(double float_value, uint64_t tag) ++ : type_(Type::FLOAT_VALUE), float_value_(float_value), tag_(tag) {} + +-Value::Value(int integer_value) +- : Value(base::checked_cast(integer_value)) {} ++Value::Value(int integer_value, uint64_t tag) ++ : Value(base::checked_cast(integer_value), tag) {} + +-Value::Value(int64_t integer_value) : integer_value_(integer_value) { ++Value::Value(int64_t integer_value, uint64_t tag) : integer_value_(integer_value), tag_(tag) { + type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE; + } + +-Value::Value(base::span in_bytes) ++Value::Value(base::span in_bytes, uint64_t tag) + : type_(Type::BYTE_STRING), +- bytestring_value_(in_bytes.begin(), in_bytes.end()) {} ++ bytestring_value_(in_bytes.begin(), in_bytes.end()), ++ tag_(tag) ++ {} + +-Value::Value(base::span in_bytes, Type type) +- : type_(type), bytestring_value_(in_bytes.begin(), in_bytes.end()) { ++Value::Value(base::span in_bytes, Type type, uint64_t tag) ++ : type_(type), bytestring_value_(in_bytes.begin(), in_bytes.end()), tag_(tag) { + DCHECK(type_ == Type::BYTE_STRING || type_ == Type::INVALID_UTF8); + } + +@@ -117,7 +119,8 @@ Value::Value(std::string&& in_string, Type type) noexcept : type_(type) { + } + } + +-Value::Value(base::StringPiece in_string, Type type) : type_(type) { ++Value::Value(base::StringPiece in_string, Type type, uint64_t tag) ++: type_(type), tag_(tag) { + switch (type_) { + case Type::STRING: + new (&string_value_) std::string(); +@@ -133,16 +136,18 @@ Value::Value(base::StringPiece in_string, Type type) : type_(type) { + } + } + +-Value::Value(const ArrayValue& in_array) : type_(Type::ARRAY), array_value_() { ++Value::Value(const ArrayValue& in_array, uint64_t tag) ++: type_(Type::ARRAY), array_value_(), tag_(tag) { + array_value_.reserve(in_array.size()); + for (const auto& val : in_array) + array_value_.emplace_back(val.Clone()); + } + +-Value::Value(ArrayValue&& in_array) noexcept +- : type_(Type::ARRAY), array_value_(std::move(in_array)) {} ++Value::Value(ArrayValue&& in_array, uint64_t tag) noexcept ++ : type_(Type::ARRAY), array_value_(std::move(in_array)), tag_(tag) {} + +-Value::Value(const MapValue& in_map) : type_(Type::MAP), map_value_() { ++Value::Value(const MapValue& in_map, uint64_t tag) ++: type_(Type::MAP), map_value_(), tag_(tag) { + map_value_.reserve(in_map.size()); + for (const auto& it : in_map) + map_value_.emplace_hint(map_value_.end(), it.first.Clone(), +@@ -168,31 +173,36 @@ Value Value::Clone() const { + case Type::NONE: + return Value(); + case Type::INVALID_UTF8: +- return Value(bytestring_value_, Type::INVALID_UTF8); ++ return Value(bytestring_value_, Type::INVALID_UTF8, tag_); + case Type::UNSIGNED: + case Type::NEGATIVE: +- return Value(integer_value_); ++ return Value(integer_value_, tag_); + case Type::BYTE_STRING: +- return Value(bytestring_value_); ++ return Value(bytestring_value_, tag_); + case Type::STRING: +- return Value(string_value_); ++ return Value(string_value_, Type::STRING, tag_); + case Type::ARRAY: +- return Value(array_value_); ++ return Value(array_value_, tag_); + case Type::MAP: +- return Value(map_value_); ++ return Value(map_value_, tag_); + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return Value(); + case Type::SIMPLE_VALUE: +- return Value(simple_value_); ++ return Value(simple_value_, tag_); + case Type::FLOAT_VALUE: +- return Value(float_value_); ++ return Value(float_value_, tag_); + } + + NOTREACHED(); + return Value(); + } + ++Value& Value::SetTag(uint64_t tag) noexcept { ++ tag_ = tag; ++ return *this; ++} ++ + Value::SimpleValue Value::GetSimpleValue() const { + CHECK(is_simple()); + return simple_value_; +@@ -258,9 +268,14 @@ const Value::BinaryValue& Value::GetInvalidUTF8() const { + return bytestring_value_; + } + ++uint64_t Value::GetTag() const { ++ CHECK(has_tag()); ++ return tag_; ++} ++ + void Value::InternalMoveConstructFrom(Value&& that) { + type_ = that.type_; +- ++ tag_ = that.tag_; + switch (type_) { + case Type::UNSIGNED: + case Type::NEGATIVE: diff --git a/chromium_edits/120.0.6099.200/components/cbor/values.h.patch b/chromium_edits/120.0.6099.200/components/cbor/values.h.patch new file mode 100644 index 00000000..ca39df01 --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/values.h.patch @@ -0,0 +1,79 @@ +diff --git a/components/cbor/values.h b/components/cbor/values.h +index d81ef5607c55a..10216a8dcdc57 100644 +--- a/components/cbor/values.h ++++ b/components/cbor/values.h +@@ -127,28 +127,29 @@ class CBOR_EXPORT Value { + + explicit Value(Type type); + +- explicit Value(SimpleValue in_simple); +- explicit Value(bool boolean_value); +- explicit Value(double in_float); ++ explicit Value(SimpleValue in_simple, uint64_t tag = NO_TAG); ++ explicit Value(bool boolean_value, uint64_t tag = NO_TAG); ++ explicit Value(double in_float, uint64_t tag = NO_TAG); + +- explicit Value(int integer_value); +- explicit Value(int64_t integer_value); ++ explicit Value(int integer_value, uint64_t tag = NO_TAG); ++ explicit Value(int64_t integer_value, uint64_t tag = NO_TAG); + explicit Value(uint64_t integer_value) = delete; + +- explicit Value(base::span in_bytes); ++ explicit Value(base::span in_bytes, uint64_t tag = NO_TAG); + explicit Value(BinaryValue&& in_bytes) noexcept; + + explicit Value(const char* in_string, Type type = Type::STRING); + explicit Value(std::string&& in_string, Type type = Type::STRING) noexcept; +- explicit Value(base::StringPiece in_string, Type type = Type::STRING); ++ explicit Value(base::StringPiece in_string, Type type = Type::STRING, uint64_t tag = NO_TAG); + +- explicit Value(const ArrayValue& in_array); +- explicit Value(ArrayValue&& in_array) noexcept; ++ explicit Value(const ArrayValue& in_array, uint64_t tag = NO_TAG); ++ explicit Value(ArrayValue&& in_array, uint64_t tag = NO_TAG) noexcept; + +- explicit Value(const MapValue& in_map); ++ explicit Value(const MapValue& in_map, uint64_t tag = NO_TAG); + explicit Value(MapValue&& in_map) noexcept; + + Value& operator=(Value&& that) noexcept; ++ Value& SetTag(uint64_t) noexcept; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; +@@ -179,6 +180,7 @@ class CBOR_EXPORT Value { + bool is_string() const { return type() == Type::STRING; } + bool is_array() const { return type() == Type::ARRAY; } + bool is_map() const { return type() == Type::MAP; } ++ bool has_tag() const { return tag_ != NO_TAG; } + + // These will all fatally assert if the type doesn't match. + SimpleValue GetSimpleValue() const; +@@ -194,12 +196,13 @@ class CBOR_EXPORT Value { + const ArrayValue& GetArray() const; + const MapValue& GetMap() const; + const BinaryValue& GetInvalidUTF8() const; ++ uint64_t GetTag() const; + + private: + friend class Reader; + // This constructor allows INVALID_UTF8 values to be created, which only + // |Reader| and InvalidUTF8StringValueForTesting() may do. +- Value(base::span in_bytes, Type type); ++ Value(base::span in_bytes, Type type, uint64_t tag = NO_TAG); + + Type type_; + +@@ -213,6 +216,11 @@ class CBOR_EXPORT Value { + MapValue map_value_; + }; + ++ //This value specified as Invalid, ++ // used here to represent absence of TAG ++ constexpr static uint64_t NO_TAG = 0xFFFF; ++ uint64_t tag_ = NO_TAG; ++ + void InternalMoveConstructFrom(Value&& that); + void InternalCleanup(); + }; diff --git a/chromium_edits/120.0.6099.200/components/cbor/writer.cc.patch b/chromium_edits/120.0.6099.200/components/cbor/writer.cc.patch new file mode 100644 index 00000000..21fe28ce --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/writer.cc.patch @@ -0,0 +1,14 @@ +diff --git a/components/cbor/writer.cc b/components/cbor/writer.cc +index bb22754d36a07..aae4027836377 100644 +--- a/components/cbor/writer.cc ++++ b/components/cbor/writer.cc +@@ -47,6 +47,9 @@ bool Writer::EncodeCBOR(const Value& node, + if (max_nesting_level < 0) + return false; + ++ if (node.has_tag()) { ++ StartItem(Value::Type::TAG, node.GetTag()); ++ } + switch (node.type()) { + case Value::Type::NONE: { + StartItem(Value::Type::BYTE_STRING, 0); diff --git a/chromium_edits/120.0.6099.200/components/cbor/writer_unittest.cc.patch b/chromium_edits/120.0.6099.200/components/cbor/writer_unittest.cc.patch new file mode 100644 index 00000000..240fee83 --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/cbor/writer_unittest.cc.patch @@ -0,0 +1,36 @@ +diff --git a/components/cbor/writer_unittest.cc b/components/cbor/writer_unittest.cc +index e3bffe20734bc..0ed569ae164a0 100644 +--- a/components/cbor/writer_unittest.cc ++++ b/components/cbor/writer_unittest.cc +@@ -522,4 +522,31 @@ TEST(CBORWriterTest, OverlyNestedCBOR) { + EXPECT_FALSE(Writer::Write(Value(map), 4).has_value()); + } + ++TEST(CBORWriterTest, CanWriteTag) { ++ std::array content{ ++ 0x00, 0x01, 0x71, 0x12, 0x20, ++ 0x69, 0xea, 0x07, 0x40, 0xf9, ++ 0x80, 0x7a, 0x28, 0xf4, 0xd9, ++ 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, ++ 0x07, 0x2c, 0x90, 0x26, 0x6a, ++ 0xb3, 0xe7, 0x9d, 0xf6, 0x3a, ++ 0x36, 0x5b ++ }; ++ Value to_write(content); ++ to_write.SetTag(42); ++ auto result = Writer::Write(to_write); ++ EXPECT_TRUE(result.has_value()); ++ auto& bytes = result.value(); ++ EXPECT_EQ(bytes.size(), 41UL); ++ EXPECT_EQ(bytes.at(0), 0xd8); ++ EXPECT_EQ(bytes.at(1), 0x2a); ++ EXPECT_EQ(bytes.at(2), 0x58); ++ EXPECT_EQ(bytes.at(3), 0x25); ++ for (auto i = 0UL; i < content.size(); ++i) { ++ ASSERT_LT(i + 4UL, bytes.size()); ++ ASSERT_EQ(content.at(i), bytes.at(i+4UL)); ++ } ++} ++ + } // namespace cbor diff --git a/chromium_edits/120.0.6099.200/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch b/chromium_edits/120.0.6099.200/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch new file mode 100644 index 00000000..891b53df --- /dev/null +++ b/chromium_edits/120.0.6099.200/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch @@ -0,0 +1,13 @@ +diff --git a/components/open_from_clipboard/clipboard_recent_content_generic.cc b/components/open_from_clipboard/clipboard_recent_content_generic.cc +index 4dcafecbc66c6..d205209c08162 100644 +--- a/components/open_from_clipboard/clipboard_recent_content_generic.cc ++++ b/components/open_from_clipboard/clipboard_recent_content_generic.cc +@@ -20,7 +20,7 @@ + namespace { + // Schemes appropriate for suggestion by ClipboardRecentContent. + const char* kAuthorizedSchemes[] = { +- url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme, ++ url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme, "ipfs", "ipns" + // TODO(mpearson): add support for chrome:// URLs. Right now the scheme + // for that lives in content and is accessible via + // GetEmbedderRepresentationOfAboutScheme() or content::kChromeUIScheme diff --git a/chromium_edits/120.0.6099.200/net/dns/dns_config_service_linux.cc.patch b/chromium_edits/120.0.6099.200/net/dns/dns_config_service_linux.cc.patch new file mode 100644 index 00000000..a5e9863f --- /dev/null +++ b/chromium_edits/120.0.6099.200/net/dns/dns_config_service_linux.cc.patch @@ -0,0 +1,18 @@ +diff --git a/net/dns/dns_config_service_linux.cc b/net/dns/dns_config_service_linux.cc +index 5273da5190277..12b28b86a4c00 100644 +--- a/net/dns/dns_config_service_linux.cc ++++ b/net/dns/dns_config_service_linux.cc +@@ -272,11 +272,11 @@ bool IsNsswitchConfigCompatible( + // Ignore any entries after `kDns` because Chrome will fallback to the + // system resolver if a result was not found in DNS. + return true; +- ++ case NsswitchReader::Service::kResolve: ++ break; + case NsswitchReader::Service::kMdns: + case NsswitchReader::Service::kMdns4: + case NsswitchReader::Service::kMdns6: +- case NsswitchReader::Service::kResolve: + case NsswitchReader::Service::kNis: + RecordIncompatibleNsswitchReason( + IncompatibleNsswitchReason::kIncompatibleService, diff --git a/chromium_edits/120.0.6099.200/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch b/chromium_edits/120.0.6099.200/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch new file mode 100644 index 00000000..119d72b2 --- /dev/null +++ b/chromium_edits/120.0.6099.200/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc +index 4eadf46ea0c24..d62fc7fb14e01 100644 +--- a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc ++++ b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc +@@ -67,7 +67,7 @@ class URLSchemesRegistry final { + // is considered secure. Additional checks are performed to ensure that + // other http pages are filtered out. + service_worker_schemes({"http", "https"}), +- fetch_api_schemes({"http", "https"}), ++ fetch_api_schemes({"http", "https", "ipfs", "ipns"}), + allowed_in_referrer_schemes({"http", "https"}) { + for (auto& scheme : url::GetCorsEnabledSchemes()) + cors_enabled_schemes.insert(scheme.c_str()); diff --git a/chromium_edits/120.0.6099.200/url/BUILD.gn.patch b/chromium_edits/120.0.6099.200/url/BUILD.gn.patch new file mode 100644 index 00000000..63fb8f8b --- /dev/null +++ b/chromium_edits/120.0.6099.200/url/BUILD.gn.patch @@ -0,0 +1,32 @@ +diff --git a/url/BUILD.gn b/url/BUILD.gn +index c525c166979d6..ce2b1ae43c0a7 100644 +--- a/url/BUILD.gn ++++ b/url/BUILD.gn +@@ -5,6 +5,7 @@ + import("//build/buildflag_header.gni") + import("//testing/libfuzzer/fuzzer_test.gni") + import("//testing/test.gni") ++import("//third_party/ipfs_client/args.gni") + import("features.gni") + + import("//build/config/cronet/config.gni") +@@ -67,6 +68,7 @@ component("url") { + public_deps = [ + "//base", + "//build:robolectric_buildflags", ++ "//third_party/ipfs_client:ipfs_buildflags", + ] + + configs += [ "//build/config/compiler:wexit_time_destructors" ] +@@ -89,6 +91,11 @@ component("url") { + public_configs = [ "//third_party/jdk" ] + } + ++ if (enable_ipfs) { ++ sources += [ "url_canon_ipfs.cc" ] ++ deps += [ "//third_party/ipfs_client:ipfs_client" ] ++ } ++ + if (is_win) { + # Don't conflict with Windows' "url.dll". + output_name = "url_lib" diff --git a/chromium_edits/120.0.6099.200/url/url_canon.h.patch b/chromium_edits/120.0.6099.200/url/url_canon.h.patch new file mode 100644 index 00000000..24ae1ba4 --- /dev/null +++ b/chromium_edits/120.0.6099.200/url/url_canon.h.patch @@ -0,0 +1,28 @@ +diff --git a/url/url_canon.h b/url/url_canon.h +index d3a7fabf09fa8..06db17242248f 100644 +--- a/url/url_canon.h ++++ b/url/url_canon.h +@@ -697,6 +697,23 @@ bool CanonicalizeMailtoURL(const char16_t* spec, + CanonOutput* output, + Parsed* new_parsed); + ++COMPONENT_EXPORT(URL) ++bool CanonicalizeIpfsURL(const char* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed); ++COMPONENT_EXPORT(URL) ++bool CanonicalizeIpfsURL(const char16_t* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed); ++ + // Part replacer -------------------------------------------------------------- + + // Internal structure used for storing separate strings for each component. diff --git a/chromium_edits/120.0.6099.200/url/url_canon_ipfs.cc b/chromium_edits/120.0.6099.200/url/url_canon_ipfs.cc new file mode 100644 index 00000000..33910614 --- /dev/null +++ b/chromium_edits/120.0.6099.200/url/url_canon_ipfs.cc @@ -0,0 +1,56 @@ +#include "url_canon_internal.h" + +#include +#include + +#include + +bool url::CanonicalizeIpfsURL(const char* spec, + int spec_len, + const Parsed& parsed, + SchemeType scheme_type, + CharsetConverter* charset_converter, + CanonOutput* output, + Parsed* output_parsed) { + if ( spec_len < 1 || !spec ) { + return false; + } + if ( parsed.host.len < 1 ) { + return false; + } + std::string_view cid_str{ spec + parsed.host.begin, static_cast(parsed.host.len) }; + auto cid = ipfs::Cid(cid_str); + if ( !cid.valid() ) { + cid = ipfs::id_cid::forText( std::string{cid_str} + " is not a valid CID." ); + } + auto as_str = cid.to_string(); + if ( as_str.empty() ) { + return false; + } + std::string stdurl{ spec, static_cast(parsed.host.begin) }; + stdurl.append( as_str ); + stdurl.append( spec + parsed.host.end(), spec_len - parsed.host.end() ); + spec = stdurl.data(); + spec_len = static_cast(stdurl.size()); + Parsed parsed_input; + ParseStandardURL(spec, spec_len, &parsed_input); + return CanonicalizeStandardURL( + spec, + spec_len, + parsed_input, + scheme_type, + charset_converter, + output, output_parsed + ); +} +bool url::CanonicalizeIpfsURL(const char16_t* spec, + int spec_len, + const Parsed& parsed, + SchemeType scheme_type, + CharsetConverter* query_converter, + CanonOutput* output, + Parsed* new_parsed) { + RawCanonOutput<2048> as8; + ConvertUTF16ToUTF8(spec, spec_len, &as8); + return CanonicalizeIpfsURL(as8.data(), as8.length(), parsed, scheme_type, query_converter, output, new_parsed); +} diff --git a/chromium_edits/120.0.6099.200/url/url_util.cc.patch b/chromium_edits/120.0.6099.200/url/url_util.cc.patch new file mode 100644 index 00000000..0332e847 --- /dev/null +++ b/chromium_edits/120.0.6099.200/url/url_util.cc.patch @@ -0,0 +1,17 @@ +diff --git a/url/url_util.cc b/url/url_util.cc +index 9258cfcfada47..daf10e4c3b741 100644 +--- a/url/url_util.cc ++++ b/url/url_util.cc +@@ -277,6 +277,12 @@ bool DoCanonicalize(const CHAR* spec, + charset_converter, output, + output_parsed); + ++ } else if (DoCompareSchemeComponent(spec, scheme, "ipfs")) { ++ // Switch multibase away from case-sensitive ones before continuing canonicalization. ++ ParseStandardURL(spec, spec_len, &parsed_input); ++ success = CanonicalizeIpfsURL(spec, spec_len, parsed_input, scheme_type, ++ charset_converter, output, output_parsed); ++ + } else if (DoIsStandard(spec, scheme, &scheme_type)) { + // All "normal" URLs. + ParseStandardURL(spec, spec_len, &parsed_input); diff --git a/cmake/patch.py b/cmake/patch.py index 2bf78f3f..4d98c109 100755 --- a/cmake/patch.py +++ b/cmake/patch.py @@ -5,7 +5,7 @@ from os import listdir, makedirs, remove from os.path import exists, dirname, isdir, isfile, join, realpath, relpath, splitext from shutil import copyfile, rmtree -from subprocess import call, check_call, check_output +from subprocess import call, check_call, check_output, DEVNULL from sys import argv, executable, platform, stderr from time import ctime from verbose import verbose @@ -48,6 +48,7 @@ class Result(Enum): RawOutput = auto() OrDie = auto() ExitCode = auto() + ExitCodeOnly = auto() StrippedOutput = Output class Patcher: @@ -147,7 +148,7 @@ def apply(self): def check_patch(self, patch_path: str, relative: str, target_path: str): - if 0 == self.git(['apply', '--check', '--reverse', '--verbose', patch_path], Result.ExitCode): + if 0 == self.git(['apply', '--check', '--reverse', '--verbose', patch_path], Result.ExitCodeOnly): verbose(patch_path, 'already applied.') return src = splitext(relative)[0] @@ -159,7 +160,7 @@ def check_patch(self, patch_path: str, relative: str, target_path: str): with open(join(self.csrc,src)) as target_file: text = target_file.read() if 'ipfs' in text: - verbose("Patch file", patch_path, 'may have already been applied.') + print("Patch file", patch_path, 'may have already been applied, or otherwise hand-edited. Ignoring.') else: print("Failed to patch", src, '( at', join(self.csrc,src), ') with', patch_path) exit(8) @@ -176,6 +177,8 @@ def git(self, args: list[str], result: Result) -> str: check_call(a) case Result.ExitCode: return call(a) + case Result.ExitCodeOnly: + return call(a, stdout=DEVNULL, stderr=DEVNULL) case _: raise RuntimeError('result type not handled') @@ -255,7 +258,7 @@ def electron_version(self, branch='main'): def unavailable(self): avail = list(map(as_int, self.available())) version_set = {} - fudge = 59891 + fudge = 59893 def check(version, version_set, s): i = as_int(version) by = (fudge,0) @@ -294,10 +297,10 @@ def out_of_date(self, p): with open(file_path) as f: lines = f.readlines() if not Patcher.has_file_line(lines, 'chrome/browser/flag-metadata.json', '+ "name": "enable-ipfs",'): - print(p, 'does not have enable-ipfs in flag-metadata.json', file_path, file=sys.stderr) + verbose(p, 'does not have enable-ipfs in flag-metadata.json', file_path, file=sys.stderr) return True if not Patcher.has_file_line(lines, 'chrome/browser/chrome_content_browser_client.cc', '+ main_parts->AddParts(std::make_unique());'): - print(p, 'does not have enable-ipfs in flag-metadata.json', file_path, file=sys.stderr) + verbose(p, 'does not have enable-ipfs in flag-metadata.json', file_path, file=sys.stderr) return True return False @@ -368,6 +371,6 @@ def list_ood(self, to_check: list[str], sense: bool): if pr.out_of_date(pch): exit(9) else: - pr.git(['add', line[3:]]) + pr.git(['add', line[3:]], Result.OrDie) else: Patcher(*argv[1:]).create_patch_file() diff --git a/component/cache_requestor.cc b/component/cache_requestor.cc index ce446b60..733f5c0b 100644 --- a/component/cache_requestor.cc +++ b/component/cache_requestor.cc @@ -20,24 +20,24 @@ Self::CacheRequestor(InterRequestState& state, base::FilePath base) Start(); } void Self::Start() { - if (pending_) { + if (startup_pending_) { return; } auto result = dc::CreateCacheBackend( net::CacheType::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, {}, path_, 0, - dc::ResetHandling::kNeverReset, - // dc::ResetHandling::kResetOnError, - nullptr, base::BindOnce(&Self::Assign, base::Unretained(this))); + // dc::ResetHandling::kNeverReset, + dc::ResetHandling::kResetOnError, nullptr, + base::BindOnce(&Self::Assign, base::Unretained(this))); LOG(INFO) << "Start(" << result.net_error << ')' << result.net_error; - pending_ = result.net_error == net::ERR_IO_PENDING; - if (!pending_) { + startup_pending_ = result.net_error == net::ERR_IO_PENDING; + if (!startup_pending_) { Assign(std::move(result)); } } Self::~CacheRequestor() noexcept = default; void Self::Assign(dc::BackendResult res) { - pending_ = false; + startup_pending_ = false; if (res.net_error == net::OK) { LOG(INFO) << "Initialized disk cache"; cache_.swap(res.backend); @@ -47,17 +47,17 @@ void Self::Assign(dc::BackendResult res) { } } auto Self::handle(RequestPtr req) -> HandleOutcome { - if (pending_) { + if (startup_pending_) { return HandleOutcome::NOT_HANDLED; } Task task; - task.key = req->main_param; + task.key = req->Key(); task.request = req; StartFetch(task, net::MAXIMUM_PRIORITY); return HandleOutcome::PENDING; } void Self::StartFetch(Task& task, net::RequestPriority priority) { - if (pending_) { + if (startup_pending_) { Start(); Miss(task); return; @@ -70,10 +70,11 @@ void Self::StartFetch(Task& task, net::RequestPriority priority) { } void Self::Miss(Task& task) { if (task.request) { - VLOG(2) << "Cache miss on " << task.request->debug_string(); + VLOG(1) << "Cache miss on '" << task.request->Key() << "' for " + << task.request->debug_string(); auto req = task.request; task.request->Hook([this, req](std::string_view bytes) { - Store(req->main_param, "TODO", std::string{bytes}); + Store(req->Key(), "TODO", std::string{bytes}); }); forward(req); } @@ -91,7 +92,6 @@ std::shared_ptr GetEntry(dc::EntryResult& result) { } // namespace void Self::OnOpen(Task task, dc::EntryResult res) { - VLOG(2) << "OnOpen(" << res.net_error() << ")"; if (res.net_error() != net::OK) { VLOG(2) << "Failed to find " << task.key << " in " << name(); Miss(task); @@ -144,14 +144,14 @@ void Self::OnBodyRead(Task task, int code) { } } } -void Self::Store(std::string cid, std::string headers, std::string body) { - VLOG(1) << "Store(" << name() << ',' << cid << ',' << headers.size() << ',' - << body.size() << ')'; +void Self::Store(std::string key, std::string headers, std::string body) { + LOG(INFO) << "Store(" << name() << ',' << key << ',' << headers.size() << ',' + << body.size() << ')'; auto bound = base::BindOnce(&Self::OnEntryCreated, base::Unretained(this), - cid, headers, body); - auto res = cache_->OpenOrCreateEntry(cid, net::LOW, std::move(bound)); + key, headers, body); + auto res = cache_->OpenOrCreateEntry(key, net::LOW, std::move(bound)); if (res.net_error() != net::ERR_IO_PENDING) { - OnEntryCreated(cid, headers, body, std::move(res)); + OnEntryCreated(key, headers, body, std::move(res)); } } void Self::OnEntryCreated(std::string cid, @@ -196,20 +196,11 @@ void Self::OnHeaderWritten(scoped_refptr buf, void Self::Task::SetHeaders(std::string_view source) { auto heads = base::MakeRefCounted(header); - DCHECK(heads); - std::string value{"blockcache-"}; - value.append(key); - value.append(";desc=\"Load from local browser block cache\";dur="); - auto dur = base::TimeTicks::Now() - start; - value.append(std::to_string(dur.InMillisecondsRoundedUp())); - heads->SetHeader("Server-Timing", value); - VLOG(2) << "From cache: Server-Timing: " << value << "; Block-Cache-" << key - << ": " << source; - heads->SetHeader("Block-Cache-" + key, {source.data(), source.size()}); + // TODO header = heads->raw_headers(); } void Self::Expire(std::string const& key) { - if (cache_ && !pending_) { + if (cache_ && !startup_pending_) { cache_->DoomEntry(key, net::RequestPriority::LOWEST, base::DoNothing()); } } diff --git a/component/cache_requestor.h b/component/cache_requestor.h index b8c31d37..5262bd05 100644 --- a/component/cache_requestor.h +++ b/component/cache_requestor.h @@ -22,7 +22,7 @@ class CacheRequestor : public gw::Requestor { public: CacheRequestor(InterRequestState&, base::FilePath); ~CacheRequestor() noexcept override; - void Store(std::string cid, std::string headers, std::string body); + void Store(std::string key, std::string headers, std::string body); void Expire(std::string const& key); std::string_view name() const override; @@ -44,7 +44,7 @@ class CacheRequestor : public gw::Requestor { }; raw_ref state_; std::unique_ptr cache_; - bool pending_ = false; + bool startup_pending_ = false; base::FilePath path_; void Start(); diff --git a/component/chromium_ipfs_context.cc b/component/chromium_ipfs_context.cc index 7ef6ad8f..d4b180a9 100644 --- a/component/chromium_ipfs_context.cc +++ b/component/chromium_ipfs_context.cc @@ -36,8 +36,6 @@ std::string Self::MimeType(std::string extension, std::string const& url) const { std::string result; auto fp_ext = base::FilePath::FromUTF8Unsafe(extension).value(); - VLOG(2) << "extension=" << extension << "content.size()=" << content.size() - << "(as-if) url for mime type:" << url; if (extension.empty()) { result.clear(); } else if (net::GetWellKnownMimeTypeFromExtension(fp_ext, &result)) { @@ -73,7 +71,7 @@ void Self::SendDnsTextRequest(std::string host, } auto don_wrap = [don, this, host]() { don(); - LOG(INFO) << "Finished resolving " << host << " via DNSLink"; + VLOG(2) << "Finished resolving " << host << " via DNSLink"; dns_reqs_.erase(host); }; auto* nc = state_->network_context(); diff --git a/component/crypto_api.cc b/component/crypto_api.cc index 250c9024..205adaba 100644 --- a/component/crypto_api.cc +++ b/component/crypto_api.cc @@ -50,13 +50,9 @@ bool cpto::VerifySignature(ipfs::ContextApi::SigningKeyType key_type, LOG(ERROR) << "EVP_DigestVerifyInit failed"; return false; } - // auto* prefix = reinterpret_cast( - // "\x69\x70\x6e\x73\x2d\x73\x69\x67\x6e\x61\x74\x75\x72\x65\x3a"); - // std::basic_string to_verify = prefix; - // to_verify.append(data_p, data.size()); auto result = EVP_DigestVerify(ctx.get(), sig_p, signature.size(), data_p, data.size()); // to_verify.data(), to_verify.size()); - LOG(INFO) << "EVP_DigestVerify returned " << result; + VLOG(1) << "EVP_DigestVerify returned " << result; return result == 1; } diff --git a/component/dns_txt_request.cc b/component/dns_txt_request.cc index c7e8e667..45f3d823 100644 --- a/component/dns_txt_request.cc +++ b/component/dns_txt_request.cc @@ -18,7 +18,6 @@ Self::DnsTxtRequest(std::string host, params->cache_usage = moj::ResolveHostParameters_CacheUsage::STALE_ALLOWED; params->secure_dns_policy = moj::SecureDnsPolicy::ALLOW; params->purpose = moj::ResolveHostParameters::Purpose::kUnspecified; - LOG(INFO) << "Querying DNS for TXT records on " << host; auto hrh = moj::HostResolverHost::NewHostPortPair({host, 0}); auto nak = net::NetworkAnonymizationKey::CreateTransient(); network_context->ResolveHost(std::move(hrh), nak, std::move(params), @@ -34,6 +33,6 @@ void Self::OnComplete(int32_t result, const ::net::ResolveErrorInfo&, const absl::optional<::net::AddressList>&, const absl::optional&) { - LOG(INFO) << "DNS Results done with code: " << result; + VLOG(1) << "DNS Results done with code: " << result; completion_callback_(); } diff --git a/component/inter_request_state.cc b/component/inter_request_state.cc index d24591e0..b05a0aee 100644 --- a/component/inter_request_state.cc +++ b/component/inter_request_state.cc @@ -33,7 +33,6 @@ auto Self::FromBrowserContext(content::BrowserContext* context) } base::SupportsUserData::Data* existing = context->GetUserData(user_data_key); if (existing) { - VLOG(2) << "Re-using existing IPFS state."; return *static_cast(existing); } else { LOG(ERROR) << "Browser context has no IPFS state! It must be set earlier!"; @@ -45,9 +44,9 @@ std::shared_ptr Self::api() { return api_; } auto Self::cache() -> std::shared_ptr& { - // if (!cache_) { - // cache_ = std::make_shared(*this, disk_path_); - // } + if (!cache_) { + cache_ = std::make_shared(*this, disk_path_); + } return cache_; } auto Self::orchestrator() -> Orchestrator& { diff --git a/component/interceptor.cc b/component/interceptor.cc index 91493687..267cf03c 100644 --- a/component/interceptor.cc +++ b/component/interceptor.cc @@ -20,11 +20,10 @@ void Interceptor::MaybeCreateLoader(network::ResourceRequest const& req, LoaderCallback loader_callback) { auto& state = InterRequestState::FromBrowserContext(context); state.network_context(network_context_); - LOG(INFO) << "MaybeCreateLoader " << req.url.spec(); if (req.url.SchemeIs("ipfs") || req.url.SchemeIs("ipns")) { auto hdr_str = req.headers.ToString(); std::replace(hdr_str.begin(), hdr_str.end(), '\r', ' '); - VLOG(1) << req.url.spec() << " getting intercepted! Headers: \n" << hdr_str; + VLOG(2) << req.url.spec() << " getting intercepted! Headers: \n" << hdr_str; DCHECK(context); auto loader = std::make_shared(*loader_factory_, state); diff --git a/component/ipfs_url_loader.cc b/component/ipfs_url_loader.cc index 5b98b08b..0ad988b0 100644 --- a/component/ipfs_url_loader.cc +++ b/component/ipfs_url_loader.cc @@ -62,7 +62,6 @@ void ipfs::IpfsUrlLoader::StartRequest( mojo::PendingRemote client) { DCHECK(!me->receiver_.is_bound()); DCHECK(!me->client_.is_bound()); - VLOG(1) << "StartRequest(" << resource_request.url.spec() << ")"; me->receiver_.Bind(std::move(receiver)); me->client_.Bind(std::move(client)); if (me->original_url_.empty()) { @@ -74,11 +73,11 @@ void ipfs::IpfsUrlLoader::StartRequest( auto cid_str = resource_request.url.host(); auto path = resource_request.url.path(); auto abs_path = "/" + ns + "/" + cid_str + path; - VLOG(1) << resource_request.url.spec() << " -> " << abs_path; + VLOG(2) << resource_request.url.spec() << " -> " << abs_path; me->root_ = cid_str; me->api_->SetLoaderFactory(*(me->lower_loader_factory_)); auto whendone = [me](IpfsRequest const& req, ipfs::Response const& res) { - VLOG(1) << "whendone(" << req.path().to_string() << ',' << res.status_ + VLOG(2) << "whendone(" << req.path().to_string() << ',' << res.status_ << ',' << res.body_.size() << "B mime=" << res.mime_ << ')'; if (!res.body_.empty()) { me->ReceiveBlockBytes(res.body_); @@ -131,7 +130,7 @@ void ipfs::IpfsUrlLoader::BlocksComplete(std::string mime_type) { VLOG(1) << "Calling WriteData(" << byte_count << ")"; pipe_prod_->WriteData(partial_block_.data(), &byte_count, MOJO_BEGIN_WRITE_DATA_FLAG_ALL_OR_NONE); - VLOG(1) << "Called WriteData(" << byte_count << ")"; + VLOG(2) << "Called WriteData(" << byte_count << ")"; head->content_length = byte_count; head->headers = net::HttpResponseHeaders::TryToCreate("access-control-allow-origin: *"); @@ -159,7 +158,7 @@ void ipfs::IpfsUrlLoader::BlocksComplete(std::string mime_type) { << head->mime_type << " and status line '" << status_line << "' @location '" << resp_loc_ << "'"; } else { - VLOG(1) << "Sending response for " << original_url_ << " with mime type " + VLOG(2) << "Sending response for " << original_url_ << " with mime type " << head->mime_type << " and status line '" << status_line << "' with no location header."; } diff --git a/component/patches/120.0.6099.200.patch b/component/patches/120.0.6099.200.patch new file mode 100644 index 00000000..9a5dc62a --- /dev/null +++ b/component/patches/120.0.6099.200.patch @@ -0,0 +1,908 @@ +diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn +index 44d3b5e543101..35bbe5da7daf8 100644 +--- a/chrome/browser/BUILD.gn ++++ b/chrome/browser/BUILD.gn +@@ -40,6 +40,7 @@ import("//rlz/buildflags/buildflags.gni") + import("//sandbox/features.gni") + import("//testing/libfuzzer/fuzzer_test.gni") + import("//third_party/blink/public/public_features.gni") ++import("//third_party/ipfs_client/args.gni") + import("//third_party/protobuf/proto_library.gni") + import("//third_party/webrtc/webrtc.gni") + import("//third_party/widevine/cdm/widevine.gni") +@@ -2660,6 +2661,14 @@ static_library("browser") { + ] + } + ++ if (enable_ipfs) { ++ sources += [ ++ "ipfs_extra_parts.cc", ++ "ipfs_extra_parts.h", ++ ] ++ deps += [ "//components/ipfs" ] ++ } ++ + if (is_chromeos_ash) { + deps += [ "//chrome/browser/screen_ai:screen_ai_dlc_installer" ] + } +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +index 8736a91998f6b..da556109dcbb1 100644 +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -213,6 +213,7 @@ + #include "third_party/blink/public/common/features_generated.h" + #include "third_party/blink/public/common/forcedark/forcedark_switches.h" + #include "third_party/blink/public/common/switches.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + #include "ui/accessibility/accessibility_features.h" + #include "ui/accessibility/accessibility_switches.h" + #include "ui/base/ui_base_features.h" +@@ -314,6 +315,10 @@ + #include "extensions/common/switches.h" + #endif // BUILDFLAG(ENABLE_EXTENSIONS) + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#endif ++ + #if BUILDFLAG(ENABLE_PDF) + #include "pdf/pdf_features.h" + #endif +@@ -9922,6 +9927,14 @@ const FeatureEntry kFeatureEntries[] = { + flag_descriptions::kOmitCorsClientCertDescription, kOsAll, + FEATURE_VALUE_TYPE(network::features::kOmitCorsClientCert)}, + ++#if BUILDFLAG(ENABLE_IPFS) ++ {"enable-ipfs", ++ flag_descriptions::kEnableIpfsName, ++ flag_descriptions::kEnableIpfsDescription, ++ kOsMac | kOsWin | kOsLinux,//TODO: These are the only variants currently getting built, but that is not likely to remain the case ++ FEATURE_VALUE_TYPE(ipfs::kEnableIpfs)}, ++#endif ++ + {"use-idna2008-non-transitional", + flag_descriptions::kUseIDNA2008NonTransitionalName, + flag_descriptions::kUseIDNA2008NonTransitionalDescription, kOsAll, +diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc +index 4c88614c68c25..f8bb12a3b0c2e 100644 +--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc ++++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc +@@ -10,6 +10,8 @@ + #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" + #include "chrome/browser/external_protocol/external_protocol_handler.h" + #include "chrome/browser/profiles/profile.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" ++ + #if BUILDFLAG(IS_ANDROID) + #include "chrome/browser/profiles/profile_android.h" + #endif +@@ -18,6 +20,9 @@ + #include "chrome/browser/ui/android/omnibox/jni_headers/ChromeAutocompleteSchemeClassifier_jni.h" + #endif + #include "components/custom_handlers/protocol_handler_registry.h" ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#endif + #include "content/public/common/url_constants.h" + #include "url/url_util.h" + +@@ -55,12 +60,20 @@ ChromeAutocompleteSchemeClassifier::GetInputTypeForScheme( + if (scheme.empty()) { + return metrics::OmniboxInputType::EMPTY; + } +- if (base::IsStringASCII(scheme) && +- (ProfileIOData::IsHandledProtocol(scheme) || +- base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) || +- base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) || +- base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme))) { +- return metrics::OmniboxInputType::URL; ++ if (base::IsStringASCII(scheme)) { ++ if (ProfileIOData::IsHandledProtocol(scheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme)) { ++ return metrics::OmniboxInputType::URL; ++ } ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs) && ++ (base::EqualsCaseInsensitiveASCII(scheme, "ipfs") || base::EqualsCaseInsensitiveASCII(scheme, "ipns")) ++ ) { ++ return metrics::OmniboxInputType::URL; ++ } ++#endif + } + + // Also check for schemes registered via registerProtocolHandler(), which +diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc +index d9c675c8aca73..8fbea741919d8 100644 +--- a/chrome/browser/chrome_content_browser_client.cc ++++ b/chrome/browser/chrome_content_browser_client.cc +@@ -364,6 +364,7 @@ + #include "third_party/blink/public/common/switches.h" + #include "third_party/blink/public/mojom/browsing_topics/browsing_topics.mojom.h" + #include "third_party/blink/public/public_buildflags.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + #include "third_party/widevine/cdm/buildflags.h" + #include "ui/base/clipboard/clipboard_format_type.h" + #include "ui/base/l10n/l10n_util.h" +@@ -487,6 +488,13 @@ + #include "chrome/browser/fuchsia/chrome_browser_main_parts_fuchsia.h" + #endif + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "chrome/browser/ipfs_extra_parts.h" ++#include "components/ipfs/interceptor.h" ++#include "components/ipfs/ipfs_features.h" ++#include "components/ipfs/url_loader_factory.h" ++#endif ++ + #if BUILDFLAG(IS_CHROMEOS) + #include "base/debug/leak_annotations.h" + #include "chrome/browser/apps/intent_helper/chromeos_disabled_apps_throttle.h" +@@ -1816,6 +1824,11 @@ ChromeContentBrowserClient::CreateBrowserMainParts(bool is_integration_test) { + main_parts->AddParts( + std::make_unique()); + ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ main_parts->AddParts(std::make_unique()); ++ } ++#endif + return main_parts; + } + +@@ -6180,12 +6193,25 @@ void ChromeContentBrowserClient:: + const absl::optional& request_initiator_origin, + NonNetworkURLLoaderFactoryMap* factories) { + #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ +- !BUILDFLAG(IS_ANDROID) ++ !BUILDFLAG(IS_ANDROID) || BUILDFLAG(ENABLE_IPFS) + content::RenderFrameHost* frame_host = + RenderFrameHost::FromID(render_process_id, render_frame_id); + WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host); + #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ + // !BUILDFLAG(IS_ANDROID) ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ network::mojom::URLLoaderFactory* default_factory = g_browser_process->system_network_context_manager()->GetURLLoaderFactory(); ++ auto* context = web_contents->GetBrowserContext(); ++ ipfs::IpfsURLLoaderFactory::Create( ++ factories, ++ context, ++ default_factory, ++ GetSystemNetworkContext(), ++ Profile::FromBrowserContext(context)->GetPrefs() ++ ); ++ } ++#endif // BUILDFLAG(ENABLE_IPFS) + + #if BUILDFLAG(IS_CHROMEOS_ASH) + if (web_contents) { +@@ -6327,6 +6353,11 @@ ChromeContentBrowserClient::WillCreateURLLoaderRequestInterceptors( + scoped_refptr navigation_response_task_runner) { + std::vector> + interceptors; ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ interceptors.push_back(std::make_unique(g_browser_process->system_network_context_manager()->GetURLLoaderFactory(), GetSystemNetworkContext())); ++ } ++#endif + #if BUILDFLAG(ENABLE_OFFLINE_PAGES) + interceptors.push_back( + std::make_unique( +diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json +index 400505f9d64e6..320b730d894c6 100644 +--- a/chrome/browser/flag-metadata.json ++++ b/chrome/browser/flag-metadata.json +@@ -2868,6 +2868,11 @@ + "owners": [ "hanxi@chromium.org", "wychen@chromium.org" ], + "expiry_milestone": 130 + }, ++ { ++ "name": "enable-ipfs", ++ "owners": [ "//components/ipfs/OWNERS" ], ++ "expiry_milestone": 150 ++ }, + { + "name": "enable-isolated-sandboxed-iframes", + "owners": [ "wjmaclean@chromium.org", "alexmos@chromium.org", "creis@chromium.org" ], +diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc +index f92c5df0fc600..e131baa70cce2 100644 +--- a/chrome/browser/flag_descriptions.cc ++++ b/chrome/browser/flag_descriptions.cc +@@ -248,6 +248,11 @@ const char kEnableBenchmarkingDescription[] = + "after 3 restarts. On the third restart, the flag will appear to be off " + "but the effect is still active."; + ++#if BUILDFLAG(ENABLE_IPFS) ++extern const char kEnableIpfsName[] = "Enable IPFS"; ++extern const char kEnableIpfsDescription[] = "Enable ipfs:// and ipns:// URLs"; ++#endif ++ + const char kPreloadingOnPerformancePageName[] = + "Preloading Settings on Performance Page"; + const char kPreloadingOnPerformancePageDescription[] = +diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h +index 71eae84724eab..a8e4b29ee3cc5 100644 +--- a/chrome/browser/flag_descriptions.h ++++ b/chrome/browser/flag_descriptions.h +@@ -22,6 +22,7 @@ + #include "pdf/buildflags.h" + #include "printing/buildflags/buildflags.h" + #include "third_party/blink/public/common/buildflags.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + + // This file declares strings used in chrome://flags. These messages are not + // translated, because instead of end-users they target Chromium developers and +@@ -165,6 +166,11 @@ extern const char kDownloadWarningImprovementsDescription[]; + extern const char kEnableBenchmarkingName[]; + extern const char kEnableBenchmarkingDescription[]; + ++#if BUILDFLAG(ENABLE_IPFS) ++extern const char kEnableIpfsName[]; ++extern const char kEnableIpfsDescription[]; ++#endif ++ + #if BUILDFLAG(USE_FONTATIONS_BACKEND) + extern const char kFontationsFontBackendName[]; + extern const char kFontationsFontBackendDescription[]; +diff --git a/chrome/browser/ipfs_extra_parts.cc b/chrome/browser/ipfs_extra_parts.cc +new file mode 100644 +index 0000000000000..90d2596fd779a +--- /dev/null ++++ b/chrome/browser/ipfs_extra_parts.cc +@@ -0,0 +1,10 @@ ++#include "ipfs_extra_parts.h" ++ ++#include "profiles/profile.h" ++ ++#include ++ ++void IpfsExtraParts::PostProfileInit(Profile* profile, bool /* is_initial_profile */ ) { ++ DCHECK(profile); ++ ipfs::InterRequestState::CreateForBrowserContext(profile, profile->GetPrefs()); ++} +diff --git a/chrome/browser/ipfs_extra_parts.h b/chrome/browser/ipfs_extra_parts.h +new file mode 100644 +index 0000000000000..2059c437e23a0 +--- /dev/null ++++ b/chrome/browser/ipfs_extra_parts.h +@@ -0,0 +1,10 @@ ++#ifndef IPFS_EXTRA_PART_H_ ++#define IPFS_EXTRA_PART_H_ ++ ++#include ++ ++class IpfsExtraParts : public ChromeBrowserMainExtraParts { ++ void PostProfileInit(Profile* profile, bool is_initial_profile) override; ++}; ++ ++#endif // IPFS_EXTRA_PART_H_ +diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc +index 0af94fd3059cf..60a20373ed748 100644 +--- a/chrome/browser/prefs/browser_prefs.cc ++++ b/chrome/browser/prefs/browser_prefs.cc +@@ -184,6 +184,7 @@ + #include "printing/buildflags/buildflags.h" + #include "rlz/buildflags/buildflags.h" + #include "third_party/abseil-cpp/absl/types/optional.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + + #if BUILDFLAG(ENABLE_BACKGROUND_MODE) + #include "chrome/browser/background/background_mode_manager.h" +@@ -234,6 +235,11 @@ + #include "chrome/browser/pdf/pdf_pref_names.h" + #endif // BUILDFLAG(ENABLE_PDF) + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#include "components/ipfs/preferences.h" ++#endif ++ + #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) + #include "chrome/browser/screen_ai/pref_names.h" + #endif +@@ -1662,6 +1668,11 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry, + IncognitoModePrefs::RegisterProfilePrefs(registry); + invalidation::PerUserTopicSubscriptionManager::RegisterProfilePrefs(registry); + invalidation::InvalidatorRegistrarWithMemory::RegisterProfilePrefs(registry); ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ ipfs::RegisterPreferences(registry); ++ } ++#endif + language::LanguagePrefs::RegisterProfilePrefs(registry); + login_detection::prefs::RegisterProfilePrefs(registry); + lookalikes::RegisterProfilePrefs(registry); +diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc +index 246ec9c5c911f..5d66d133a7907 100644 +--- a/chrome/common/chrome_content_client.cc ++++ b/chrome/common/chrome_content_client.cc +@@ -296,6 +296,12 @@ void ChromeContentClient::AddAdditionalSchemes(Schemes* schemes) { + #if BUILDFLAG(IS_ANDROID) + schemes->local_schemes.push_back(url::kContentScheme); + #endif ++ for ( const char* ip_s : {"ipfs", "ipns"} ) { ++ schemes->standard_schemes.push_back(ip_s); ++ schemes->cors_enabled_schemes.push_back(ip_s); ++ schemes->secure_schemes.push_back(ip_s); ++ schemes->csp_bypassing_schemes.push_back(ip_s); ++ } + } + + std::u16string ChromeContentClient::GetLocalizedString(int message_id) { +diff --git a/components/cbor/reader.cc b/components/cbor/reader.cc +index 306ba52fa4944..6b13b3a679a65 100644 +--- a/components/cbor/reader.cc ++++ b/components/cbor/reader.cc +@@ -22,7 +22,7 @@ + namespace cbor { + + namespace constants { +-const char kUnsupportedMajorType[] = "Unsupported major type."; ++const char kUnsupportedMajorType[] = "Unsupported major type operation."; + } + + namespace { +@@ -156,7 +156,11 @@ absl::optional Reader::DecodeCompleteDataItem(const Config& config, + case Value::Type::FLOAT_VALUE: + // Floating point values also go here since they are also type 7. + return DecodeToSimpleValueOrFloat(*header, config); +- case Value::Type::TAG: // We explicitly don't support TAG. ++ case Value::Type::TAG: ++ if (config.parse_tags) { ++ return ReadTagContent(*header, config, max_nesting_level); ++ } ++ break; + case Value::Type::NONE: + case Value::Type::INVALID_UTF8: + break; +@@ -347,6 +351,17 @@ absl::optional Reader::ReadByteStringContent( + return Value(std::move(cbor_byte_string)); + } + ++absl::optional Reader::ReadTagContent( ++ const Reader::DataItemHeader& header, ++ const Config& config, ++ int max_nesting_level) { ++ auto tagged_content = DecodeCompleteDataItem(config, max_nesting_level); ++ if (tagged_content.has_value()) { ++ tagged_content.value().SetTag(header.value); ++ } ++ return tagged_content; ++} ++ + absl::optional Reader::ReadArrayContent( + const Reader::DataItemHeader& header, + const Config& config, +diff --git a/components/cbor/reader.h b/components/cbor/reader.h +index f0b43a5517528..a57e277a1bc66 100644 +--- a/components/cbor/reader.h ++++ b/components/cbor/reader.h +@@ -130,6 +130,11 @@ class CBOR_EXPORT Reader { + // during decoding will set raise the `UNSUPPORTED_FLOATING_POINT_VALUE` + // error. + bool allow_floating_point = false; ++ ++ // If the parser encounters a TAG element, should it be parsed out and ++ // the tag value saved (true), or should the entire node and its content ++ // be discarded (false) ++ bool parse_tags = false; + }; + + Reader(const Reader&) = delete; +@@ -204,6 +209,9 @@ class CBOR_EXPORT Reader { + absl::optional ReadMapContent(const DataItemHeader& header, + const Config& config, + int max_nesting_level); ++ absl::optional ReadTagContent(const DataItemHeader& header, ++ const Config& config, ++ int max_nesting_level); + absl::optional ReadByte(); + absl::optional> ReadBytes(uint64_t num_bytes); + bool IsKeyInOrder(const Value& new_key, +diff --git a/components/cbor/reader_unittest.cc b/components/cbor/reader_unittest.cc +index 83d44a48d6dfa..a6ec5299b3241 100644 +--- a/components/cbor/reader_unittest.cc ++++ b/components/cbor/reader_unittest.cc +@@ -1451,5 +1451,42 @@ TEST(CBORReaderTest, AllowInvalidUTF8) { + EXPECT_FALSE(cbor); + EXPECT_EQ(Reader::DecoderError::INVALID_UTF8, error); + } ++TEST(CBORReaderTest, RejectsTagUnderDefaultConfig) { ++ static const uint8_t kTaggedCbor[] = { ++ 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x71, 0x12, 0x20, 0x69, 0xea, 0x07, ++ 0x40, 0xf9, 0x80, 0x7a, 0x28, 0xf4, 0xd9, 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, 0x07, 0x2c, 0x90, 0x26, 0x6a, 0xb3, 0xe7, ++ 0x9d, 0xf6, 0x3a, 0x36, 0x5b ++ }; ++ Reader::Config config; ++ absl::optional cbor = Reader::Read(kTaggedCbor, config); ++ EXPECT_FALSE(cbor.has_value()); ++} ++TEST(CBORReaderTest, ReadsTagWhenConfiguredToDoSo) { ++ static const uint8_t kTaggedCbor[] = { ++ 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x71, 0x12, 0x20, 0x69, 0xea, 0x07, ++ 0x40, 0xf9, 0x80, 0x7a, 0x28, 0xf4, 0xd9, 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, 0x07, 0x2c, 0x90, 0x26, 0x6a, 0xb3, 0xe7, ++ 0x9d, 0xf6, 0x3a, 0x36, 0x5b ++ }; ++ Reader::Config config; ++ config.parse_tags = true; ++ absl::optional cbor = Reader::Read(kTaggedCbor, config); ++ EXPECT_TRUE(cbor.has_value()); ++ auto& v = cbor.value(); ++ EXPECT_TRUE(v.has_tag()); ++ EXPECT_EQ(v.GetTag(),42UL); ++ EXPECT_TRUE(v.is_bytestring()); ++ EXPECT_EQ(v.type(), Value::Type::BYTE_STRING); ++ auto& bytes = v.GetBytestring(); ++ EXPECT_EQ(bytes.size(), 37UL); ++ EXPECT_EQ(bytes.at(0), 0x00);//identity multibase (e.g. not base-encoded, bytes are themselves) ++ EXPECT_EQ(bytes.at(1), 0x01);//CID version 1 ++ EXPECT_EQ(bytes.at(2), 0x71);//codec = dag-cbor ++ EXPECT_EQ(bytes.at(3), 0x12);//multihash = 18 = sha2-256 ++ EXPECT_EQ(bytes.at(4), 0x20);//hash length = 32 bytes ++ EXPECT_EQ(bytes.at(5), 0x69);//first byte of hash digest ++ EXPECT_EQ(bytes.at(36),0x5b);//last byte of hash digest ++} + + } // namespace cbor +diff --git a/components/cbor/values.cc b/components/cbor/values.cc +index 02498209c820e..34055aef24cfe 100644 +--- a/components/cbor/values.cc ++++ b/components/cbor/values.cc +@@ -66,32 +66,34 @@ Value::Value(Type type) : type_(type) { + NOTREACHED(); + } + +-Value::Value(SimpleValue in_simple) +- : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) { ++Value::Value(SimpleValue in_simple, uint64_t tag) ++ : type_(Type::SIMPLE_VALUE), simple_value_(in_simple), tag_(tag) { + CHECK(static_cast(in_simple) >= 20 && static_cast(in_simple) <= 23); + } + +-Value::Value(bool boolean_value) : type_(Type::SIMPLE_VALUE) { ++Value::Value(bool boolean_value, uint64_t tag) : type_(Type::SIMPLE_VALUE), tag_(tag) { + simple_value_ = boolean_value ? Value::SimpleValue::TRUE_VALUE + : Value::SimpleValue::FALSE_VALUE; + } + +-Value::Value(double float_value) +- : type_(Type::FLOAT_VALUE), float_value_(float_value) {} ++Value::Value(double float_value, uint64_t tag) ++ : type_(Type::FLOAT_VALUE), float_value_(float_value), tag_(tag) {} + +-Value::Value(int integer_value) +- : Value(base::checked_cast(integer_value)) {} ++Value::Value(int integer_value, uint64_t tag) ++ : Value(base::checked_cast(integer_value), tag) {} + +-Value::Value(int64_t integer_value) : integer_value_(integer_value) { ++Value::Value(int64_t integer_value, uint64_t tag) : integer_value_(integer_value), tag_(tag) { + type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE; + } + +-Value::Value(base::span in_bytes) ++Value::Value(base::span in_bytes, uint64_t tag) + : type_(Type::BYTE_STRING), +- bytestring_value_(in_bytes.begin(), in_bytes.end()) {} ++ bytestring_value_(in_bytes.begin(), in_bytes.end()), ++ tag_(tag) ++ {} + +-Value::Value(base::span in_bytes, Type type) +- : type_(type), bytestring_value_(in_bytes.begin(), in_bytes.end()) { ++Value::Value(base::span in_bytes, Type type, uint64_t tag) ++ : type_(type), bytestring_value_(in_bytes.begin(), in_bytes.end()), tag_(tag) { + DCHECK(type_ == Type::BYTE_STRING || type_ == Type::INVALID_UTF8); + } + +@@ -117,7 +119,8 @@ Value::Value(std::string&& in_string, Type type) noexcept : type_(type) { + } + } + +-Value::Value(base::StringPiece in_string, Type type) : type_(type) { ++Value::Value(base::StringPiece in_string, Type type, uint64_t tag) ++: type_(type), tag_(tag) { + switch (type_) { + case Type::STRING: + new (&string_value_) std::string(); +@@ -133,16 +136,18 @@ Value::Value(base::StringPiece in_string, Type type) : type_(type) { + } + } + +-Value::Value(const ArrayValue& in_array) : type_(Type::ARRAY), array_value_() { ++Value::Value(const ArrayValue& in_array, uint64_t tag) ++: type_(Type::ARRAY), array_value_(), tag_(tag) { + array_value_.reserve(in_array.size()); + for (const auto& val : in_array) + array_value_.emplace_back(val.Clone()); + } + +-Value::Value(ArrayValue&& in_array) noexcept +- : type_(Type::ARRAY), array_value_(std::move(in_array)) {} ++Value::Value(ArrayValue&& in_array, uint64_t tag) noexcept ++ : type_(Type::ARRAY), array_value_(std::move(in_array)), tag_(tag) {} + +-Value::Value(const MapValue& in_map) : type_(Type::MAP), map_value_() { ++Value::Value(const MapValue& in_map, uint64_t tag) ++: type_(Type::MAP), map_value_(), tag_(tag) { + map_value_.reserve(in_map.size()); + for (const auto& it : in_map) + map_value_.emplace_hint(map_value_.end(), it.first.Clone(), +@@ -168,31 +173,36 @@ Value Value::Clone() const { + case Type::NONE: + return Value(); + case Type::INVALID_UTF8: +- return Value(bytestring_value_, Type::INVALID_UTF8); ++ return Value(bytestring_value_, Type::INVALID_UTF8, tag_); + case Type::UNSIGNED: + case Type::NEGATIVE: +- return Value(integer_value_); ++ return Value(integer_value_, tag_); + case Type::BYTE_STRING: +- return Value(bytestring_value_); ++ return Value(bytestring_value_, tag_); + case Type::STRING: +- return Value(string_value_); ++ return Value(string_value_, Type::STRING, tag_); + case Type::ARRAY: +- return Value(array_value_); ++ return Value(array_value_, tag_); + case Type::MAP: +- return Value(map_value_); ++ return Value(map_value_, tag_); + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return Value(); + case Type::SIMPLE_VALUE: +- return Value(simple_value_); ++ return Value(simple_value_, tag_); + case Type::FLOAT_VALUE: +- return Value(float_value_); ++ return Value(float_value_, tag_); + } + + NOTREACHED(); + return Value(); + } + ++Value& Value::SetTag(uint64_t tag) noexcept { ++ tag_ = tag; ++ return *this; ++} ++ + Value::SimpleValue Value::GetSimpleValue() const { + CHECK(is_simple()); + return simple_value_; +@@ -258,9 +268,14 @@ const Value::BinaryValue& Value::GetInvalidUTF8() const { + return bytestring_value_; + } + ++uint64_t Value::GetTag() const { ++ CHECK(has_tag()); ++ return tag_; ++} ++ + void Value::InternalMoveConstructFrom(Value&& that) { + type_ = that.type_; +- ++ tag_ = that.tag_; + switch (type_) { + case Type::UNSIGNED: + case Type::NEGATIVE: +diff --git a/components/cbor/values.h b/components/cbor/values.h +index d81ef5607c55a..10216a8dcdc57 100644 +--- a/components/cbor/values.h ++++ b/components/cbor/values.h +@@ -127,28 +127,29 @@ class CBOR_EXPORT Value { + + explicit Value(Type type); + +- explicit Value(SimpleValue in_simple); +- explicit Value(bool boolean_value); +- explicit Value(double in_float); ++ explicit Value(SimpleValue in_simple, uint64_t tag = NO_TAG); ++ explicit Value(bool boolean_value, uint64_t tag = NO_TAG); ++ explicit Value(double in_float, uint64_t tag = NO_TAG); + +- explicit Value(int integer_value); +- explicit Value(int64_t integer_value); ++ explicit Value(int integer_value, uint64_t tag = NO_TAG); ++ explicit Value(int64_t integer_value, uint64_t tag = NO_TAG); + explicit Value(uint64_t integer_value) = delete; + +- explicit Value(base::span in_bytes); ++ explicit Value(base::span in_bytes, uint64_t tag = NO_TAG); + explicit Value(BinaryValue&& in_bytes) noexcept; + + explicit Value(const char* in_string, Type type = Type::STRING); + explicit Value(std::string&& in_string, Type type = Type::STRING) noexcept; +- explicit Value(base::StringPiece in_string, Type type = Type::STRING); ++ explicit Value(base::StringPiece in_string, Type type = Type::STRING, uint64_t tag = NO_TAG); + +- explicit Value(const ArrayValue& in_array); +- explicit Value(ArrayValue&& in_array) noexcept; ++ explicit Value(const ArrayValue& in_array, uint64_t tag = NO_TAG); ++ explicit Value(ArrayValue&& in_array, uint64_t tag = NO_TAG) noexcept; + +- explicit Value(const MapValue& in_map); ++ explicit Value(const MapValue& in_map, uint64_t tag = NO_TAG); + explicit Value(MapValue&& in_map) noexcept; + + Value& operator=(Value&& that) noexcept; ++ Value& SetTag(uint64_t) noexcept; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; +@@ -179,6 +180,7 @@ class CBOR_EXPORT Value { + bool is_string() const { return type() == Type::STRING; } + bool is_array() const { return type() == Type::ARRAY; } + bool is_map() const { return type() == Type::MAP; } ++ bool has_tag() const { return tag_ != NO_TAG; } + + // These will all fatally assert if the type doesn't match. + SimpleValue GetSimpleValue() const; +@@ -194,12 +196,13 @@ class CBOR_EXPORT Value { + const ArrayValue& GetArray() const; + const MapValue& GetMap() const; + const BinaryValue& GetInvalidUTF8() const; ++ uint64_t GetTag() const; + + private: + friend class Reader; + // This constructor allows INVALID_UTF8 values to be created, which only + // |Reader| and InvalidUTF8StringValueForTesting() may do. +- Value(base::span in_bytes, Type type); ++ Value(base::span in_bytes, Type type, uint64_t tag = NO_TAG); + + Type type_; + +@@ -213,6 +216,11 @@ class CBOR_EXPORT Value { + MapValue map_value_; + }; + ++ //This value specified as Invalid, ++ // used here to represent absence of TAG ++ constexpr static uint64_t NO_TAG = 0xFFFF; ++ uint64_t tag_ = NO_TAG; ++ + void InternalMoveConstructFrom(Value&& that); + void InternalCleanup(); + }; +diff --git a/components/cbor/writer.cc b/components/cbor/writer.cc +index bb22754d36a07..aae4027836377 100644 +--- a/components/cbor/writer.cc ++++ b/components/cbor/writer.cc +@@ -47,6 +47,9 @@ bool Writer::EncodeCBOR(const Value& node, + if (max_nesting_level < 0) + return false; + ++ if (node.has_tag()) { ++ StartItem(Value::Type::TAG, node.GetTag()); ++ } + switch (node.type()) { + case Value::Type::NONE: { + StartItem(Value::Type::BYTE_STRING, 0); +diff --git a/components/cbor/writer_unittest.cc b/components/cbor/writer_unittest.cc +index e3bffe20734bc..0ed569ae164a0 100644 +--- a/components/cbor/writer_unittest.cc ++++ b/components/cbor/writer_unittest.cc +@@ -522,4 +522,31 @@ TEST(CBORWriterTest, OverlyNestedCBOR) { + EXPECT_FALSE(Writer::Write(Value(map), 4).has_value()); + } + ++TEST(CBORWriterTest, CanWriteTag) { ++ std::array content{ ++ 0x00, 0x01, 0x71, 0x12, 0x20, ++ 0x69, 0xea, 0x07, 0x40, 0xf9, ++ 0x80, 0x7a, 0x28, 0xf4, 0xd9, ++ 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, ++ 0x07, 0x2c, 0x90, 0x26, 0x6a, ++ 0xb3, 0xe7, 0x9d, 0xf6, 0x3a, ++ 0x36, 0x5b ++ }; ++ Value to_write(content); ++ to_write.SetTag(42); ++ auto result = Writer::Write(to_write); ++ EXPECT_TRUE(result.has_value()); ++ auto& bytes = result.value(); ++ EXPECT_EQ(bytes.size(), 41UL); ++ EXPECT_EQ(bytes.at(0), 0xd8); ++ EXPECT_EQ(bytes.at(1), 0x2a); ++ EXPECT_EQ(bytes.at(2), 0x58); ++ EXPECT_EQ(bytes.at(3), 0x25); ++ for (auto i = 0UL; i < content.size(); ++i) { ++ ASSERT_LT(i + 4UL, bytes.size()); ++ ASSERT_EQ(content.at(i), bytes.at(i+4UL)); ++ } ++} ++ + } // namespace cbor +diff --git a/components/open_from_clipboard/clipboard_recent_content_generic.cc b/components/open_from_clipboard/clipboard_recent_content_generic.cc +index 4dcafecbc66c6..d205209c08162 100644 +--- a/components/open_from_clipboard/clipboard_recent_content_generic.cc ++++ b/components/open_from_clipboard/clipboard_recent_content_generic.cc +@@ -20,7 +20,7 @@ + namespace { + // Schemes appropriate for suggestion by ClipboardRecentContent. + const char* kAuthorizedSchemes[] = { +- url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme, ++ url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme, "ipfs", "ipns" + // TODO(mpearson): add support for chrome:// URLs. Right now the scheme + // for that lives in content and is accessible via + // GetEmbedderRepresentationOfAboutScheme() or content::kChromeUIScheme +diff --git a/net/dns/dns_config_service_linux.cc b/net/dns/dns_config_service_linux.cc +index 5273da5190277..12b28b86a4c00 100644 +--- a/net/dns/dns_config_service_linux.cc ++++ b/net/dns/dns_config_service_linux.cc +@@ -272,11 +272,11 @@ bool IsNsswitchConfigCompatible( + // Ignore any entries after `kDns` because Chrome will fallback to the + // system resolver if a result was not found in DNS. + return true; +- ++ case NsswitchReader::Service::kResolve: ++ break; + case NsswitchReader::Service::kMdns: + case NsswitchReader::Service::kMdns4: + case NsswitchReader::Service::kMdns6: +- case NsswitchReader::Service::kResolve: + case NsswitchReader::Service::kNis: + RecordIncompatibleNsswitchReason( + IncompatibleNsswitchReason::kIncompatibleService, +diff --git a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc +index 4eadf46ea0c24..d62fc7fb14e01 100644 +--- a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc ++++ b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc +@@ -67,7 +67,7 @@ class URLSchemesRegistry final { + // is considered secure. Additional checks are performed to ensure that + // other http pages are filtered out. + service_worker_schemes({"http", "https"}), +- fetch_api_schemes({"http", "https"}), ++ fetch_api_schemes({"http", "https", "ipfs", "ipns"}), + allowed_in_referrer_schemes({"http", "https"}) { + for (auto& scheme : url::GetCorsEnabledSchemes()) + cors_enabled_schemes.insert(scheme.c_str()); +diff --git a/url/BUILD.gn b/url/BUILD.gn +index c525c166979d6..ce2b1ae43c0a7 100644 +--- a/url/BUILD.gn ++++ b/url/BUILD.gn +@@ -5,6 +5,7 @@ + import("//build/buildflag_header.gni") + import("//testing/libfuzzer/fuzzer_test.gni") + import("//testing/test.gni") ++import("//third_party/ipfs_client/args.gni") + import("features.gni") + + import("//build/config/cronet/config.gni") +@@ -67,6 +68,7 @@ component("url") { + public_deps = [ + "//base", + "//build:robolectric_buildflags", ++ "//third_party/ipfs_client:ipfs_buildflags", + ] + + configs += [ "//build/config/compiler:wexit_time_destructors" ] +@@ -89,6 +91,11 @@ component("url") { + public_configs = [ "//third_party/jdk" ] + } + ++ if (enable_ipfs) { ++ sources += [ "url_canon_ipfs.cc" ] ++ deps += [ "//third_party/ipfs_client:ipfs_client" ] ++ } ++ + if (is_win) { + # Don't conflict with Windows' "url.dll". + output_name = "url_lib" +diff --git a/url/url_canon.h b/url/url_canon.h +index d3a7fabf09fa8..06db17242248f 100644 +--- a/url/url_canon.h ++++ b/url/url_canon.h +@@ -697,6 +697,23 @@ bool CanonicalizeMailtoURL(const char16_t* spec, + CanonOutput* output, + Parsed* new_parsed); + ++COMPONENT_EXPORT(URL) ++bool CanonicalizeIpfsURL(const char* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed); ++COMPONENT_EXPORT(URL) ++bool CanonicalizeIpfsURL(const char16_t* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed); ++ + // Part replacer -------------------------------------------------------------- + + // Internal structure used for storing separate strings for each component. +diff --git a/url/url_canon_ipfs.cc b/url/url_canon_ipfs.cc +new file mode 100644 +index 0000000000000..33910614c4527 +--- /dev/null ++++ b/url/url_canon_ipfs.cc +@@ -0,0 +1,56 @@ ++#include "url_canon_internal.h" ++ ++#include ++#include ++ ++#include ++ ++bool url::CanonicalizeIpfsURL(const char* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* charset_converter, ++ CanonOutput* output, ++ Parsed* output_parsed) { ++ if ( spec_len < 1 || !spec ) { ++ return false; ++ } ++ if ( parsed.host.len < 1 ) { ++ return false; ++ } ++ std::string_view cid_str{ spec + parsed.host.begin, static_cast(parsed.host.len) }; ++ auto cid = ipfs::Cid(cid_str); ++ if ( !cid.valid() ) { ++ cid = ipfs::id_cid::forText( std::string{cid_str} + " is not a valid CID." ); ++ } ++ auto as_str = cid.to_string(); ++ if ( as_str.empty() ) { ++ return false; ++ } ++ std::string stdurl{ spec, static_cast(parsed.host.begin) }; ++ stdurl.append( as_str ); ++ stdurl.append( spec + parsed.host.end(), spec_len - parsed.host.end() ); ++ spec = stdurl.data(); ++ spec_len = static_cast(stdurl.size()); ++ Parsed parsed_input; ++ ParseStandardURL(spec, spec_len, &parsed_input); ++ return CanonicalizeStandardURL( ++ spec, ++ spec_len, ++ parsed_input, ++ scheme_type, ++ charset_converter, ++ output, output_parsed ++ ); ++} ++bool url::CanonicalizeIpfsURL(const char16_t* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed) { ++ RawCanonOutput<2048> as8; ++ ConvertUTF16ToUTF8(spec, spec_len, &as8); ++ return CanonicalizeIpfsURL(as8.data(), as8.length(), parsed, scheme_type, query_converter, output, new_parsed); ++} +diff --git a/url/url_util.cc b/url/url_util.cc +index 9258cfcfada47..daf10e4c3b741 100644 +--- a/url/url_util.cc ++++ b/url/url_util.cc +@@ -277,6 +277,12 @@ bool DoCanonicalize(const CHAR* spec, + charset_converter, output, + output_parsed); + ++ } else if (DoCompareSchemeComponent(spec, scheme, "ipfs")) { ++ // Switch multibase away from case-sensitive ones before continuing canonicalization. ++ ParseStandardURL(spec, spec_len, &parsed_input); ++ success = CanonicalizeIpfsURL(spec, spec_len, parsed_input, scheme_type, ++ charset_converter, output, output_parsed); ++ + } else if (DoIsStandard(spec, scheme, &scheme_type)) { + // All "normal" URLs. + ParseStandardURL(spec, spec_len, &parsed_input); + diff --git a/component/preferences.cc b/component/preferences.cc index 60bb0f67..0db47f00 100644 --- a/component/preferences.cc +++ b/component/preferences.cc @@ -17,9 +17,9 @@ void ipfs::RegisterPreferences(PrefRegistrySimple* service) { for (auto& gw : Gateways::DefaultGateways()) { vals.Set(gw.prefix, static_cast(gw.rate)); } - LOG(WARNING) << "Registering ipfs.gateways preference with a default value " - "that contains " - << vals.size() << " entries."; + VLOG(2) << "Registering ipfs.gateways preference with a default value " + "that contains " + << vals.size() << " entries."; for (auto [k, v] : vals) { DCHECK(v.is_int()); } @@ -33,7 +33,7 @@ Rates::GatewayRates(PrefService* prefs) : prefs_{prefs} { auto i = v.GetInt(); curr_.Set(k, std::max(i, 1)); } - LOG(INFO) << "Initialized with " << curr_.size() << " gateways."; + VLOG(1) << "Initialized with " << curr_.size() << " gateways."; } else { LOG(ERROR) << "Reading preferences without a preferences service is not great."; @@ -62,7 +62,7 @@ void Rates::SetRate(std::string_view k, unsigned val) { // TODO - I believe the calls to save here need to be sent to UI thread save(); } else if (++changes > update_thresh) { - LOG(INFO) << "Changing rate for gateway " << k << " to " << val; + VLOG(2) << "Changing rate for gateway " << k << " to " << val; auto d = delta(); if (d > update_thresh) { save(); @@ -80,8 +80,6 @@ std::size_t Rates::delta() const { return rv; } void Rates::save() { - LOG(INFO) << "Saving " << changes - << " dynamic updates to gateway rates to disk."; changes = 0; last_ = curr_.Clone(); update_thresh++; diff --git a/component/url_loader_factory.cc b/component/url_loader_factory.cc index 9a802840..1544ba9a 100644 --- a/component/url_loader_factory.cc +++ b/component/url_loader_factory.cc @@ -28,8 +28,7 @@ ipfs::IpfsURLLoaderFactory::IpfsURLLoaderFactory( scheme_{scheme}, context_{context}, default_factory_{default_factory}, - network_context_{net_ctxt}, - pref_svc_{pref_svc} {} + network_context_{net_ctxt} {} ipfs::IpfsURLLoaderFactory::~IpfsURLLoaderFactory() noexcept { context_ = nullptr; @@ -45,8 +44,6 @@ void ipfs::IpfsURLLoaderFactory::CreateLoaderAndStart( mojo::PendingRemote client, net::MutableNetworkTrafficAnnotationTag const& // traffic_annotation ) { - VLOG(2) << "IPFS subresource: case=" << scheme_ - << " url=" << request.url.spec(); DCHECK(default_factory_); if (scheme_ == "ipfs" || scheme_ == "ipns") { auto ptr = std::make_shared( diff --git a/component/url_loader_factory.h b/component/url_loader_factory.h index 01cd66ea..5d209c93 100644 --- a/component/url_loader_factory.h +++ b/component/url_loader_factory.h @@ -51,7 +51,6 @@ class COMPONENT_EXPORT(IPFS) IpfsURLLoaderFactory raw_ptr context_; raw_ptr default_factory_; raw_ptr network_context_; - raw_ptr pref_svc_; }; } // namespace ipfs diff --git a/doc/design_notes.md b/doc/design_notes.md index c01011ec..db121b8a 100644 --- a/doc/design_notes.md +++ b/doc/design_notes.md @@ -78,10 +78,10 @@ It's an unsigned integer in two forms: * This helps to ensure you won't always be sending requests to the same gateways in the same order, or in a deterministic way. When issuing a request to another gateway, it checks the gateways in descending-score order: -* If the gateway already has a request for that data pending_, or has already failed to return successfully, it's skipped. -* If the gateways score is less than the number of pending_ requests currently sent to that gateway, it's skipped as it's considered already-too-busy +* If the gateway already has a request for that data startup_pending_, or has already failed to return successfully, it's skipped. +* If the gateways score is less than the number of startup_pending_ requests currently sent to that gateway, it's skipped as it's considered already-too-busy * The "need" is generally calculated as the target number of gateways desired to be involved (based on request parallel), subtracting the number of gateways currently processing a request for this data. -* If the "need" is less than half the count of pending_ requests on this gateway, it's skipped as it's simply not urgent enough to justify further overloading this gateway. +* If the "need" is less than half the count of startup_pending_ requests on this gateway, it's skipped as it's simply not urgent enough to justify further overloading this gateway. On a side-note, the hard-coded starting points for the scoring effectively encodes known information about those gateways. For example: http://localhost:8080/ is scored extremely highly. There's a good chance it has the resource you're looking for, and if it doesn't you may want to send a request that way anyhow so that it will in the future. diff --git a/doc/original_design.md b/doc/original_design.md index 09200330..3e2a3072 100644 --- a/doc/original_design.md +++ b/doc/original_design.md @@ -83,13 +83,13 @@ The class maintains: ```mermaid graph TD; - start(["URL suffix from above flow"]) --> add[("Add to pending_ requests")] + start(["URL suffix from above flow"]) --> add[("Add to startup_pending_ requests")] style start fill:#9CF,color:black - add --> selreq["Select the pending_ request with the lowest dup count"] --> incdup["Increase its dup count"] + add --> selreq["Select the startup_pending_ request with the lowest dup count"] --> incdup["Increase its dup count"] incdup --> goodfree{"Is there a gateway that is both GOOD and FREE"} goodfree --NO--> badfree{"Are there any FREE that have not already TaskFailed this request?"} badfree --NO--> anybusy{"Are there any BUSY gateways?"} - anybusy --YES--> wait(("Wait for pending_ requests to finish (return flow control)")) + anybusy --YES--> wait(("Wait for startup_pending_ requests to finish (return flow control)")) badfree --YES--> selbf["Select the one with the fewest TaskFailed requests, initial parallel tiebreaks"] selbf --> mark_busy["Mark the gateway as BUSY"] goodfree --YES--> selbf diff --git a/library/BUILD.gn.in b/library/BUILD.gn.in index 07ccf084..61d4338a 100644 --- a/library/BUILD.gn.in +++ b/library/BUILD.gn.in @@ -19,7 +19,6 @@ if (enable_ipfs) { static_library("ipfs_client") { if (is_nacl) { sources = cxx_sources - [ - "src/ipfs_client/dag_block.cc", "src/ipfs_client/gw/gateway_request.cc", "src/ipfs_client/gw/gateway_http_requestor.cc", "src/ipfs_client/gw/requestor.cc", @@ -27,6 +26,7 @@ if (enable_ipfs) { "src/ipfs_client/ipns_names.cc", "src/ipfs_client/ipns_record.cc", "src/ipfs_client/logger.cc", + "src/ipfs_client/pb_dag.cc", "src/ipfs_client/signing_key_type.cc", ] } else { diff --git a/library/include/ipfs_client/gw/gateway_request.h b/library/include/ipfs_client/gw/gateway_request.h index f1d7d795..d1ea8365 100644 --- a/library/include/ipfs_client/gw/gateway_request.h +++ b/library/include/ipfs_client/gw/gateway_request.h @@ -66,6 +66,7 @@ class GatewayRequest { std::shared_ptr const& api); void Hook(std::function); bool PartiallyRedundant() const; + std::string Key() const; static std::shared_ptr fromIpfsPath(SlashDelimited); }; diff --git a/library/src/ipfs_client/car.cc b/library/src/ipfs_client/car.cc index b231e8d0..0b508698 100644 --- a/library/src/ipfs_client/car.cc +++ b/library/src/ipfs_client/car.cc @@ -26,7 +26,6 @@ Self::Car(ByteView bytes, ContextApi const& api) { LOG(ERROR) << "Problem parsing CAR header."; break; case 1: - VLOG(1) << "Reading CARv1"; data_ = after_header; break; case 2: { diff --git a/library/src/ipfs_client/gateways.cc b/library/src/ipfs_client/gateways.cc index 68eaa7c3..a5b7bf83 100644 --- a/library/src/ipfs_client/gateways.cc +++ b/library/src/ipfs_client/gateways.cc @@ -100,22 +100,22 @@ auto ipfs::Gateways::DefaultGateways() -> GatewayList { } return result; } - return {{"http://localhost:8080/"s, 885}, - {"https://jcsl.hopto.org/"s, 833}, - {"https://human.mypinata.cloud/"s, 737}, - {"https://ipfs.io/"s, 731}, - {"https://gateway.ipfs.io/"s, 628}, - {"https://dweb.link/"s, 512}, - {"https://gateway.pinata.cloud/"s, 455}, - {"https://ipfs.joaoleitao.org/"s, 355}, - {"https://ipfs.runfission.com/"s, 341}, - {"https://nftstorage.link/"s, 239}, - {"https://w3s.link/"s, 166}, - {"https://ipfs.fleek.co/"s, 133}, - {"https://permaweb.eu.org/"s, 96}, + return {{"http://localhost:8080/"s, 854}, + {"https://jcsl.hopto.org/"s, 791}, + {"https://ipfs.io/"s, 720}, + {"https://human.mypinata.cloud/"s, 622}, + {"https://gateway.ipfs.io/"s, 606}, + {"https://dweb.link/"s, 373}, + {"https://gateway.pinata.cloud/"s, 324}, + {"https://ipfs.runfission.com/"s, 289}, + {"https://ipfs.joaoleitao.org/"s, 259}, + {"https://nftstorage.link/"s, 175}, + {"https://w3s.link/"s, 91}, + {"https://permaweb.eu.org/"s, 63}, + {"https://ipfs.fleek.co/"s, 27}, {"https://hardbin.com/"s, 4}, - {"https://jorropo.net/"s, 3}, - {"https://ipfs.jpu.jp/"s, 2}, - {"https://ipfs.soul-network.com/"s, 1}, + {"https://ipfs.jpu.jp/"s, 3}, + {"https://ipfs.soul-network.com/"s, 2}, + {"https://jorropo.net/"s, 1}, {"https://storry.tv/"s, 0}}; } diff --git a/library/src/ipfs_client/gw/default_requestor.cc b/library/src/ipfs_client/gw/default_requestor.cc index 3a3da2d8..e58c4dc4 100644 --- a/library/src/ipfs_client/gw/default_requestor.cc +++ b/library/src/ipfs_client/gw/default_requestor.cc @@ -17,13 +17,8 @@ auto ipfs::gw::default_requestor(ipfs::GatewayList /* gws */, result->or_else(early); early->api(api); } - // auto pool = std::make_shared(); result->or_else(std::make_shared(api)) .or_else(std::make_shared()) .or_else(std::make_shared()); - // for (auto& gw : gws) { - // auto gwr = std::make_shared(gw.prefix, gw.rate, - // api); pool->add(gwr); - // } return result; } diff --git a/library/src/ipfs_client/gw/dnslink_requestor.cc b/library/src/ipfs_client/gw/dnslink_requestor.cc index 731b750f..7249ce80 100644 --- a/library/src/ipfs_client/gw/dnslink_requestor.cc +++ b/library/src/ipfs_client/gw/dnslink_requestor.cc @@ -39,8 +39,6 @@ auto Self::handle(ipfs::gw::RequestPtr req) -> HandleOutcome { *success = *success || parse_results(req, results, a); }; auto don = [success, req]() { - LOG(INFO) << "DNSLink request completed for " << req->main_param - << " success=" << *success; if (!*success) { req->dependent->finish(ipfs::Response::HOST_NOT_FOUND); } diff --git a/library/src/ipfs_client/gw/gateway_http_requestor.cc b/library/src/ipfs_client/gw/gateway_http_requestor.cc deleted file mode 100644 index 5fd1d91e..00000000 --- a/library/src/ipfs_client/gw/gateway_http_requestor.cc +++ /dev/null @@ -1,136 +0,0 @@ -#include "gateway_http_requestor.h" - -#include -#include - -#include -#include -#include - -#include "log_macros.h" - -using Self = ipfs::gw::GatewayHttpRequestor; -using ReqTyp = ipfs::gw::Type; - -std::string_view Self::name() const { - return "simplistic HTTP requestor"; -} -auto Self::handle(ipfs::gw::RequestPtr r) -> HandleOutcome { - DCHECK(r); - DCHECK(r->dependent); - DCHECK_GT(prefix_.size(), 0UL); - if (!r->is_http()) { - LOG(ERROR) << name() << " only handles HTTP requests"; - return HandleOutcome::NOT_HANDLED; - } - auto req_key = r->url_suffix().append(r->accept()); - if (seen_[req_key] > 0xFD) { - return HandleOutcome::NOT_HANDLED; - } - if (target(*r) <= r->parallel + pending_ + seen_[req_key]) { - return HandleOutcome::MAYBE_LATER; - } - auto desc = r->describe_http(prefix_); - if (!desc.has_value() || desc.value().url.empty()) { - LOG(ERROR) - << r->debug_string() - << " is HTTP but can't describe the HTTP request that would happen?"; - return HandleOutcome::NOT_HANDLED; - } - desc.value().timeout_seconds += extra_seconds_; - auto cb = [this, r, desc, req_key](std::int16_t status, std::string_view body, - ContextApi::HeaderAccess ha) { - if (r->parallel) { - r->parallel--; - } - if (pending_) { - pending_--; - } - if (r->type == Type::Zombie) { - return; - } else if (status == 408 || status == 504) { - // Timeouts - extra_seconds_++; - forward(r); - return; - } else if (status / 100 == 2) { - auto ct = ha("content-type"); - std::transform(ct.begin(), ct.end(), ct.begin(), ::tolower); - if (ct.empty()) { - LOG(ERROR) << "No content-type header?"; - } - if (ct.size() && desc->accept.size() && - ct.find(desc->accept) == std::string::npos) { - LOG(WARNING) << "Requested with Accept: " << desc->accept - << " but received response with content-type: " << ct; - LOG(INFO) << "Demote(" << prefix_ << ')'; - } else if (!r->RespondSuccessfully(body, api_)) { - LOG(ERROR) << "Got an unuseful response from " << prefix_ - << " forwarding request " << r->debug_string() - << " to next requestor."; - } else { - // Good cases - if (typ_good_.insert(r->type).second) { - VLOG(1) << prefix_ << " OK with requests of type " - << static_cast(r->type); - } else if (typ_bad_.erase(r->type)) { - VLOG(1) << prefix_ << " truly OK with requests of type " - << static_cast(r->type); - } - if (aff_good_.insert(r->affinity).second) { - VLOG(1) << prefix_ << " likes requests in the neighborhood of " - << r->affinity; - } else if (aff_bad_.erase(r->affinity)) { - VLOG(1) << prefix_ << " truly OK with affinity " << r->affinity; - } - VLOG(2) << prefix_ << " had a success on " << r->debug_string(); - LOG(INFO) << "Promote(" << prefix_ << ')'; - ++strength_; - return; - } - } else if (status / 100 == 4) { - seen_[req_key] += 9; - } - seen_[req_key] += 9; - LOG(INFO) << "Demote(" << prefix_ << ')'; - if (strength_ > 0) { - --strength_; - } - aff_bad_.insert(r->affinity); - typ_bad_.insert(r->type); - forward(r); - }; - DCHECK(api_); - api_->SendHttpRequest(desc.value(), cb); - seen_[req_key]++; - pending_++; - return HandleOutcome::PENDING; -} - -Self::GatewayHttpRequestor(std::string gateway_prefix, - int strength, - std::shared_ptr api) - : prefix_{gateway_prefix}, strength_{strength} { - api_ = api; -} -Self::~GatewayHttpRequestor() {} - -int Self::target(GatewayRequest const& r) const { - int result = (strength_ - pending_) / 2; - if (!pending_) { - ++result; - } - if (typ_good_.count(r.type)) { - result += 3; - } - if (!typ_bad_.count(r.type)) { - result += 2; - } - if (aff_good_.count(r.affinity)) { - result += 5; - } - if (aff_bad_.count(r.affinity) == 0UL) { - result += 4; - } - return result; -} diff --git a/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc b/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc deleted file mode 100644 index 03641944..00000000 --- a/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc +++ /dev/null @@ -1,122 +0,0 @@ -#include - -#include - -#include -#include -#include - -using T = ipfs::gw::GatewayHttpRequestor; -using R = ipfs::gw::GatewayRequest; -using P = ipfs::gw::RequestPtr; - -using namespace std::literals; - -namespace { - -struct FakeRtor : public ipfs::gw::Requestor { - std::string_view name() const { return "fake requestor"; } - std::vector

requests_forwarded; - HandleOutcome handle(P p) { - requests_forwarded.push_back(p); - return HandleOutcome::DONE; - } -}; -struct GatewayHttpRequestorTest : public ::testing::Test { - GatewayHttpRequestorTest() { ipfs::log::SetLevel(ipfs::log::Level::OFF); } - std::shared_ptr api = std::make_shared(); - std::shared_ptr t = std::make_shared("scheme://host", 1, api); - std::shared_ptr chain = std::make_shared(); - std::shared_ptr orc; - P req() { - t->or_else(chain); - auto noop = [](auto) {}; - auto noop2 = [](auto, auto) {}; - auto req = R::fromIpfsPath(i::SlashDelimited{ - "/ipfs/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku"}); - req->orchestrator(orc = std::make_shared(t, api)); - req->dependent = std::make_shared( - "/ipfs/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", - noop2); - return req; - } - ipfs::gw::Requestor& sup() { return *t; } -}; -} // namespace -TEST_F(GatewayHttpRequestorTest, name) { - EXPECT_EQ(sup().name(), "simplistic HTTP requestor"); -} -TEST_F(GatewayHttpRequestorTest, without_slash) { - t->request(req()); - EXPECT_EQ(api->http_requests_sent.size(), 1); - EXPECT_EQ(api->http_requests_sent.at(0).url, - "scheme://host/ipfs/" - "bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku"); -} -TEST_F(GatewayHttpRequestorTest, with_slash) { - t = std::make_shared("scheme://host/", 1, api); - t->request(req()); - EXPECT_EQ(api->http_requests_sent.size(), 1); - EXPECT_EQ(api->http_requests_sent.at(0).url, - "scheme://host/ipfs/" - "bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku"); -} -TEST_F(GatewayHttpRequestorTest, block_has_accept) { - t->request(req()); - EXPECT_EQ(api->http_requests_sent.size(), 1); - EXPECT_EQ(api->http_requests_sent.at(0).accept, "application/vnd.ipld.raw"); -} -TEST_F(GatewayHttpRequestorTest, callback_failure_forwards) { - t->request(req()); - EXPECT_EQ(api->http_requests_sent.size(), 1); - EXPECT_EQ(api->http_requests_sent.at(0).accept, "application/vnd.ipld.raw"); - EXPECT_EQ(api->cbs.size(), 1); - auto noop = [](auto) { return std::string{}; }; - api->cbs.at(0)(404, "", noop); - EXPECT_EQ(chain->requests_forwarded.size(), 1); -} -TEST_F(GatewayHttpRequestorTest, callback_success_adds_node) { - t->request(req()); - EXPECT_EQ(api->http_requests_sent.size(), 1); - EXPECT_EQ(api->http_requests_sent.at(0).accept, "application/vnd.ipld.raw"); - EXPECT_EQ(api->cbs.size(), 1); - auto noop = [](auto) { return std::string{}; }; - api->cbs.at(0)(200, "", noop); - EXPECT_TRUE(orc->has_key( - "bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku")); - EXPECT_EQ(chain->requests_forwarded.size(), 0); -} -TEST_F(GatewayHttpRequestorTest, high_parallel_means_maybe_later) { - auto r = req(); - r->parallel = 8; - t->request(r); - t.reset(); - EXPECT_EQ(api->http_requests_sent.size(), 0); - EXPECT_EQ(api->cbs.size(), 0); - EXPECT_EQ(chain->requests_forwarded.size(), 1); - t.reset(); -} -TEST_F(GatewayHttpRequestorTest, high_parallel_passeswithaffinity) { - auto r = req(); - EXPECT_TRUE(orc); - t->request(r); - EXPECT_EQ(api->http_requests_sent.size(), 1); - EXPECT_EQ(api->cbs.size(), 1); - EXPECT_EQ(chain->requests_forwarded.size(), 0); - EXPECT_EQ(api->http_requests_sent.at(0).url, - "scheme://host/ipfs/" - "bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku"); - auto noop = [](auto) { return std::string{}; }; - api->cbs.at(0)(200, "", noop); - r->parallel = 8; - r->type = ipfs::gw::Type::Car; - r->path = "index.html"; - t->request(r); - EXPECT_EQ(api->http_requests_sent.size(), 2); - EXPECT_EQ(api->cbs.size(), 2); - EXPECT_EQ(chain->requests_forwarded.size(), 0); - EXPECT_EQ(api->http_requests_sent.at(1).url, - "scheme://host/ipfs/" - "bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku/" - "index.html?dag-scope=entity"); -} diff --git a/library/src/ipfs_client/gw/gateway_request.cc b/library/src/ipfs_client/gw/gateway_request.cc index 8149b7cc..a4335a3c 100644 --- a/library/src/ipfs_client/gw/gateway_request.cc +++ b/library/src/ipfs_client/gw/gateway_request.cc @@ -230,6 +230,11 @@ std::string Self::debug_string() const { oss << " plel=" << parallel << '}'; return oss.str(); } +std::string Self::Key() const { + auto rv = main_param; + rv.append(" ").append(name(type)).append(" ").append(path); + return rv; +} bool Self::RespondSuccessfully(std::string_view bytes, std::shared_ptr const& api) { using namespace ipfs::ipld; @@ -288,7 +293,6 @@ bool Self::RespondSuccessfully(std::string_view bytes, LOG(INFO) << "Did not add node from CAR: " << cid_s; } } - VLOG(1) << "Added " << added << " nodes from a CAR."; success = added > 0; break; } diff --git a/library/src/ipfs_client/gw/inline_request_handler.cc b/library/src/ipfs_client/gw/inline_request_handler.cc index 435142a1..b482bfc8 100644 --- a/library/src/ipfs_client/gw/inline_request_handler.cc +++ b/library/src/ipfs_client/gw/inline_request_handler.cc @@ -13,7 +13,6 @@ std::string_view Self::name() const { } auto Self::handle(ipfs::gw::RequestPtr req) -> HandleOutcome { if (req->type != gw::Type::Identity) { - VLOG(2) << ipfs::gw::name(req->type); return HandleOutcome::NOT_HANDLED; } std::string data{req->identity_data()}; diff --git a/library/src/ipfs_client/gw/multi_gateway_requestor.cc b/library/src/ipfs_client/gw/multi_gateway_requestor.cc index 97af40d6..2d1aa39f 100644 --- a/library/src/ipfs_client/gw/multi_gateway_requestor.cc +++ b/library/src/ipfs_client/gw/multi_gateway_requestor.cc @@ -15,7 +15,6 @@ std::string_view Self::name() const { return "multi-gateway requestor"; } auto Self::handle(RequestPtr r) -> HandleOutcome { - VLOG(2) << name() << " handle(" << r->debug_string() << ")"; if (!r->is_http()) { LOG(INFO) << r->debug_string() << " is not an HTTP request."; return HandleOutcome::NOT_HANDLED; @@ -38,7 +37,7 @@ bool Self::Process(RequestPtr const& req) { auto bored = 0U; while (auto gw = api_->GetGateway(config_idx++)) { if (state_iter == state_.end() || state_iter->first > gw->prefix) { - VLOG(1) << "A new gateway has entered the chat: " << gw->prefix << '=' + VLOG(2) << "A new gateway has entered the chat: " << gw->prefix << '=' << gw->rate; // One can insert like this because state_ is std::map w/ stable iterators state_iter = state_.insert({gw->prefix, GatewayState{}}).first; @@ -136,14 +135,18 @@ void Self::HandleResponse(HttpRequestDescription const& desc, i->second.hit(*req); } auto rpm = api_->GetGatewayRate(gw); - api_->SetGatewayRate(gw, rpm + 3); + if (rpm < 15) { + api_->SetGatewayRate(gw, rpm * 2 + 1); + } else { + api_->SetGatewayRate(gw, rpm + 1); + } return; } } auto rpm = api_->GetGatewayRate(gw); if (status == 408 || status == 504 || status == 429 || status == 110 || timed_out) { - LOG(INFO) << gw << " timed out."; + VLOG(1) << gw << " timed out."; if (rpm > 9) { api_->SetGatewayRate(gw, rpm - 4); } else if (rpm) { diff --git a/library/src/ipfs_client/gw/requestor.cc b/library/src/ipfs_client/gw/requestor.cc index 72e6746c..147c8190 100644 --- a/library/src/ipfs_client/gw/requestor.cc +++ b/library/src/ipfs_client/gw/requestor.cc @@ -17,11 +17,10 @@ Self& Self::or_else(std::shared_ptr p) { if (next_) { next_->or_else(p); } else { - VLOG(2) << name() << " is followed by " << p->name(); next_ = p; } if (api_ && !p->api_) { - VLOG(1) << name() << " granting context to " << p->name(); + VLOG(2) << name() << " granting context to " << p->name(); p->api_ = api_; } return *this; diff --git a/library/src/ipfs_client/ipfs_request.cc b/library/src/ipfs_client/ipfs_request.cc index e4f3e1e4..90222a0b 100644 --- a/library/src/ipfs_client/ipfs_request.cc +++ b/library/src/ipfs_client/ipfs_request.cc @@ -23,7 +23,6 @@ void Self::till_next(std::size_t w) { waiting_ = w; } void Self::finish(ipfs::Response& r) { - VLOG(2) << "IpfsRequest::finish(" << waiting_ << ',' << r.status_ << ");"; if (waiting_) { if (--waiting_) { return; diff --git a/library/src/ipfs_client/ipld/directory_shard.cc b/library/src/ipfs_client/ipld/directory_shard.cc index 3ac7e166..a225601d 100644 --- a/library/src/ipfs_client/ipld/directory_shard.cc +++ b/library/src/ipfs_client/ipld/directory_shard.cc @@ -56,9 +56,6 @@ auto Self::resolve_internal(ipfs::ipld::DirShard::HashIter hash_b, LOG(ERROR) << "Ran out of hash bits."; return ProvenAbsent{}; } - VLOG(2) << "Found hash chunk, continuing to next level of HAMT sharded " - "directory " - << name << "->" << link.cid; return downcast->resolve_internal(std::next(hash_b), hash_e, human_name, parms); } else { diff --git a/library/src/ipfs_client/ipld/root.cc b/library/src/ipfs_client/ipld/root.cc index e08afc54..fd5af1b2 100644 --- a/library/src/ipfs_client/ipld/root.cc +++ b/library/src/ipfs_client/ipld/root.cc @@ -21,7 +21,6 @@ Ptr Self::rooted() { auto Self::resolve(ResolutionState& params) -> ResolveResult { auto location = params.PathToResolve().to_string(); - VLOG(2) << "Root " << params.MyPath() << " resolving " << location; auto result = deroot()->resolve(params); if (auto pc = std::get_if(&result)) { auto lower = params.WithPath(pc->new_path); diff --git a/library/src/ipfs_client/ipld/small_directory.cc b/library/src/ipfs_client/ipld/small_directory.cc index bae13675..39c66f22 100644 --- a/library/src/ipfs_client/ipld/small_directory.cc +++ b/library/src/ipfs_client/ipld/small_directory.cc @@ -13,10 +13,8 @@ using namespace std::literals; using Self = ipfs::ipld::SmallDirectory; auto Self::resolve(ResolutionState& params) -> ResolveResult { - VLOG(1) << "dir(" << params.MyPath() << " // " << params.PathToResolve() - << ")"; if (params.IsFinalComponent()) { - LOG(INFO) << "Directory listing requested for " << params.MyPath(); + VLOG(2) << "Directory listing requested for " << params.MyPath(); auto result = CallChild(params, "index.html"); if (auto resp = std::get_if(&result)) { resp->mime_ = "text/html"; diff --git a/library/src/ipfs_client/ipns_record.cc b/library/src/ipfs_client/ipns_record.cc index 86be780f..81e52065 100644 --- a/library/src/ipfs_client/ipns_record.cc +++ b/library/src/ipfs_client/ipns_record.cc @@ -201,8 +201,8 @@ auto ipfs::ValidateIpnsRecord(ipfs::ByteView top_level_bytes, << ") and V2(" << result.ttl << ')'; return {}; } - LOG(INFO) << "IPNS record verification passes for " << name.to_string() - << " sequence: " << result.sequence << " points at " + VLOG(1) << "IPNS record verification passes for " << name.to_string() + << " sequence: " << result.sequence << " points at " << result.value; return result; } diff --git a/library/src/ipfs_client/orchestrator.cc b/library/src/ipfs_client/orchestrator.cc index b66cfb15..45a4bec9 100644 --- a/library/src/ipfs_client/orchestrator.cc +++ b/library/src/ipfs_client/orchestrator.cc @@ -23,7 +23,6 @@ void Self::build_response(std::shared_ptr req) { return; } auto req_path = req->path(); - VLOG(1) << "build_response(" << req_path.to_string() << ')'; req_path.pop(); // namespace std::string affinity{req_path.pop()}; auto it = dags_.find(affinity); @@ -32,7 +31,7 @@ void Self::build_response(std::shared_ptr req) { build_response(req); } } else { - VLOG(1) << "Requesting root " << affinity << " resolve path " + VLOG(2) << "Requesting root " << affinity << " resolve path " << req_path.to_string(); auto root = it->second->rooted(); if (root != it->second) { @@ -61,10 +60,10 @@ void Self::from_tree(std::shared_ptr req, << response->body_.size() << " bytes."; if (response->mime_.empty() && !response->body_.empty()) { if (response->location_.empty()) { - LOG(INFO) << "Request for " << req->path() - << " returned no location, so sniffing from request path and " - "body of " - << response->body_.size() << "B."; + VLOG(1) << "Request for " << req->path() + << " returned no location, so sniffing from request path and " + "body of " + << response->body_.size() << "B."; response->mime_ = sniff(req->path(), response->body_); } else { std::string hit_path{req->path().pop_n(2)}; @@ -94,7 +93,7 @@ void Self::from_tree(std::shared_ptr req, auto& mps = std::get(result).ipfs_abs_paths_; req->till_next(mps.size()); for (auto& mp : mps) { - VLOG(1) << "Attempt to resolve " << relative_path << " for " + VLOG(2) << "Attempt to resolve " << relative_path << " for " << req->path() << " leads to request for " << mp; } if (std::any_of(mps.begin(), mps.end(), [this, &req, &affinity](auto& p) { @@ -108,7 +107,7 @@ bool Self::gw_request(std::shared_ptr ir, ipfs::SlashDelimited path, std::string const& aff) { auto req = gw::GatewayRequest::fromIpfsPath(path); - VLOG(1) << "Seeking " << path.to_string() << " -> " << req->debug_string(); + VLOG(2) << "Seeking " << path.to_string() << " -> " << req->debug_string(); if (req) { req->dependent = ir; req->orchestrator(shared_from_this()); diff --git a/library/src/vocab/slash_delimited.cc b/library/src/vocab/slash_delimited.cc index c81ae582..48aa806e 100644 --- a/library/src/vocab/slash_delimited.cc +++ b/library/src/vocab/slash_delimited.cc @@ -1,7 +1,5 @@ #include -#include "log_macros.h" - #include #if __has_include() @@ -92,6 +90,7 @@ std::ostream& operator<<(std::ostream& str, ipfs::SlashDelimited const& sd) { return str << sd.to_view(); } +#ifndef NACL_TC_REV #if __has_include() #include @@ -115,3 +114,4 @@ LogMessage& operator<<(LogMessage& str, ipfs::SlashDelimited const& sd) { #endif #endif +#endif diff --git a/test_data/blocks/QmRRT1NeNR46UNzqJR6aTGRuttP2znm52awaTHoXath28F b/test_data/blocks/QmRRT1NeNR46UNzqJR6aTGRuttP2znm52awaTHoXath28F deleted file mode 100644 index ac42b33d..00000000 --- a/test_data/blocks/QmRRT1NeNR46UNzqJR6aTGRuttP2znm52awaTHoXath28F +++ /dev/null @@ -1,2 +0,0 @@ - -˜Rs8 Rs9 Rt0 Rt1 Rt2 Rt3 Rt4 Rt5 Rt6 Rt7 Rt8 Rt9 Ru0 Ru1 Ru2 Ru3 Ru4 Ru5 Ru6 Ru7 Ru8 Ru9 Rv0 Rv1 Rv2 Rv3 Rv4 Rv5 Rv6 Rv7 Rv8 Rv9 Rw0 Rw1 Rw2 Rw3  \ No newline at end of file diff --git a/test_data/blocks/QmRSytrPEhVpkkrGiwNEYZiNysijGMpeuLfvN4gUc7e8iB b/test_data/blocks/QmRSytrPEhVpkkrGiwNEYZiNysijGMpeuLfvN4gUc7e8iB deleted file mode 100644 index 42f4e5d9..00000000 --- a/test_data/blocks/QmRSytrPEhVpkkrGiwNEYZiNysijGMpeuLfvN4gUc7e8iB +++ /dev/null @@ -1,2 +0,0 @@ - -˜Mw8 Mw9 Mx0 Mx1 Mx2 Mx3 Mx4 Mx5 Mx6 Mx7 Mx8 Mx9 My0 My1 My2 My3 My4 My5 My6 My7 My8 My9 Mz0 Mz1 Mz2 Mz3 Mz4 Mz5 Mz6 Mz7 Mz8 Mz9 Na0 Na1 Na2 Na3  \ No newline at end of file