| // 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 <stdint.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_ |