Index: ios/web/net/request_tracker_impl.h |
diff --git a/ios/web/net/request_tracker_impl.h b/ios/web/net/request_tracker_impl.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..45aaa0361b195c8309904c2e20dc8c4a432de5f6 |
--- /dev/null |
+++ b/ios/web/net/request_tracker_impl.h |
@@ -0,0 +1,399 @@ |
+// 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_WEB_NET_REQUEST_TRACKER_IMPL_H_ |
+#define IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_ |
+ |
+#import <Foundation/Foundation.h> |
+#include <map> |
+#include <set> |
+ |
+#include "base/callback_forward.h" |
+#include "base/mac/scoped_nsobject.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/memory/scoped_vector.h" |
+#include "base/memory/weak_ptr.h" |
+#import "ios/net/request_tracker.h" |
+#import "ios/web/net/crw_request_tracker_delegate.h" |
+#include "ios/web/public/web_thread.h" |
+#include "net/url_request/url_request_context_getter.h" |
+#include "url/gurl.h" |
+ |
+@class SSLCarrier; |
+@class CRWSSLCarrier; |
+class SSLErrorInfo; |
+struct TrackerCounts; |
+ |
+namespace content { |
+struct SSLStatus; |
+} |
+ |
+namespace net { |
+class HttpResponseHeaders; |
+class URLRequest; |
+class URLRequestContext; |
+class SSLInfo; |
+class X509Certificate; |
+} |
+ |
+namespace web { |
+ |
+class BrowserState; |
+class CertificatePolicyCache; |
+ |
+// Structure to capture the current state of a page. |
+struct PageCounts { |
+ public: |
+ PageCounts() : finished(0), |
+ finished_bytes(0), |
+ unfinished(0), |
+ unfinished_no_estimate(0), |
+ unfinished_no_estimate_bytes_done(0), |
+ unfinished_estimated_bytes_left(0), |
+ unfinished_estimate_bytes_done(0), |
+ largest_byte_size_known(0) { |
+ }; |
+ |
+ // Count of finished requests. |
+ uint64_t finished; |
+ // Total bytes count dowloaded for all finished requests. |
+ uint64_t finished_bytes; |
+ // Count of unfinished requests. |
+ uint64_t unfinished; |
+ // Count of unfinished requests with unknown size. |
+ uint64_t unfinished_no_estimate; |
+ // Total bytes count dowloaded for unfinished requests of unknown size. |
+ uint64_t unfinished_no_estimate_bytes_done; |
+ // Count of unfinished requests with an estimated size. |
+ uint64_t unfinished_estimated_bytes_left; |
+ // Total bytes count dowloaded for unfinished requests with an estimated size. |
+ uint64_t unfinished_estimate_bytes_done; |
+ // Size of the request with the most bytes on the page. |
+ uint64_t largest_byte_size_known; |
+}; |
+ |
+// RequestTrackerImpl captures and stores all the network requests that |
+// initiated from a particular tab. It only keeps the URLs and eventually, if |
+// available, the expected length of the result and the length of the received |
+// data so far as this is used to build a progress bar for a page. |
+// Note that the Request tracker has no notion of a page, it only tracks the |
+// requests by tab. In order for the tracker to know that a request is for a |
+// page or a subresource it is necessary for the tab to call StartPageLoad() |
+// with the URL of the page once it is known to avoid storing all the requests |
+// forever. |
+// |
+// The consumer needs to implement the CRWRequestTrackerImplDelegate protocol |
+// and needs to call StartPageLoad() and FinishPageLoad() to indicate the page |
+// boundaries. StartPageLoad() will also have the side effect of clearing past |
+// requests from memory. The consumer is assumed to be on the UI thread at all |
+// times. |
+// |
+// RequestTrackerImpl objects are created and destroyed on the UI thread and |
+// must be owned by some other object on the UI thread by way of a |
+// scoped_refptr, as returned by the public static constructor method, |
+// CreateTrackerForRequestGroupID. All consumer API methods will be called |
+// through this pointer. |
+ |
+class RequestTrackerImpl; |
+ |
+struct RequestTrackerImplTraits { |
+ static void Destruct(const RequestTrackerImpl* t); |
+}; |
+ |
+class RequestTrackerImpl |
+ : public base::RefCountedThreadSafe<RequestTrackerImpl, |
+ RequestTrackerImplTraits>, |
+ public net::RequestTracker { |
+ public: |
+#pragma mark Public Consumer API |
+ // Consumer API methods should only be called on the UI thread. |
+ |
+ // Create a new RequestTrackerImpl associated with a particular tab. The |
+ // profile must be the one associated to the given tab. This method has to be |
+ // called *once* per tab and needs to be called before triggering any network |
+ // request. The caller of CreateTrackerForRequestGroupID owns the tracker, and |
+ // this class also keeps a global map of all active trackers. When the owning |
+ // object releases it, the class removes it from the global map. |
+ static scoped_refptr<RequestTrackerImpl> CreateTrackerForRequestGroupID( |
+ NSString* request_group_id, |
+ BrowserState* browser_state, |
+ net::URLRequestContextGetter* context_getter, |
+ id<CRWRequestTrackerDelegate> delegate); |
+ |
+ // The network layer has no way to know which network request is the primary |
+ // one for a page load. The tab knows, either because it initiated the page |
+ // load via the URL or received a callback informing it of the page change. |
+ // Every time this happens the tab should call this method to clear the |
+ // resources tracked. |
+ // This will forget all the finished requests made before this URL in history. |
+ // user_info is to be used by the consumer to store more additional specific |
+ // info about the page, as an URL is not unique. |
+ void StartPageLoad(const GURL& url, id user_info); |
+ |
+ // In order to properly provide progress information the tracker needs to know |
+ // when the page is fully loaded. |load_success| indicates if the page |
+ // successfully loaded. |
+ void FinishPageLoad(const GURL& url, bool load_success); |
+ |
+ // Tells the tracker that history.pushState() or history.replaceState() |
+ // changed the page URL. |
+ void HistoryStateChange(const GURL& url); |
+ |
+ // Marks the tracker as closed. An owner must call this before the tracker is |
+ // deleted. Once closed, no further calls will be made to the delegate. |
+ void Close(); |
+ |
+ // Call |callback| on the UI thread after any pending request cancellations |
+ // have completed on the IO thread. |
+ // This should be used to delete a profile for which all of the trackers |
+ // that use the profile's request context are closed. |
+ static void RunAfterRequestsCancel(const base::Closure& callback); |
+ |
+ // Block until all pending IO thread activity has completed. This should only |
+ // be used when Chrome is shutting down, and after all request trackers have |
+ // had Close() called on them. |
+ static void BlockUntilTrackersShutdown(); |
+ |
+#pragma mark Client utility methods. |
+ |
+ // Finds the tracker given the tab ID. As calling this method involves a lock |
+ // it is expected that the provider will call it only once. |
+ // Returns a weak pointer, which should only be dereferenced on the IO thread. |
+ // Returns NULL if no tracker exists for |request_group_id|. |
+ static RequestTrackerImpl* GetTrackerForRequestGroupID( |
+ NSString* request_group_id); |
+ |
+ // Callback from the UI to allow or deny a particular certificate. |
+ void ErrorCallback(CRWSSLCarrier* carrier, bool allow); |
+ |
+ // Utility method for clients to post tasks to the IO thread from the UI |
+ // thread. |
+ void PostIOTask(const base::Closure& task); |
+ |
+ // Utility method for clients to post tasks to the IO thread from the IO |
+ // thread. |
+ void ScheduleIOTask(const base::Closure& task); |
+ |
+ // Utility method for clients to conditionally post tasks to the UI thread |
+ // from the IO thread. The task will not be posted if the request tracker |
+ // is in the process of closing (thus it "is open"). |
+ void PostUITaskIfOpen(const base::Closure& task); |
+ // Static version of the method, where |tracker| is a RequestTrackerImpl |
+ // passed as a base::WeakPtr<RequestTracker>. |
+ static void PostUITaskIfOpen(const base::WeakPtr<RequestTracker> tracker, |
+ const base::Closure& task); |
+ |
+ // Sets the cache mode. Must be called from the UI thread. |
+ void SetCacheModeFromUIThread(RequestTracker::CacheMode mode); |
+ |
+#pragma mark Testing methods |
+ |
+ void SetCertificatePolicyCacheForTest(web::CertificatePolicyCache* cache); |
+ |
+#pragma mark Accessors used by internal classes and network clients. |
+ int identifier() { return identifier_; } |
+ bool has_mixed_content() { return has_mixed_content_; } |
+ |
+ // RequestTracker implementation. |
+ void StartRequest(net::URLRequest* request) override; |
+ void CaptureHeaders(net::URLRequest* request) override; |
+ void CaptureExpectedLength(const net::URLRequest* request, |
+ uint64_t length) override; |
+ void CaptureReceivedBytes(const net::URLRequest* request, |
+ uint64_t byte_count) override; |
+ void CaptureCertificatePolicyCache( |
+ const net::URLRequest* request, |
+ const SSLCallback& should_continue) override; |
+ void StopRequest(net::URLRequest* request) override; |
+ void StopRedirectedRequest(net::URLRequest* request) override; |
+ void OnSSLCertificateError(const net::URLRequest* request, |
+ const net::SSLInfo& ssl_info, |
+ bool recoverable, |
+ const SSLCallback& should_continue) override; |
+ net::URLRequestContext* GetRequestContext() override; |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<RequestTrackerImpl>; |
+ friend struct RequestTrackerImplTraits; |
+ |
+#pragma mark Object lifecycle API |
+ // Private. RequestTrackerImpls are created through |
+ // CreateTrackerForRequestGroupID(). |
+ RequestTrackerImpl(NSString* request_group_id, |
+ net::URLRequestContextGetter* context_getter, |
+ id<CRWRequestTrackerDelegate> delegate); |
+ |
+ void InitOnIOThread( |
+ const scoped_refptr<web::CertificatePolicyCache>& policy_cache); |
+ |
+ // Private destructor because the object is reference counted. A no-op; the |
+ // useful destruction work happens in Destruct(). |
+ ~RequestTrackerImpl() override; |
+ |
+ // Handles pre-destruction destruction tasks. This is invoked by |
+ // RequestTrackerImplTraits::Destruct whenever the reference count of a |
+ // RequestTrackerImpl is zero, and this will untimately delete the |
+ // RequestTrackerImpl. |
+ void Destruct(); |
+ |
+#pragma mark Private Provider API |
+ // Private methods that implement provider API features. All are only called |
+ // on the IO thread. |
+ |
+ // Called when something has changed (network load progress or SSL status) |
+ // that the consumer should know about. Notifications are asynchronous and |
+ // batched. |
+ void Notify(); |
+ |
+ // If no other notifications are pending, notifies the consumer of SSL status |
+ // and load progress. |
+ void StackNotification(); |
+ |
+ // Notify the consumer about the SSL status of this tracker's page load. |
+ void SSLNotify(); |
+ |
+ // If the counts is for a request currently waiting for the user to approve it |
+ // will reevaluate the approval. |
+ void EvaluateSSLCallbackForCounts(TrackerCounts* counts); |
+ |
+ // Loop through all the requests waiting for approval and invoke |
+ // |-evaluateSSLCallbackForCounts:| on all the ones with an |UNKNOWN| |
+ // judgment. |
+ void ReevaluateCallbacksForAllCounts(); |
+ |
+ // To cancel a rejected request due to a SSL issue. |
+ void CancelRequestForCounts(TrackerCounts* counts); |
+ |
+ // Estimate the page load progress. Returns -1 if the progress didn't change |
+ // since the last time this method was invoked. |
+ float EstimatedProgress(); |
+ |
+ // The URL change notification is often late, therefore the mixed content |
+ // status and the certificate policies may need to be recomputed. |
+ void RecomputeMixedContent(const TrackerCounts* split_position); |
+ void RecomputeCertificatePolicy(const TrackerCounts* split_position); |
+ |
+ // Remove all finished request up to the last instance of |url|. If url is not |
+ // found, this will clear all the requests. |
+ void TrimToURL(const GURL& url, id user_info); |
+ |
+ // Sets page_url_ to the new URL if it's a valid history state change (i.e. |
+ // the URL's have the same origin) and if the tab is currently loading. |
+ void HistoryStateChangeToURL(const GURL& full_url); |
+ |
+ // Note that the page started by a call to Trim is no longer loading. |
+ // |load_success| indicates if the page successfully loaded. |
+ void StopPageLoad(const GURL& url, bool load_success); |
+ |
+ // Cancels all the requests in |live_requests_|. |
+ void CancelRequests(); |
+ |
+#pragma mark Private Consumer API |
+ // Private methods that call into delegate methods. |
+ |
+ // Notify* methods are posted to the UI thread by the provider API |
+ // methods. |
+ |
+ // Has the delegate handle |headers| for |request_url|. |
+ void NotifyResponseHeaders(net::HttpResponseHeaders* headers, |
+ const GURL& request_url); |
+ |
+ // Notifies the deleage of certificate use. |
+ void NotifyCertificateUsed(net::X509Certificate* certificate, |
+ const std::string& host, |
+ net::CertStatus status); |
+ |
+ // Notifies the deleate of a load completion estimate. |
+ void NotifyUpdatedProgress(float estimate); |
+ |
+ // Has the delegate clear SSL certificates. |
+ void NotifyClearCertificates(); |
+ |
+ // Notifies the delegate of an SSL status update. |
+ void NotifyUpdatedSSLStatus(base::scoped_nsobject<CRWSSLCarrier> carrier); |
+ |
+ // Calls the delegate method to present an SSL error interstitial. |
+ void NotifyPresentSSLError(base::scoped_nsobject<CRWSSLCarrier> carrier, |
+ bool recoverable); |
+ |
+#pragma mark Internal utilities for task posting |
+ // Posts |task| to |thread|. Must not be called from |thread|. If |thread| is |
+ // the IO thread, silently returns if |is_closing_| is true. |
+ void PostTask(const base::Closure& task, web::WebThread::ID thread); |
+ |
+ // Posts |block| to |thread|, safely passing in |caller| to |block|. |
+ void PostBlock(id caller, void (^block)(id), web::WebThread::ID thread); |
+ |
+#pragma mark Other internal methods. |
+ // Returns the current state of the page. |
+ PageCounts pageCounts(); |
+ |
+ // Like description, but cannot be called from any thread. It must be called |
+ // only from the IO thread. |
+ NSString* UnsafeDescription(); |
+ |
+ // Generates a string unique to this RequestTrackerImpl to use with the |
+ // CRWNetworkActivityIndicatorManager. |
+ NSString* GetNetworkActivityKey(); |
+ |
+#pragma mark Non thread-safe fields, only accessed from the main thread. |
+ // The RequestTrackerImpl delegate. All changes and access to this object |
+ // should be done on the main thread. |
+ id<CRWRequestTrackerDelegate> delegate_; // Weak. |
+ |
+#pragma mark Non thread-safe fields, only accessed from the IO thread. |
+ // All the tracked requests for the page, indexed by net::URLRequest (Cast as |
+ // a void* to avoid the temptation of accessing it from the wrong thread). |
+ // This map is not exhaustive: it is only meant to estimate the loading |
+ // progress, and thus requests corresponding to old navigation events are not |
+ // in it. |
+ std::map<const void*, TrackerCounts*> counts_by_request_; |
+ // All the live requests associated with the tracker. |
+ std::set<net::URLRequest*> live_requests_; |
+ // A list of all the TrackerCounts, including the finished ones. |
+ ScopedVector<TrackerCounts> counts_; |
+ // The system shall never allow the page load estimate to go back. |
+ float previous_estimate_; |
+ // Index of the first request to consider for building the estimation. |
+ unsigned int estimate_start_index_; |
+ // How many notifications are currently queued, to avoid notifying too often. |
+ int notification_depth_; |
+ // The tracker containing the error currently presented to the user. |
+ TrackerCounts* current_ssl_error_; |
+ // Set to |YES| if the page has mixed content |
+ bool has_mixed_content_; |
+ // Set to true if between TrimToURL and StopPageLoad. |
+ bool is_loading_; |
+ // Set to true in TrimToURL if starting a new estimate round. Set to false by |
+ // StartRequest once the new round is started. |
+ bool new_estimate_round_; |
+ |
+#pragma mark Other fields. |
+ scoped_refptr<web::CertificatePolicyCache> policy_cache_; |
+ // If |true| all the requests should be static file requests, otherwise all |
+ // the requests should be network requests. This is a constant initialized |
+ // in the constructor and read in IO and UI threads. |
+ const bool is_for_static_file_requests_; |
+ |
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
+ // Current page URL, as far as we know. |
+ GURL page_url_; |
+ // Userinfo attached to the page, passed back by the delegate. |
+ base::scoped_nsobject<id> user_info_; |
+ // A tracker identifier (a simple increasing number) used to store |
+ // certificates. |
+ int identifier_; |
+ // The string that identifies the tab this tracker serves. Used to index |
+ // g_trackers. |
+ base::scoped_nsobject<NSString> request_group_id_; |
+ // Flag to synchronize deletion and callback creation. Lives on the IO thread. |
+ // True when this tracker has beed Close()d. If this is the case, no further |
+ // references to it should be generated (for example by binding it into a |
+ // callback), and the expectation is that it will soon be deleted. |
+ bool is_closing_; |
+}; |
+ |
+} // namespace web |
+ |
+#endif // IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_ |