diff options
author | droger <droger@chromium.org> | 2015-04-03 02:40:46 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-03 09:41:19 +0000 |
commit | f1ba207ccc66eb006b3e51822879926a08629d56 (patch) | |
tree | 4e8c376f0327a1a4e1be52e13300eacdc100050b /ios | |
parent | a014946a9df19ed6296c36e3142d9271d137de24 (diff) | |
download | chromium_src-f1ba207ccc66eb006b3e51822879926a08629d56.zip chromium_src-f1ba207ccc66eb006b3e51822879926a08629d56.tar.gz chromium_src-f1ba207ccc66eb006b3e51822879926a08629d56.tar.bz2 |
[iOS] Upstream //ios/chrome/browser/net
Review URL: https://codereview.chromium.org/1052873004
Cr-Commit-Position: refs/heads/master@{#323718}
Diffstat (limited to 'ios')
-rw-r--r-- | ios/chrome/DEPS | 2 | ||||
-rw-r--r-- | ios/chrome/browser/browsing_data_change_listening.h | 14 | ||||
-rw-r--r-- | ios/chrome/browser/net/OWNERS | 1 | ||||
-rw-r--r-- | ios/chrome/browser/net/chrome_cookie_store_ios_client.h | 34 | ||||
-rw-r--r-- | ios/chrome/browser/net/chrome_cookie_store_ios_client.mm | 30 | ||||
-rw-r--r-- | ios/chrome/browser/net/metrics_network_client.h | 19 | ||||
-rw-r--r-- | ios/chrome/browser/net/metrics_network_client.mm | 95 | ||||
-rw-r--r-- | ios/chrome/browser/net/metrics_network_client_manager.h | 39 | ||||
-rw-r--r-- | ios/chrome/browser/net/metrics_network_client_manager.mm | 137 | ||||
-rw-r--r-- | ios/chrome/browser/net/metrics_network_client_unittest.mm | 72 | ||||
-rw-r--r-- | ios/chrome/browser/net/retryable_url_fetcher.h | 48 | ||||
-rw-r--r-- | ios/chrome/browser/net/retryable_url_fetcher.mm | 92 | ||||
-rw-r--r-- | ios/chrome/browser/net/retryable_url_fetcher_unittest.mm | 103 | ||||
-rw-r--r-- | ios/chrome/ios_chrome.gyp | 10 | ||||
-rw-r--r-- | ios/chrome/ios_chrome_tests.gyp | 2 |
15 files changed, 698 insertions, 0 deletions
diff --git a/ios/chrome/DEPS b/ios/chrome/DEPS index f809f8d..f23eea2 100644 --- a/ios/chrome/DEPS +++ b/ios/chrome/DEPS @@ -6,6 +6,7 @@ include_rules = [ "+components/autofill/core/browser", "+components/autofill/ios/browser", + "+components/data_reduction_proxy/core/common", "+components/dom_distiller/core", "+components/dom_distiller/ios", "+components/infobars/core", @@ -17,6 +18,7 @@ include_rules = [ "+components/translate/ios", "+components/web_resource", "+components/webp_transcode", + "+ios/net", "+ios/public/provider/chrome", "+ios/web/public", "+net", diff --git a/ios/chrome/browser/browsing_data_change_listening.h b/ios/chrome/browser/browsing_data_change_listening.h new file mode 100644 index 0000000..2c0afe8 --- /dev/null +++ b/ios/chrome/browser/browsing_data_change_listening.h @@ -0,0 +1,14 @@ +// 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. + +#ifndef IOS_CHROME_BROWSER_BROWSING_DATA_CHANGE_LISTENING_H_ +#define IOS_CHROME_BROWSER_BROWSING_DATA_CHANGE_LISTENING_H_ + +// Listener for changes in browsing data. +@protocol BrowsingDataChangeListening +// Called when cookie storage is changed. Can be called on a background thread. +- (void)didChangeCookieStorage; +@end + +#endif // IOS_CHROME_BROWSER_BROWSING_DATA_CHANGE_LISTENING_H_ diff --git a/ios/chrome/browser/net/OWNERS b/ios/chrome/browser/net/OWNERS new file mode 100644 index 0000000..ed94051 --- /dev/null +++ b/ios/chrome/browser/net/OWNERS @@ -0,0 +1 @@ +droger@chromium.org diff --git a/ios/chrome/browser/net/chrome_cookie_store_ios_client.h b/ios/chrome/browser/net/chrome_cookie_store_ios_client.h new file mode 100644 index 0000000..54ed312 --- /dev/null +++ b/ios/chrome/browser/net/chrome_cookie_store_ios_client.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef IOS_CHROME_BROWSER_NET_CHROME_COOKIE_STORE_IOS_CLIENT_H_ +#define IOS_CHROME_BROWSER_NET_CHROME_COOKIE_STORE_IOS_CLIENT_H_ + +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "ios/net/cookies/cookie_store_ios_client.h" + +@protocol BrowsingDataChangeListening; + +// Chrome implementation of net::CookieStoreIOSClient. This class lives on the +// IOThread. +class ChromeCookieStoreIOSClient : public net::CookieStoreIOSClient { + public: + // Creates a CookieStoreIOSClient with a BrowsingDataChangeListening. + // |browsing_data_change_listener| cannot be nil. + explicit ChromeCookieStoreIOSClient( + id<BrowsingDataChangeListening> browsing_data_change_listener); + + // CookieStoreIOSClient implementation. + void DidChangeCookieStorage() const override; + scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override; + + private: + base::ThreadChecker thread_checker_; + // The listener that is informed of change in browsing data. + id<BrowsingDataChangeListening> browsing_data_change_listener_; // Weak. + DISALLOW_COPY_AND_ASSIGN(ChromeCookieStoreIOSClient); +}; + +#endif // IOS_CHROME_BROWSER_NET_CHROME_COOKIE_STORE_IOS_CLIENT_H_ diff --git a/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm b/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm new file mode 100644 index 0000000..fb0b8f0 --- /dev/null +++ b/ios/chrome/browser/net/chrome_cookie_store_ios_client.mm @@ -0,0 +1,30 @@ +// 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. + +#include "ios/chrome/browser/net/chrome_cookie_store_ios_client.h" + +#include "base/logging.h" +#import "ios/chrome/browser/browsing_data_change_listening.h" +#include "ios/web/public/web_thread.h" + +ChromeCookieStoreIOSClient::ChromeCookieStoreIOSClient( + id<BrowsingDataChangeListening> browsing_data_change_listener) + : browsing_data_change_listener_(browsing_data_change_listener) { + DCHECK(browsing_data_change_listener); + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO); +} + +void ChromeCookieStoreIOSClient::DidChangeCookieStorage() const { + DCHECK(thread_checker_.CalledOnValidThread()); + + [browsing_data_change_listener_ didChangeCookieStorage]; +} + +scoped_refptr<base::SequencedTaskRunner> +ChromeCookieStoreIOSClient::GetTaskRunner() const { + DCHECK(thread_checker_.CalledOnValidThread()); + + base::SequencedWorkerPool* pool = web::WebThread::GetBlockingPool(); + return pool->GetSequencedTaskRunner(pool->GetSequenceToken()).get(); +} diff --git a/ios/chrome/browser/net/metrics_network_client.h b/ios/chrome/browser/net/metrics_network_client.h new file mode 100644 index 0000000..90b37fb --- /dev/null +++ b/ios/chrome/browser/net/metrics_network_client.h @@ -0,0 +1,19 @@ +// Copyright 2013 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. + +#ifndef IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_H_ +#define IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_H_ + +#import "ios/net/clients/crn_forwarding_network_client.h" + +@class MetricsNetworkClientManager; + +// MetricsNetworkClient records UMA metrics about the network requests. +@interface MetricsNetworkClient : CRNForwardingNetworkClient + +- (instancetype)initWithManager:(MetricsNetworkClientManager*)manager; + +@end + +#endif // IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_H_ diff --git a/ios/chrome/browser/net/metrics_network_client.mm b/ios/chrome/browser/net/metrics_network_client.mm new file mode 100644 index 0000000..45f041c --- /dev/null +++ b/ios/chrome/browser/net/metrics_network_client.mm @@ -0,0 +1,95 @@ +// Copyright 2013 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/metrics_network_client.h" + +#import "base/ios/weak_nsobject.h" +#include "base/logging.h" +#include "base/metrics/sparse_histogram.h" +#include "base/strings/sys_string_conversions.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" +#import "ios/chrome/browser/net/metrics_network_client_manager.h" +#include "ios/web/public/url_util.h" +#include "net/base/net_errors.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" + +@interface MetricsNetworkClient () { + BOOL _histogramUpdated; + // Pointer to the load time record for this request. This will be created + // and owned by |_manager|, and it will remain valid as long as |_manager| is. + PageLoadTimeRecord* _loadTimeRecord; + // Pointer to the creating manager, which is owned by a tab. All network + // requests for the tab are destroyed before the tab is, so this pointer + // will always be valid as long as the owning client is alive. + MetricsNetworkClientManager* _manager; + // A pointer to the request, kept so it can be referred to later. + scoped_refptr<net::HttpResponseHeaders> _nativeHeaders; +} +- (void)updateHistogram:(NSInteger)code; +@end + +@implementation MetricsNetworkClient + +- (void)updateHistogram:(NSInteger)code { + DCHECK(!_histogramUpdated) << "Histogram should not be updated twice."; + // The |error| must be in the |net::kErrorDomain|. All those errors are + // defined in |net/base/net_error_list.h|, must be negative values that + // fits in an |int|. See |net/base/net_errors.h| for more information. + DCHECK_LE(code, 0) << "Net error codes should be negative."; + DCHECK_GT(code, INT_MIN) << "Net error code should fit in an int."; + // On iOS, we cannot distinguish between main frames, images and other + // subresources. Consequently, all the codes are aggregated in + // |ErrorCodesForMainFrame3|. + // The other histograms (such as |ErrorCodesForHTTPSGoogleMainFrame2|, + // |ErrorCodesForImages| and |ErrorCodesForSubresources2|) are not filled. + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.ErrorCodesForMainFrame3", + static_cast<int>(-code)); + _histogramUpdated = YES; +} + +- (instancetype)initWithManager:(MetricsNetworkClientManager*)manager { + if ((self = [super init])) { + _manager = manager; + } + return self; +} + +#pragma mark CRNNetworkClientProtocol methods + +- (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest { + [super didCreateNativeRequest:nativeRequest]; + GURL url = web::GURLByRemovingRefFromGURL(nativeRequest->original_url()); + _loadTimeRecord = + [_manager recordForPageLoad:url time:nativeRequest->creation_time()]; + _nativeHeaders = nativeRequest->response_headers(); +} + +- (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode + netErrorCode:(int)netErrorCode { + [super didFailWithNSErrorCode:nsErrorCode netErrorCode:netErrorCode]; + + // Ignore NSURLErrorCancelled errors, which are sometimes created to + // silently abort loads. + + if (nsErrorCode != NSURLErrorCancelled) { + [self updateHistogram:netErrorCode]; + } +} + +- (void)didFinishLoading { + [super didFinishLoading]; + [self updateHistogram:net::OK]; + if (!_nativeHeaders) + return; + + if (!_loadTimeRecord) + return; + + [_loadTimeRecord + setDataProxyUsed:data_reduction_proxy::HasDataReductionProxyViaHeader( + _nativeHeaders.get(), NULL)]; +} + +@end diff --git a/ios/chrome/browser/net/metrics_network_client_manager.h b/ios/chrome/browser/net/metrics_network_client_manager.h new file mode 100644 index 0000000..bc7d2a1 --- /dev/null +++ b/ios/chrome/browser/net/metrics_network_client_manager.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_MANAGER_H_ +#define IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_MANAGER_H_ + +#import <Foundation/Foundation.h> + +#import "base/time/time.h" +#import "ios/net/clients/crn_forwarding_network_client_factory.h" +#include "url/gurl.h" + +@interface PageLoadTimeRecord : NSObject +@property(nonatomic, assign) BOOL dataProxyUsed; +@end + +// Factory that creates MetricsNetworkClient instances. +// Each Tab that cares to report page load metrics should create an instance +// of this class add add it to its request tracker. +@interface MetricsNetworkClientManager : CRNForwardingNetworkClientFactory + +// Called by the tab when a new page load is about to start, to signal the +// current page URL. +- (void)pageLoadStarted:(GURL)url; + +// Called by the tab when the page load is complete. +- (void)pageLoadCompleted; + +// Return a page load time record that will be used to record a load of |url| +// that started at |time|. Returns nil if |url| doesn't match the current page +// url. The page load record is owned by the target, and the caller should not +// take ownership of it. +// This method should only be called on the IO thread. +- (PageLoadTimeRecord*)recordForPageLoad:(const GURL&)url + time:(base::TimeTicks)time; +@end + +#endif // IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_MANAGER_H_ diff --git a/ios/chrome/browser/net/metrics_network_client_manager.mm b/ios/chrome/browser/net/metrics_network_client_manager.mm new file mode 100644 index 0000000..be7afdf --- /dev/null +++ b/ios/chrome/browser/net/metrics_network_client_manager.mm @@ -0,0 +1,137 @@ +// 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/metrics_network_client_manager.h" + +#import "base/ios/weak_nsobject.h" +#import "base/location.h" +#include "base/mac/bind_objc_block.h" +#include "base/mac/scoped_nsobject.h" +#include "base/metrics/histogram.h" +#import "ios/chrome/browser/net/metrics_network_client.h" +#include "ios/web/public/web_thread.h" +#include "url/gurl.h" + +@interface PageLoadTimeRecord () + +@property(nonatomic, readonly) GURL url; +@property(nonatomic, readonly) base::TimeTicks creationTime; +@property(nonatomic, assign) BOOL alreadyCounted; + +- (instancetype)initWithURL:(const GURL&)url time:(base::TimeTicks)time; + +@end + +@implementation PageLoadTimeRecord { + GURL _url; + base::TimeTicks _creationTime; + BOOL _alreadyCounted; + BOOL _dataProxyUsed; +} + +@synthesize url = _url; +@synthesize creationTime = _creationTime; +@synthesize alreadyCounted = _alreadyCounted; +@synthesize dataProxyUsed = _dataProxyUsed; + +- (instancetype)initWithURL:(const GURL&)url time:(base::TimeTicks)time { + if ((self = [super init])) { + _url = url; + _creationTime = time; + } + return self; +} + +@end + +@interface MetricsNetworkClientManager () + +// IO-thread-only methods. +- (void)handlePageLoadStarted:(const GURL&)url; +- (void)handlePageLoadCompleted; + +@end + +@implementation MetricsNetworkClientManager { + // Set of page load time objects created. Beyond deallocation and + // creation, should only be accessed on the IO thread. + base::scoped_nsobject<NSMutableSet> _pageLoadTimes; + // Current URL being loaded by the tab that owns this object. Only accessible + // on the IO thread. + GURL _pageURL; +} + +- (instancetype)init { + if ((self = [super init])) { + _pageLoadTimes.reset([[NSMutableSet set] retain]); + } + return self; +} + +- (Class)clientClass { + return [MetricsNetworkClient class]; +} + +#pragma mark CRWForwardingNetworkClientFactory methods + +- (CRNForwardingNetworkClient*)clientHandlingRequest: + (const net::URLRequest&)request { + return [[[MetricsNetworkClient alloc] initWithManager:self] autorelease]; +} + +#pragma mark - public UI-thread methods + +- (void)pageLoadStarted:(GURL)url { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); + web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ + [self handlePageLoadStarted:url]; + })); +} + +- (void)pageLoadCompleted { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); + web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlock(^{ + [self handlePageLoadCompleted]; + })); +} + +#pragma mark - public IO-thread methods + +- (PageLoadTimeRecord*)recordForPageLoad:(const GURL&)url + time:(base::TimeTicks)time { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO); + base::scoped_nsobject<PageLoadTimeRecord> plt; + if (!_pageURL.spec().empty() && url == _pageURL) { + plt.reset([[PageLoadTimeRecord alloc] initWithURL:url time:time]); + [_pageLoadTimes addObject:plt]; + } + return plt.get(); +} + +#pragma mark - IO-thread handlers for UI thread methods. + +- (void)handlePageLoadStarted:(const GURL&)url { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO); + [_pageLoadTimes removeAllObjects]; + _pageURL = url; +} + +- (void)handlePageLoadCompleted { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::IO); + for (PageLoadTimeRecord* plt in _pageLoadTimes.get()) { + if (plt.url == _pageURL && !plt.alreadyCounted) { + plt.alreadyCounted = YES; + base::TimeDelta elapsed = base::TimeTicks::Now() - plt.creationTime; + if (plt.dataProxyUsed) { + UMA_HISTOGRAM_MEDIUM_TIMES( + "Tabs.iOS_PostRedirectPLT_DataReductionProxy", elapsed); + } else { + UMA_HISTOGRAM_MEDIUM_TIMES("Tabs.iOS_PostRedirectPLT", elapsed); + } + break; + } + } +} + +@end diff --git a/ios/chrome/browser/net/metrics_network_client_unittest.mm b/ios/chrome/browser/net/metrics_network_client_unittest.mm new file mode 100644 index 0000000..01c543a --- /dev/null +++ b/ios/chrome/browser/net/metrics_network_client_unittest.mm @@ -0,0 +1,72 @@ +// 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. + +#include "ios/chrome/browser/net/metrics_network_client.h" + +#include "base/mac/scoped_nsobject.h" +#include "base/test/histogram_tester.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" + +// Dummy client to be registered as underlying client for the +// MetricsNetworkClient. +@interface MetricsMockClient : CRNForwardingNetworkClient +@end + +@implementation MetricsMockClient + +- (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode + netErrorCode:(int)netErrorCode { +} + +- (void)didFinishLoading { +} + +@end + +namespace { + +// Name for the histogram the MetricsNetworkClient has to update. +const char kHistogramName[] = "Net.ErrorCodesForMainFrame3"; + +class MetricsNetworkClientTest : public testing::Test { + public: + MetricsNetworkClientTest() + : histogram_tester_(), client_([[MetricsNetworkClient alloc] init]) { + // Setup a dummy underlying client to avoid DCHECKs. + base::scoped_nsobject<MetricsMockClient> underying_client( + [[MetricsMockClient alloc] init]); + [client_ setUnderlyingClient:underying_client]; + } + + // Returns true if there are no samples for "Net.ErrorCodesForMainFrame3". + void VerifyNoSamples() { + histogram_tester_.ExpectTotalCount(kHistogramName, 0); + } + + protected: + base::HistogramTester histogram_tester_; + base::scoped_nsobject<MetricsNetworkClient> client_; +}; + +} // namespace + +TEST_F(MetricsNetworkClientTest, HistogramUpdatedOnErrors) { + int net_error = net::ERR_FAILED; + VerifyNoSamples(); + // NSURLErrorCancelled errors must not update the histogram. + [client_ didFailWithNSErrorCode:NSURLErrorCancelled netErrorCode:net_error]; + VerifyNoSamples(); + // Other iOS errors update the histogram. + [client_ didFailWithNSErrorCode:NSURLErrorCannotConnectToHost + netErrorCode:net_error]; + // |net_error| is negative, the histogram reports the opposite value. + histogram_tester_.ExpectUniqueSample(kHistogramName, -net_error, 1); +} + +TEST_F(MetricsNetworkClientTest, HistogramUpdatedOnSuccess) { + VerifyNoSamples(); + [client_ didFinishLoading]; + histogram_tester_.ExpectUniqueSample(kHistogramName, -net::OK, 1); +} diff --git a/ios/chrome/browser/net/retryable_url_fetcher.h b/ios/chrome/browser/net/retryable_url_fetcher.h new file mode 100644 index 0000000..cd153980 --- /dev/null +++ b/ios/chrome/browser/net/retryable_url_fetcher.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef IOS_CHROME_BROWSER_NET_RETRYABLE_URL_FETCHER_H_ +#define IOS_CHROME_BROWSER_NET_RETRYABLE_URL_FETCHER_H_ + +#import <Foundation/Foundation.h> + +#include "net/base/backoff_entry.h" + +namespace net { +class URLRequestContextGetter; +} // namespace net + +// Delegate protocol for RetryableURLFetcher object. +@protocol RetryableURLFetcherDelegate<NSObject> + +// Returns the HTTP URL for RetryableURLFetcher to fetch. +- (NSString*)urlToFetch; + +// Callback function after URL has been fetched. |response| is the content of +// the HTTP response. |response| may be nil if the HTTP request failed. +- (void)processSuccessResponse:(NSString*)response; + +@end + +@interface RetryableURLFetcher : NSObject + +// Designated initializer. |context| and |delegate| must not be nil. If |policy| +// is not null, it specifies how often to retry the URL fetch on a call to +// -startFetch. If |policy| is null, there is no retry. +- (instancetype) + initWithRequestContextGetter:(net::URLRequestContextGetter*)context + delegate:(id<RetryableURLFetcherDelegate>)delegate + backoffPolicy:(const net::BackoffEntry::Policy*)policy; + +// Starts fetching URL. Uses the backoff policy specified when the object was +// initialized. +- (void)startFetch; + +// Returns the number of times that this URL Fetcher failed to receive a +// success response. Returns 0 if this URL Fetcher was not set up to do retries. +- (int)failureCount; + +@end + +#endif // IOS_CHROME_BROWSER_NET_RETRYABLE_URL_FETCHER_H_ diff --git a/ios/chrome/browser/net/retryable_url_fetcher.mm b/ios/chrome/browser/net/retryable_url_fetcher.mm new file mode 100644 index 0000000..0e6bc60 --- /dev/null +++ b/ios/chrome/browser/net/retryable_url_fetcher.mm @@ -0,0 +1,92 @@ +// 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 "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/sys_string_conversions.h" +#include "net/http/http_status_code.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_context_getter.h" +#include "url/gurl.h" + +@interface RetryableURLFetcher () +- (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher; +@end + +class URLRequestDelegate : public net::URLFetcherDelegate { + public: + explicit URLRequestDelegate(RetryableURLFetcher* owner) : owner_(owner) {} + void OnURLFetchComplete(const net::URLFetcher* source) override { + [owner_ urlFetchDidComplete:source]; + } + + private: + RetryableURLFetcher* owner_; // Weak. +}; + +@implementation RetryableURLFetcher { + scoped_refptr<net::URLRequestContextGetter> requestContextGetter_; + scoped_ptr<URLRequestDelegate> fetcherDelegate_; + scoped_ptr<net::URLFetcher> fetcher_; + scoped_ptr<net::BackoffEntry> backoffEntry_; + int retryCount_; + id<RetryableURLFetcherDelegate> delegate_; // Weak. +} + +- (instancetype) + initWithRequestContextGetter:(net::URLRequestContextGetter*)context + delegate:(id<RetryableURLFetcherDelegate>)delegate + backoffPolicy:(const net::BackoffEntry::Policy*)policy { + self = [super init]; + if (self) { + DCHECK(context); + DCHECK(delegate); + requestContextGetter_ = context; + delegate_ = delegate; + if (policy) + backoffEntry_.reset(new net::BackoffEntry(policy)); + } + return self; +} + +- (void)startFetch { + DCHECK(requestContextGetter_.get()); + GURL url(base::SysNSStringToUTF8([delegate_ urlToFetch])); + if (url.is_valid()) { + fetcherDelegate_.reset(new URLRequestDelegate(self)); + fetcher_.reset(net::URLFetcher::Create(url, net::URLFetcher::GET, + fetcherDelegate_.get())); + fetcher_->SetRequestContext(requestContextGetter_.get()); + fetcher_->Start(); + } +} + +- (int)failureCount { + return backoffEntry_ ? backoffEntry_->failure_count() : 0; +} + +- (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher { + BOOL success = fetcher->GetResponseCode() == net::HTTP_OK; + if (!success && 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 (success) { + std::string responseString; + if (fetcher->GetResponseAsString(&responseString)) + response = base::SysUTF8ToNSString(responseString); + } + [delegate_ processSuccessResponse:response]; +} + +@end diff --git a/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm b/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm new file mode 100644 index 0000000..6f73234 --- /dev/null +++ b/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm @@ -0,0 +1,103 @@ +// 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" + +#import "base/mac/scoped_nsobject.h" +#include "ios/web/public/test/test_web_thread.h" +#include "net/url_request/test_url_fetcher_factory.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_test_util.h" +#import "testing/gtest_mac.h" +#include "testing/platform_test.h" + +namespace { +// An arbitrary text string for a fake response. +NSString* const kFakeResponseString = @"Something interesting here."; +} + +// Delegate object to provide data for RetryableURLFetcher and +// handles the callback when URL is fetched. +@interface TestRetryableURLFetcherDelegate + : NSObject<RetryableURLFetcherDelegate> +// Counts the number of times that a successful response has been processed. +@property(nonatomic, assign) NSUInteger responsesProcessed; +@end + +@implementation TestRetryableURLFetcherDelegate +@synthesize responsesProcessed; + +- (NSString*)urlToFetch { + return @"http://www.google.com"; +} + +- (void)processSuccessResponse:(NSString*)response { + if (response) { + EXPECT_NSEQ(kFakeResponseString, response); + ++responsesProcessed; + } +} + +@end + +namespace { + +class RetryableURLFetcherTest : public PlatformTest { + protected: + void SetUp() override { + PlatformTest::SetUp(); + test_delegate_.reset([[TestRetryableURLFetcherDelegate alloc] init]); + io_thread_.reset( + new web::TestWebThread(web::WebThread::IO, &message_loop_)); + } + + net::TestURLFetcherFactory factory_; + scoped_ptr<web::TestWebThread> io_thread_; + base::MessageLoop message_loop_; + base::scoped_nsobject<TestRetryableURLFetcherDelegate> test_delegate_; +}; + +TEST_F(RetryableURLFetcherTest, TestResponse200) { + scoped_refptr<net::URLRequestContextGetter> request_context_getter = + new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy()); + base::scoped_nsobject<RetryableURLFetcher> retryableFetcher( + [[RetryableURLFetcher alloc] + initWithRequestContextGetter:request_context_getter.get() + delegate:test_delegate_.get() + backoffPolicy:nil]); + [retryableFetcher startFetch]; + + // Manually calls the delegate. + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + [test_delegate_ setResponsesProcessed:0U]; + fetcher->set_response_code(200); + fetcher->SetResponseString([kFakeResponseString UTF8String]); + fetcher->delegate()->OnURLFetchComplete(fetcher); + EXPECT_EQ(1U, [test_delegate_ responsesProcessed]); +} + +TEST_F(RetryableURLFetcherTest, TestResponse404) { + scoped_refptr<net::URLRequestContextGetter> request_context_getter = + new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy()); + base::scoped_nsobject<RetryableURLFetcher> retryableFetcher( + [[RetryableURLFetcher alloc] + initWithRequestContextGetter:request_context_getter.get() + delegate:test_delegate_.get() + backoffPolicy:nil]); + [retryableFetcher startFetch]; + + // Manually calls the delegate. + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + [test_delegate_ setResponsesProcessed:0U]; + fetcher->set_response_code(404); + fetcher->SetResponseString(""); + fetcher->delegate()->OnURLFetchComplete(fetcher); + EXPECT_EQ(0U, [test_delegate_ responsesProcessed]); +} + +} // namespace diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index f2e8122..6a221ec 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp @@ -17,6 +17,7 @@ '../../base/base.gyp:base', '../../components/components.gyp:autofill_core_browser', '../../components/components.gyp:autofill_ios_browser', + '../../components/components.gyp:data_reduction_proxy_core_common', '../../components/components.gyp:dom_distiller_core', '../../components/components.gyp:dom_distiller_ios', '../../components/components.gyp:infobars_core', @@ -73,6 +74,7 @@ 'browser/autofill/form_suggestion_view_client.h', 'browser/browser_state/browser_state_otr_helper.cc', 'browser/browser_state/browser_state_otr_helper.h', + 'browser/browsing_data_change_listening.h', 'browser/chrome_switches.cc', 'browser/chrome_switches.h', 'browser/chrome_url_constants.cc', @@ -103,8 +105,16 @@ 'browser/infobars/infobar_manager_impl.h', 'browser/infobars/infobar_utils.h', 'browser/infobars/infobar_utils.mm', + 'browser/net/chrome_cookie_store_ios_client.h', + 'browser/net/chrome_cookie_store_ios_client.mm', 'browser/net/image_fetcher.h', 'browser/net/image_fetcher.mm', + 'browser/net/metrics_network_client.h', + 'browser/net/metrics_network_client.mm', + 'browser/net/metrics_network_client_manager.h', + 'browser/net/metrics_network_client_manager.mm', + 'browser/net/retryable_url_fetcher.h', + 'browser/net/retryable_url_fetcher.mm', 'browser/passwords/password_generation_utils.h', 'browser/passwords/password_generation_utils.mm', 'browser/pref_names.cc', diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp index 2029cf6..7cea1a3 100644 --- a/ios/chrome/ios_chrome_tests.gyp +++ b/ios/chrome/ios_chrome_tests.gyp @@ -24,6 +24,8 @@ ], 'sources': [ 'browser/net/image_fetcher_unittest.mm', + 'browser/net/metrics_network_client_unittest.mm', + 'browser/net/retryable_url_fetcher_unittest.mm', 'browser/snapshots/snapshot_cache_unittest.mm', 'browser/snapshots/snapshots_util_unittest.mm', 'browser/translate/translate_service_ios_unittest.cc', |