Skip to content

Commit

Permalink
Fix x-ipfs-path handling
Browse files Browse the repository at this point in the history
Resolves brave/brave-browser#25281
Autoredirect to dnslink only if url has _dnslink DNS record.
_dnslink has priority over x-ipfs-path content.
When there is only x-ipfs-path header then translate url to
https://gateway/<x-ipfs-path-content> instead of ipns://original_url
  • Loading branch information
cypt4 committed Sep 26, 2022
1 parent 65e6fc9 commit 19bb25f
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 159 deletions.
3 changes: 3 additions & 0 deletions browser/ipfs/ipfs_host_resolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ void IPFSHostResolver::OnComplete(
if (result != net::OK) {
VLOG(1) << "DNS resolving error:" << net::ErrorToString(result)
<< " for host: " << prefix_ + resolving_host_;
if (resolved_callback_) {
std::move(resolved_callback_).Run(resolving_host_, absl::nullopt);
}
}
if (complete_callback_for_testing_)
std::move(complete_callback_for_testing_).Run();
Expand Down
2 changes: 1 addition & 1 deletion browser/ipfs/ipfs_host_resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class IPFSHostResolver : public network::ResolveHostClientBase {

using HostTextResultsCallback =
base::OnceCallback<void(const std::string& host,
const std::string& dnslink)>;
const absl::optional<std::string>& dnslink)>;

virtual void Resolve(const net::HostPortPair& host,
const net::NetworkIsolationKey& isolation_key,
Expand Down
11 changes: 7 additions & 4 deletions browser/ipfs/ipfs_host_resolver_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class IPFSHostResolverTest : public testing::Test {
void HostResolvedCallback(base::OnceClosure callback,
const std::string& expected_host,
const std::string& host,
const std::string& dnslink) {
const absl::optional<std::string>& dnslink) {
EXPECT_EQ(expected_host, host);
resolved_callback_called_++;
if (callback)
Expand Down Expand Up @@ -218,7 +218,9 @@ TEST_F(IPFSHostResolverTest, SuccessOnReuse) {
net::DnsQueryType::TXT,
base::BindOnce(
[](const std::string& expected_host, const std::string& host,
const std::string& dnslink) { EXPECT_EQ(expected_host, host); },
const absl::optional<std::string>& dnslink) {
EXPECT_EQ(expected_host, host);
},
host));
EXPECT_EQ(fake_host_resolver_raw->resolve_host_called(), 1);
EXPECT_EQ(resolved_callback_called(), 1);
Expand All @@ -239,8 +241,9 @@ TEST_F(IPFSHostResolverTest, ResolutionFailed) {
ipfs_resolver.Resolve(
net::HostPortPair(host, 11), net::NetworkIsolationKey(),
net::DnsQueryType::TXT,
base::BindOnce([](const std::string& host, const std::string& dnslink) {
NOTREACHED();
base::BindOnce([](const std::string& host,
const absl::optional<std::string>& dnslink) {
EXPECT_FALSE(dnslink);
}));
run_loop.Run();
EXPECT_EQ(ipfs_resolver.host(), host);
Expand Down
90 changes: 49 additions & 41 deletions browser/ipfs/ipfs_tab_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,16 @@ bool IPFSTabHelper::MaybeCreateForWebContents(
return true;
}

void IPFSTabHelper::IPFSLinkResolved(const GURL& ipfs) {
void IPFSTabHelper::XIPFSPathLinkResolved(const GURL& ipfs) {
ipfs_resolved_url_ = ipfs;
if (pref_service_->GetBoolean(kIPFSAutoRedirectDNSLink)) {
UpdateLocationBar();
}

void IPFSTabHelper::DNSLinkResolved(const GURL& ipfs) {
ipfs_resolved_url_ = ipfs;
DCHECK(ipfs.is_empty() || ipfs.SchemeIs(kIPNSScheme));
if (pref_service_->GetBoolean(kIPFSAutoRedirectDNSLink) &&
!ipfs_resolved_url_.is_empty()) {
content::OpenURLParams params(GetIPFSResolvedURL(), content::Referrer(),
WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_LINK, false);
Expand All @@ -107,18 +114,23 @@ void IPFSTabHelper::IPFSLinkResolved(const GURL& ipfs) {
UpdateLocationBar();
}

void IPFSTabHelper::HostResolvedCallback(const std::string& host,
const std::string& dnslink) {
void IPFSTabHelper::HostResolvedCallback(
absl::optional<std::string> x_ipfs_path_header,
const std::string& host,
const absl::optional<std::string>& dnslink) {
GURL current = web_contents()->GetURL();

if (current.host() != host || !current.SchemeIsHTTPOrHTTPS())
return;
if (dnslink.empty())
if (!dnslink || dnslink.value().empty()) {
if (x_ipfs_path_header) {
XIPFSPathLinkResolved(ResolveXIPFSPathUrl(x_ipfs_path_header.value()));
}
return;
GURL::Replacements replacements;
replacements.SetSchemeStr(kIPNSScheme);
GURL resolved_url(current.ReplaceComponents(replacements));
}
GURL resolved_url = ResolveDNSLinkUrl(current);
if (resolved_url.is_valid())
IPFSLinkResolved(resolved_url);
DNSLinkResolved(resolved_url);
}

void IPFSTabHelper::UpdateLocationBar() {
Expand All @@ -143,15 +155,17 @@ GURL IPFSTabHelper::GetIPFSResolvedURL() const {
return ipfs_resolved_url_.ReplaceComponents(replacements);
}

void IPFSTabHelper::ResolveIPFSLink() {
void IPFSTabHelper::CheckDNSLinkRecord(
absl::optional<std::string> x_ipfs_path_header) {
GURL current = web_contents()->GetURL();
if (!current.SchemeIsHTTPOrHTTPS())
return;

const auto& host_port_pair = net::HostPortPair::FromURL(current);

auto resolved_callback = base::BindOnce(&IPFSTabHelper::HostResolvedCallback,
weak_ptr_factory_.GetWeakPtr());
weak_ptr_factory_.GetWeakPtr(),
std::move(x_ipfs_path_header));
const auto& key =
web_contents()->GetPrimaryMainFrame()
? web_contents()->GetPrimaryMainFrame()->GetNetworkIsolationKey()
Expand Down Expand Up @@ -196,48 +210,42 @@ bool IPFSTabHelper::CanResolveURL(const GURL& url) const {
return resolve;
}

std::string IPFSTabHelper::GetPathForDNSLink(GURL url) {
if (ipfs::IsIPFSScheme(url)) {
std::string path = url.path();
if (base::StartsWith(path, "//"))
return path.substr(1, path.size());
return path;
}
return "/ipns/" + url.host() + url.path();
}
// For DNSLink we are making urls like
// <gateway>/ipns/<dnslink-domain>/<dnslink-path>
GURL IPFSTabHelper::ResolveDNSLinkURL(GURL url) {
if (!url.is_valid())
return url;
// For x-ipfs-path header we are making urls like
// <gateway>/<x-ipfs-path>
GURL IPFSTabHelper::ResolveXIPFSPathUrl(
const std::string& x_ipfs_path_header_value) {
GURL gateway =
ipfs::GetConfiguredBaseGateway(pref_service_, chrome::GetChannel());
GURL::Replacements replacements;
auto path = GetPathForDNSLink(url);
replacements.SetPathStr(path);
replacements.SetPathStr(x_ipfs_path_header_value);
return gateway.ReplaceComponents(replacements);
}

void IPFSTabHelper::MaybeShowDNSLinkButton(
// For _dnslink we just translate url to ipns:// scheme
GURL IPFSTabHelper::ResolveDNSLinkUrl(const GURL& url) {
GURL::Replacements replacements;
replacements.SetSchemeStr(kIPNSScheme);
return url.ReplaceComponents(replacements);
}

void IPFSTabHelper::MaybeCheckDNSLinkRecord(
const net::HttpResponseHeaders* headers) {
UpdateDnsLinkButtonState();
auto current_url = GetCurrentPageURL();

if (!IsDNSLinkCheckEnabled() || !headers || ipfs_resolved_url_.is_valid() ||
!CanResolveURL(current_url))
!CanResolveURL(current_url)) {
return;
}

int response_code = headers->response_code();
if (response_code >= net::HttpStatusCode::HTTP_INTERNAL_SERVER_ERROR &&
response_code <= net::HttpStatusCode::HTTP_VERSION_NOT_SUPPORTED) {
ResolveIPFSLink();
} else if (headers->HasHeader(kIfpsPathHeader)) {
std::string ipfs_path_value;
if (!headers->GetNormalizedHeader(kIfpsPathHeader, &ipfs_path_value) ||
ipfs_path_value.empty())
return;
auto resolved_url = ResolveDNSLinkURL(current_url);
if (resolved_url.is_valid())
IPFSLinkResolved(resolved_url);
std::string normalized_header;
if ((response_code >= net::HttpStatusCode::HTTP_INTERNAL_SERVER_ERROR &&
response_code <= net::HttpStatusCode::HTTP_VERSION_NOT_SUPPORTED)) {
CheckDNSLinkRecord(absl::nullopt);
} else if (headers->GetNormalizedHeader(kIfpsPathHeader,
&normalized_header)) {
CheckDNSLinkRecord(normalized_header);
}
}

Expand Down Expand Up @@ -265,7 +273,7 @@ void IPFSTabHelper::DidFinishNavigation(content::NavigationHandle* handle) {
handle->GetResponseHeaders()->HasHeader(kIfpsPathHeader)) {
MaybeSetupIpfsProtocolHandlers(handle->GetURL());
}
MaybeShowDNSLinkButton(handle->GetResponseHeaders());
MaybeCheckDNSLinkRecord(handle->GetResponseHeaders());
}

WEB_CONTENTS_USER_DATA_KEY_IMPL(IPFSTabHelper);
Expand Down
42 changes: 33 additions & 9 deletions browser/ipfs/ipfs_tab_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,44 @@ class IPFSTabHelper : public content::WebContentsObserver,

private:
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest, CanResolveURLTest);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest, URLResolvingTest);
FRIEND_TEST_ALL_PREFIXES(
IpfsTabHelperUnitTest,
TranslateUrlToIpns_When_HasDNSLinkRecord_AndXIPFSPathHeader);
FRIEND_TEST_ALL_PREFIXES(
IpfsTabHelperUnitTest,
TranslateUrlToIpns_When_HasDNSLinkRecord_AndOriginalPageFails_500);
FRIEND_TEST_ALL_PREFIXES(
IpfsTabHelperUnitTest,
TranslateUrlToIpns_When_HasDNSLinkRecord_AndOriginalPageFails_400);
FRIEND_TEST_ALL_PREFIXES(
IpfsTabHelperUnitTest,
TranslateUrlToIpns_When_HasDNSLinkRecord_AndOriginalPageFails_505);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest,
DoNotTranslateUrlToIpns_When_NoDNSLinkRecord);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest,
DoNotTranslateUrlToIpns_When_NoHeader_And_NoError);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest,
DNSLinkRecordResolved_AutoRedirectDNSLink);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest,
XIpfsPathHeaderUsed_IfNoDnsLinkRecord_IPFS);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest,
XIpfsPathHeaderUsed_IfNoDnsLinkRecord_IPNS);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest, ResolveXIPFSPathUrl);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest, GatewayResolving);
FRIEND_TEST_ALL_PREFIXES(IpfsTabHelperUnitTest, ResolveDNSLinkURL);

friend class content::WebContentsUserData<IPFSTabHelper>;
explicit IPFSTabHelper(content::WebContents* web_contents);

GURL GetCurrentPageURL() const;
bool CanResolveURL(const GURL& url) const;
bool IsDNSLinkCheckEnabled() const;
void IPFSLinkResolved(const GURL& ipfs);
void MaybeShowDNSLinkButton(const net::HttpResponseHeaders* headers);
void XIPFSPathLinkResolved(const GURL& ipfs);
void DNSLinkResolved(const GURL& ipfs);
void MaybeCheckDNSLinkRecord(const net::HttpResponseHeaders* headers);
void UpdateDnsLinkButtonState();
GURL ResolveDNSLinkURL(GURL url);

GURL ResolveDNSLinkUrl(const GURL& url);
GURL ResolveXIPFSPathUrl(const std::string& x_ipfs_path_header_value);

void MaybeSetupIpfsProtocolHandlers(const GURL& url);

Expand All @@ -76,10 +100,10 @@ class IPFSTabHelper : public content::WebContentsObserver,
content::NavigationHandle* navigation_handle) override;
void UpdateLocationBar();

void ResolveIPFSLink();
std::string GetPathForDNSLink(GURL url);
void HostResolvedCallback(const std::string& host,
const std::string& dnslink);
void CheckDNSLinkRecord(absl::optional<std::string> x_ipfs_path_header);
void HostResolvedCallback(absl::optional<std::string> x_ipfs_path_header,
const std::string& host,
const absl::optional<std::string>& dnslink);

PrefService* pref_service_ = nullptr;
PrefChangeRegistrar pref_change_registrar_;
Expand Down
Loading

0 comments on commit 19bb25f

Please sign in to comment.