diff --git a/browser/ipfs/test/ipns_keys_manager_browsertest.cc b/browser/ipfs/test/ipns_keys_manager_browsertest.cc index 3acb7e789308..abe07251f27a 100644 --- a/browser/ipfs/test/ipns_keys_manager_browsertest.cc +++ b/browser/ipfs/test/ipns_keys_manager_browsertest.cc @@ -18,6 +18,7 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/network_session_configurator/common/network_switches.h" #include "content/public/test/browser_test.h" +#include "net/base/net_errors.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" @@ -229,4 +230,18 @@ IN_PROC_BROWSER_TEST_F(IpnsManagerBrowserTest, ImportKey) { run_loop.Run(); } +IN_PROC_BROWSER_TEST_F(IpnsManagerBrowserTest, LoadKeysRetry) { + base::RunLoop run_loop; + auto* ipns_manager = ipfs_service()->GetIpnsKeysManager(); + ipns_manager->LoadKeys(base::BindOnce( + [](base::OnceCallback launch_callback, const bool success) { + ASSERT_FALSE(success); + if (launch_callback) + std::move(launch_callback).Run(); + }, + run_loop.QuitClosure())); + run_loop.Run(); + EXPECT_EQ(ipns_manager->GetLastLoadRetryForTest(), 0); +} + } // namespace ipfs diff --git a/components/ipfs/keys/ipns_keys_manager.cc b/components/ipfs/keys/ipns_keys_manager.cc index dde0125e3ebd..fc2d01679644 100644 --- a/components/ipfs/keys/ipns_keys_manager.cc +++ b/components/ipfs/keys/ipns_keys_manager.cc @@ -9,6 +9,7 @@ #include #include +#include "base/rand_util.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "brave/components/ipfs/blob_context_getter_factory.h" @@ -26,6 +27,29 @@ #include "storage/browser/blob/blob_data_builder.h" #include "storage/browser/blob/blob_data_handle.h" +namespace { + +// Retry after some time If local node responded with error. +// The keys are often called immediately after startup +// and node initialization may take some time. +constexpr int kDefaultRetries = 5; + +// Used to retry requests if we got error from ipfs node, +// it may fail requests sometimes right after launch, +// Actual value will be generated randomly in range +// (kMinimalRequestRetryIntervalMs, +// kRequetsRetryRate*kMinimalRequestRetryIntervalMs) +const int kMinimalRequestRetryIntervalMs = 350; +const int kRequetsRetryRate = 3; + +base::TimeDelta CalculateKeysRetryTime() { + return base::TimeDelta::FromMilliseconds( + base::RandInt(kMinimalRequestRetryIntervalMs, + kRequetsRetryRate * kMinimalRequestRetryIntervalMs)); +} + +} // namespace + namespace ipfs { IpnsKeysManager::IpnsKeysManager( @@ -164,13 +188,17 @@ void IpnsKeysManager::LoadKeys(LoadKeysCallback callback) { if (callback) pending_load_callbacks_.push(std::move(callback)); + LoadKeysInternal(kDefaultRetries); +} + +void IpnsKeysManager::LoadKeysInternal(int retries) { auto url_loader = CreateURLLoader(server_endpoint_.Resolve(kAPIKeyListEndpoint), "POST"); auto iter = url_loaders_.insert(url_loaders_.begin(), std::move(url_loader)); - iter->get()->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - url_loader_factory_, base::BindOnce(&IpnsKeysManager::OnKeysLoaded, - weak_factory_.GetWeakPtr(), iter)); + url_loader_factory_, + base::BindOnce(&IpnsKeysManager::OnKeysLoaded, weak_factory_.GetWeakPtr(), + iter, retries)); } void IpnsKeysManager::UploadData( @@ -226,6 +254,7 @@ void IpnsKeysManager::OnIpfsShutdown() { } void IpnsKeysManager::OnKeysLoaded(SimpleURLLoaderList::iterator iter, + int retry_number, std::unique_ptr response_body) { auto* url_loader = iter->get(); int error_code = url_loader->NetError(); @@ -233,6 +262,15 @@ void IpnsKeysManager::OnKeysLoaded(SimpleURLLoaderList::iterator iter, if (url_loader->ResponseInfo() && url_loader->ResponseInfo()->headers) response_code = url_loader->ResponseInfo()->headers->response_code(); url_loaders_.erase(iter); + last_load_retry_value_for_test_ = retry_number; + if (error_code == net::ERR_CONNECTION_REFUSED && retry_number) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&IpnsKeysManager::LoadKeysInternal, + weak_factory_.GetWeakPtr(), retry_number - 1), + CalculateKeysRetryTime()); + return; + } bool success = (error_code == net::OK && response_code == net::HTTP_OK); std::unordered_map new_keys; @@ -247,6 +285,10 @@ void IpnsKeysManager::OnKeysLoaded(SimpleURLLoaderList::iterator iter, NotifyKeysLoaded(success); } +int IpnsKeysManager::GetLastLoadRetryForTest() const { + return last_load_retry_value_for_test_; +} + void IpnsKeysManager::SetLoadCallbackForTest(LoadKeysCallback callback) { if (callback) pending_load_callbacks_.push(std::move(callback)); diff --git a/components/ipfs/keys/ipns_keys_manager.h b/components/ipfs/keys/ipns_keys_manager.h index 23fc3ca97463..5fc4c67f9c58 100644 --- a/components/ipfs/keys/ipns_keys_manager.h +++ b/components/ipfs/keys/ipns_keys_manager.h @@ -62,6 +62,7 @@ class IpnsKeysManager : public IpfsServiceObserver { ImportKeyCallback callback); void SetServerEndpointForTest(const GURL& gurl); void SetLoadCallbackForTest(LoadKeysCallback callback); + int GetLastLoadRetryForTest() const; private: using SimpleURLLoaderList = @@ -81,14 +82,16 @@ class IpnsKeysManager : public IpfsServiceObserver { RemoveKeyCallback callback, std::unique_ptr response_body); void OnKeysLoaded(SimpleURLLoaderList::iterator iter, + int retry_number, std::unique_ptr response_body); void NotifyKeysLoaded(bool result); - + void LoadKeysInternal(int retries); void UploadData(ImportKeyCallback callback, const std::string& name, std::unique_ptr request); + int last_load_retry_value_for_test_ = -1; BlobContextGetterFactory* blob_context_getter_factory_ = nullptr; network::mojom::URLLoaderFactory* url_loader_factory_; SimpleURLLoaderList url_loaders_;