blob: f1e9b17221ff49510a72fa6c3239694f31e7fc22 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/net/retryable_url_fetcher.h"
#include <memory>
#include "base/bind.h"
#include "base/check.h"
#include "base/strings/sys_string_conversions.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface RetryableURLFetcher ()
- (void)urlFetchDidComplete:(std::unique_ptr<std::string>)response_body;
@end
@implementation RetryableURLFetcher {
scoped_refptr<network::SharedURLLoaderFactory> _shared_url_loader_factory;
std::unique_ptr<net::BackoffEntry> _backoffEntry;
std::unique_ptr<network::SimpleURLLoader> _simple_loader;
int _retryCount;
__weak id<RetryableURLFetcherDelegate> _delegate;
}
- (instancetype)
initWithURLLoaderFactory:
(scoped_refptr<network::SharedURLLoaderFactory>)shared_url_loader_factory
delegate:(id<RetryableURLFetcherDelegate>)delegate
backoffPolicy:(const net::BackoffEntry::Policy*)policy {
self = [super init];
if (self) {
DCHECK(shared_url_loader_factory);
DCHECK(delegate);
_shared_url_loader_factory = shared_url_loader_factory;
_delegate = delegate;
if (policy)
_backoffEntry.reset(new net::BackoffEntry(policy));
}
return self;
}
- (void)startFetch {
DCHECK(_shared_url_loader_factory.get());
GURL url(base::SysNSStringToUTF8([_delegate urlToFetch]));
if (url.is_valid()) {
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = url;
_simple_loader = network::SimpleURLLoader::Create(
std::move(resource_request), NO_TRAFFIC_ANNOTATION_YET);
_simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
_shared_url_loader_factory.get(),
base::BindOnce(^(std::unique_ptr<std::string> response) {
[self urlFetchDidComplete:std::forward<std::unique_ptr<std::string>>(
response)];
}));
} else {
// Invalid URLs returned from delegate method are considered a permanent
// failure. Delegate method is called with nil to indicate failure.
[_delegate processSuccessResponse:nil];
}
}
- (int)failureCount {
return _backoffEntry ? _backoffEntry->failure_count() : 0;
}
- (void)urlFetchDidComplete:(std::unique_ptr<std::string>)response_body {
if (!response_body && _backoffEntry) {
_backoffEntry->InformOfRequest(false);
double nextRetry = _backoffEntry->GetTimeUntilRelease().InSecondsF();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nextRetry * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
[self startFetch];
});
return;
}
NSString* response = nil;
if (response_body)
response = base::SysUTF8ToNSString(*response_body);
[_delegate processSuccessResponse:response];
}
@end