1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/chrome/browser/net/retryable_url_fetcher.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "net/http/http_status_code.h"
11 #include "net/url_request/url_fetcher.h"
12 #include "net/url_request/url_fetcher_delegate.h"
13 #include "net/url_request/url_request_context_getter.h"
16 @interface RetryableURLFetcher ()
17 - (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher;
20 class URLRequestDelegate : public net::URLFetcherDelegate {
22 explicit URLRequestDelegate(RetryableURLFetcher* owner) : owner_(owner) {}
23 void OnURLFetchComplete(const net::URLFetcher* source) override {
24 [owner_ urlFetchDidComplete:source];
28 RetryableURLFetcher* owner_; // Weak.
31 @implementation RetryableURLFetcher {
32 scoped_refptr<net::URLRequestContextGetter> requestContextGetter_;
33 scoped_ptr<URLRequestDelegate> fetcherDelegate_;
34 scoped_ptr<net::URLFetcher> fetcher_;
35 scoped_ptr<net::BackoffEntry> backoffEntry_;
37 id<RetryableURLFetcherDelegate> delegate_; // Weak.
41 initWithRequestContextGetter:(net::URLRequestContextGetter*)context
42 delegate:(id<RetryableURLFetcherDelegate>)delegate
43 backoffPolicy:(const net::BackoffEntry::Policy*)policy {
48 requestContextGetter_ = context;
51 backoffEntry_.reset(new net::BackoffEntry(policy));
57 DCHECK(requestContextGetter_.get());
58 GURL url(base::SysNSStringToUTF8([delegate_ urlToFetch]));
60 fetcherDelegate_.reset(new URLRequestDelegate(self));
61 fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET,
62 fetcherDelegate_.get());
63 fetcher_->SetRequestContext(requestContextGetter_.get());
69 return backoffEntry_ ? backoffEntry_->failure_count() : 0;
72 - (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher {
73 BOOL success = fetcher->GetResponseCode() == net::HTTP_OK;
74 if (!success && backoffEntry_) {
75 backoffEntry_->InformOfRequest(false);
76 double nextRetry = backoffEntry_->GetTimeUntilRelease().InSecondsF();
77 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, nextRetry * NSEC_PER_SEC),
78 dispatch_get_main_queue(), ^{
83 NSString* response = nil;
85 std::string responseString;
86 if (fetcher->GetResponseAsString(&responseString))
87 response = base::SysUTF8ToNSString(responseString);
89 [delegate_ processSuccessResponse:response];