| // 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 |