OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #ifndef IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_ |
| 6 #define IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_ |
| 7 |
| 8 #import <Foundation/Foundation.h> |
| 9 #include <map> |
| 10 #include <set> |
| 11 |
| 12 #include "base/callback_forward.h" |
| 13 #include "base/mac/scoped_nsobject.h" |
| 14 #include "base/memory/ref_counted.h" |
| 15 #include "base/memory/scoped_vector.h" |
| 16 #include "base/memory/weak_ptr.h" |
| 17 #import "ios/net/request_tracker.h" |
| 18 #import "ios/web/net/crw_request_tracker_delegate.h" |
| 19 #include "ios/web/public/web_thread.h" |
| 20 #include "net/url_request/url_request_context_getter.h" |
| 21 #include "url/gurl.h" |
| 22 |
| 23 @class SSLCarrier; |
| 24 @class CRWSSLCarrier; |
| 25 class SSLErrorInfo; |
| 26 struct TrackerCounts; |
| 27 |
| 28 namespace content { |
| 29 struct SSLStatus; |
| 30 } |
| 31 |
| 32 namespace net { |
| 33 class HttpResponseHeaders; |
| 34 class URLRequest; |
| 35 class URLRequestContext; |
| 36 class SSLInfo; |
| 37 class X509Certificate; |
| 38 } |
| 39 |
| 40 namespace web { |
| 41 |
| 42 class BrowserState; |
| 43 class CertificatePolicyCache; |
| 44 |
| 45 // Structure to capture the current state of a page. |
| 46 struct PageCounts { |
| 47 public: |
| 48 PageCounts() : finished(0), |
| 49 finished_bytes(0), |
| 50 unfinished(0), |
| 51 unfinished_no_estimate(0), |
| 52 unfinished_no_estimate_bytes_done(0), |
| 53 unfinished_estimated_bytes_left(0), |
| 54 unfinished_estimate_bytes_done(0), |
| 55 largest_byte_size_known(0) { |
| 56 }; |
| 57 |
| 58 // Count of finished requests. |
| 59 uint64_t finished; |
| 60 // Total bytes count dowloaded for all finished requests. |
| 61 uint64_t finished_bytes; |
| 62 // Count of unfinished requests. |
| 63 uint64_t unfinished; |
| 64 // Count of unfinished requests with unknown size. |
| 65 uint64_t unfinished_no_estimate; |
| 66 // Total bytes count dowloaded for unfinished requests of unknown size. |
| 67 uint64_t unfinished_no_estimate_bytes_done; |
| 68 // Count of unfinished requests with an estimated size. |
| 69 uint64_t unfinished_estimated_bytes_left; |
| 70 // Total bytes count dowloaded for unfinished requests with an estimated size. |
| 71 uint64_t unfinished_estimate_bytes_done; |
| 72 // Size of the request with the most bytes on the page. |
| 73 uint64_t largest_byte_size_known; |
| 74 }; |
| 75 |
| 76 // RequestTrackerImpl captures and stores all the network requests that |
| 77 // initiated from a particular tab. It only keeps the URLs and eventually, if |
| 78 // available, the expected length of the result and the length of the received |
| 79 // data so far as this is used to build a progress bar for a page. |
| 80 // Note that the Request tracker has no notion of a page, it only tracks the |
| 81 // requests by tab. In order for the tracker to know that a request is for a |
| 82 // page or a subresource it is necessary for the tab to call StartPageLoad() |
| 83 // with the URL of the page once it is known to avoid storing all the requests |
| 84 // forever. |
| 85 // |
| 86 // The consumer needs to implement the CRWRequestTrackerImplDelegate protocol |
| 87 // and needs to call StartPageLoad() and FinishPageLoad() to indicate the page |
| 88 // boundaries. StartPageLoad() will also have the side effect of clearing past |
| 89 // requests from memory. The consumer is assumed to be on the UI thread at all |
| 90 // times. |
| 91 // |
| 92 // RequestTrackerImpl objects are created and destroyed on the UI thread and |
| 93 // must be owned by some other object on the UI thread by way of a |
| 94 // scoped_refptr, as returned by the public static constructor method, |
| 95 // CreateTrackerForRequestGroupID. All consumer API methods will be called |
| 96 // through this pointer. |
| 97 |
| 98 class RequestTrackerImpl; |
| 99 |
| 100 struct RequestTrackerImplTraits { |
| 101 static void Destruct(const RequestTrackerImpl* t); |
| 102 }; |
| 103 |
| 104 class RequestTrackerImpl |
| 105 : public base::RefCountedThreadSafe<RequestTrackerImpl, |
| 106 RequestTrackerImplTraits>, |
| 107 public net::RequestTracker { |
| 108 public: |
| 109 #pragma mark Public Consumer API |
| 110 // Consumer API methods should only be called on the UI thread. |
| 111 |
| 112 // Create a new RequestTrackerImpl associated with a particular tab. The |
| 113 // profile must be the one associated to the given tab. This method has to be |
| 114 // called *once* per tab and needs to be called before triggering any network |
| 115 // request. The caller of CreateTrackerForRequestGroupID owns the tracker, and |
| 116 // this class also keeps a global map of all active trackers. When the owning |
| 117 // object releases it, the class removes it from the global map. |
| 118 static scoped_refptr<RequestTrackerImpl> CreateTrackerForRequestGroupID( |
| 119 NSString* request_group_id, |
| 120 BrowserState* browser_state, |
| 121 net::URLRequestContextGetter* context_getter, |
| 122 id<CRWRequestTrackerDelegate> delegate); |
| 123 |
| 124 // The network layer has no way to know which network request is the primary |
| 125 // one for a page load. The tab knows, either because it initiated the page |
| 126 // load via the URL or received a callback informing it of the page change. |
| 127 // Every time this happens the tab should call this method to clear the |
| 128 // resources tracked. |
| 129 // This will forget all the finished requests made before this URL in history. |
| 130 // user_info is to be used by the consumer to store more additional specific |
| 131 // info about the page, as an URL is not unique. |
| 132 void StartPageLoad(const GURL& url, id user_info); |
| 133 |
| 134 // In order to properly provide progress information the tracker needs to know |
| 135 // when the page is fully loaded. |load_success| indicates if the page |
| 136 // successfully loaded. |
| 137 void FinishPageLoad(const GURL& url, bool load_success); |
| 138 |
| 139 // Tells the tracker that history.pushState() or history.replaceState() |
| 140 // changed the page URL. |
| 141 void HistoryStateChange(const GURL& url); |
| 142 |
| 143 // Marks the tracker as closed. An owner must call this before the tracker is |
| 144 // deleted. Once closed, no further calls will be made to the delegate. |
| 145 void Close(); |
| 146 |
| 147 // Call |callback| on the UI thread after any pending request cancellations |
| 148 // have completed on the IO thread. |
| 149 // This should be used to delete a profile for which all of the trackers |
| 150 // that use the profile's request context are closed. |
| 151 static void RunAfterRequestsCancel(const base::Closure& callback); |
| 152 |
| 153 // Block until all pending IO thread activity has completed. This should only |
| 154 // be used when Chrome is shutting down, and after all request trackers have |
| 155 // had Close() called on them. |
| 156 static void BlockUntilTrackersShutdown(); |
| 157 |
| 158 #pragma mark Client utility methods. |
| 159 |
| 160 // Finds the tracker given the tab ID. As calling this method involves a lock |
| 161 // it is expected that the provider will call it only once. |
| 162 // Returns a weak pointer, which should only be dereferenced on the IO thread. |
| 163 // Returns NULL if no tracker exists for |request_group_id|. |
| 164 static RequestTrackerImpl* GetTrackerForRequestGroupID( |
| 165 NSString* request_group_id); |
| 166 |
| 167 // Callback from the UI to allow or deny a particular certificate. |
| 168 void ErrorCallback(CRWSSLCarrier* carrier, bool allow); |
| 169 |
| 170 // Utility method for clients to post tasks to the IO thread from the UI |
| 171 // thread. |
| 172 void PostIOTask(const base::Closure& task); |
| 173 |
| 174 // Utility method for clients to post tasks to the IO thread from the IO |
| 175 // thread. |
| 176 void ScheduleIOTask(const base::Closure& task); |
| 177 |
| 178 // Utility method for clients to conditionally post tasks to the UI thread |
| 179 // from the IO thread. The task will not be posted if the request tracker |
| 180 // is in the process of closing (thus it "is open"). |
| 181 void PostUITaskIfOpen(const base::Closure& task); |
| 182 // Static version of the method, where |tracker| is a RequestTrackerImpl |
| 183 // passed as a base::WeakPtr<RequestTracker>. |
| 184 static void PostUITaskIfOpen(const base::WeakPtr<RequestTracker> tracker, |
| 185 const base::Closure& task); |
| 186 |
| 187 // Sets the cache mode. Must be called from the UI thread. |
| 188 void SetCacheModeFromUIThread(RequestTracker::CacheMode mode); |
| 189 |
| 190 #pragma mark Testing methods |
| 191 |
| 192 void SetCertificatePolicyCacheForTest(web::CertificatePolicyCache* cache); |
| 193 |
| 194 #pragma mark Accessors used by internal classes and network clients. |
| 195 int identifier() { return identifier_; } |
| 196 bool has_mixed_content() { return has_mixed_content_; } |
| 197 |
| 198 // RequestTracker implementation. |
| 199 void StartRequest(net::URLRequest* request) override; |
| 200 void CaptureHeaders(net::URLRequest* request) override; |
| 201 void CaptureExpectedLength(const net::URLRequest* request, |
| 202 uint64_t length) override; |
| 203 void CaptureReceivedBytes(const net::URLRequest* request, |
| 204 uint64_t byte_count) override; |
| 205 void CaptureCertificatePolicyCache( |
| 206 const net::URLRequest* request, |
| 207 const SSLCallback& should_continue) override; |
| 208 void StopRequest(net::URLRequest* request) override; |
| 209 void StopRedirectedRequest(net::URLRequest* request) override; |
| 210 void OnSSLCertificateError(const net::URLRequest* request, |
| 211 const net::SSLInfo& ssl_info, |
| 212 bool recoverable, |
| 213 const SSLCallback& should_continue) override; |
| 214 net::URLRequestContext* GetRequestContext() override; |
| 215 |
| 216 private: |
| 217 friend class base::RefCountedThreadSafe<RequestTrackerImpl>; |
| 218 friend struct RequestTrackerImplTraits; |
| 219 |
| 220 #pragma mark Object lifecycle API |
| 221 // Private. RequestTrackerImpls are created through |
| 222 // CreateTrackerForRequestGroupID(). |
| 223 RequestTrackerImpl(NSString* request_group_id, |
| 224 net::URLRequestContextGetter* context_getter, |
| 225 id<CRWRequestTrackerDelegate> delegate); |
| 226 |
| 227 void InitOnIOThread( |
| 228 const scoped_refptr<web::CertificatePolicyCache>& policy_cache); |
| 229 |
| 230 // Private destructor because the object is reference counted. A no-op; the |
| 231 // useful destruction work happens in Destruct(). |
| 232 ~RequestTrackerImpl() override; |
| 233 |
| 234 // Handles pre-destruction destruction tasks. This is invoked by |
| 235 // RequestTrackerImplTraits::Destruct whenever the reference count of a |
| 236 // RequestTrackerImpl is zero, and this will untimately delete the |
| 237 // RequestTrackerImpl. |
| 238 void Destruct(); |
| 239 |
| 240 #pragma mark Private Provider API |
| 241 // Private methods that implement provider API features. All are only called |
| 242 // on the IO thread. |
| 243 |
| 244 // Called when something has changed (network load progress or SSL status) |
| 245 // that the consumer should know about. Notifications are asynchronous and |
| 246 // batched. |
| 247 void Notify(); |
| 248 |
| 249 // If no other notifications are pending, notifies the consumer of SSL status |
| 250 // and load progress. |
| 251 void StackNotification(); |
| 252 |
| 253 // Notify the consumer about the SSL status of this tracker's page load. |
| 254 void SSLNotify(); |
| 255 |
| 256 // If the counts is for a request currently waiting for the user to approve it |
| 257 // will reevaluate the approval. |
| 258 void EvaluateSSLCallbackForCounts(TrackerCounts* counts); |
| 259 |
| 260 // Loop through all the requests waiting for approval and invoke |
| 261 // |-evaluateSSLCallbackForCounts:| on all the ones with an |UNKNOWN| |
| 262 // judgment. |
| 263 void ReevaluateCallbacksForAllCounts(); |
| 264 |
| 265 // To cancel a rejected request due to a SSL issue. |
| 266 void CancelRequestForCounts(TrackerCounts* counts); |
| 267 |
| 268 // Estimate the page load progress. Returns -1 if the progress didn't change |
| 269 // since the last time this method was invoked. |
| 270 float EstimatedProgress(); |
| 271 |
| 272 // The URL change notification is often late, therefore the mixed content |
| 273 // status and the certificate policies may need to be recomputed. |
| 274 void RecomputeMixedContent(const TrackerCounts* split_position); |
| 275 void RecomputeCertificatePolicy(const TrackerCounts* split_position); |
| 276 |
| 277 // Remove all finished request up to the last instance of |url|. If url is not |
| 278 // found, this will clear all the requests. |
| 279 void TrimToURL(const GURL& url, id user_info); |
| 280 |
| 281 // Sets page_url_ to the new URL if it's a valid history state change (i.e. |
| 282 // the URL's have the same origin) and if the tab is currently loading. |
| 283 void HistoryStateChangeToURL(const GURL& full_url); |
| 284 |
| 285 // Note that the page started by a call to Trim is no longer loading. |
| 286 // |load_success| indicates if the page successfully loaded. |
| 287 void StopPageLoad(const GURL& url, bool load_success); |
| 288 |
| 289 // Cancels all the requests in |live_requests_|. |
| 290 void CancelRequests(); |
| 291 |
| 292 #pragma mark Private Consumer API |
| 293 // Private methods that call into delegate methods. |
| 294 |
| 295 // Notify* methods are posted to the UI thread by the provider API |
| 296 // methods. |
| 297 |
| 298 // Has the delegate handle |headers| for |request_url|. |
| 299 void NotifyResponseHeaders(net::HttpResponseHeaders* headers, |
| 300 const GURL& request_url); |
| 301 |
| 302 // Notifies the deleage of certificate use. |
| 303 void NotifyCertificateUsed(net::X509Certificate* certificate, |
| 304 const std::string& host, |
| 305 net::CertStatus status); |
| 306 |
| 307 // Notifies the deleate of a load completion estimate. |
| 308 void NotifyUpdatedProgress(float estimate); |
| 309 |
| 310 // Has the delegate clear SSL certificates. |
| 311 void NotifyClearCertificates(); |
| 312 |
| 313 // Notifies the delegate of an SSL status update. |
| 314 void NotifyUpdatedSSLStatus(base::scoped_nsobject<CRWSSLCarrier> carrier); |
| 315 |
| 316 // Calls the delegate method to present an SSL error interstitial. |
| 317 void NotifyPresentSSLError(base::scoped_nsobject<CRWSSLCarrier> carrier, |
| 318 bool recoverable); |
| 319 |
| 320 #pragma mark Internal utilities for task posting |
| 321 // Posts |task| to |thread|. Must not be called from |thread|. If |thread| is |
| 322 // the IO thread, silently returns if |is_closing_| is true. |
| 323 void PostTask(const base::Closure& task, web::WebThread::ID thread); |
| 324 |
| 325 // Posts |block| to |thread|, safely passing in |caller| to |block|. |
| 326 void PostBlock(id caller, void (^block)(id), web::WebThread::ID thread); |
| 327 |
| 328 #pragma mark Other internal methods. |
| 329 // Returns the current state of the page. |
| 330 PageCounts pageCounts(); |
| 331 |
| 332 // Like description, but cannot be called from any thread. It must be called |
| 333 // only from the IO thread. |
| 334 NSString* UnsafeDescription(); |
| 335 |
| 336 // Generates a string unique to this RequestTrackerImpl to use with the |
| 337 // CRWNetworkActivityIndicatorManager. |
| 338 NSString* GetNetworkActivityKey(); |
| 339 |
| 340 #pragma mark Non thread-safe fields, only accessed from the main thread. |
| 341 // The RequestTrackerImpl delegate. All changes and access to this object |
| 342 // should be done on the main thread. |
| 343 id<CRWRequestTrackerDelegate> delegate_; // Weak. |
| 344 |
| 345 #pragma mark Non thread-safe fields, only accessed from the IO thread. |
| 346 // All the tracked requests for the page, indexed by net::URLRequest (Cast as |
| 347 // a void* to avoid the temptation of accessing it from the wrong thread). |
| 348 // This map is not exhaustive: it is only meant to estimate the loading |
| 349 // progress, and thus requests corresponding to old navigation events are not |
| 350 // in it. |
| 351 std::map<const void*, TrackerCounts*> counts_by_request_; |
| 352 // All the live requests associated with the tracker. |
| 353 std::set<net::URLRequest*> live_requests_; |
| 354 // A list of all the TrackerCounts, including the finished ones. |
| 355 ScopedVector<TrackerCounts> counts_; |
| 356 // The system shall never allow the page load estimate to go back. |
| 357 float previous_estimate_; |
| 358 // Index of the first request to consider for building the estimation. |
| 359 unsigned int estimate_start_index_; |
| 360 // How many notifications are currently queued, to avoid notifying too often. |
| 361 int notification_depth_; |
| 362 // The tracker containing the error currently presented to the user. |
| 363 TrackerCounts* current_ssl_error_; |
| 364 // Set to |YES| if the page has mixed content |
| 365 bool has_mixed_content_; |
| 366 // Set to true if between TrimToURL and StopPageLoad. |
| 367 bool is_loading_; |
| 368 // Set to true in TrimToURL if starting a new estimate round. Set to false by |
| 369 // StartRequest once the new round is started. |
| 370 bool new_estimate_round_; |
| 371 |
| 372 #pragma mark Other fields. |
| 373 scoped_refptr<web::CertificatePolicyCache> policy_cache_; |
| 374 // If |true| all the requests should be static file requests, otherwise all |
| 375 // the requests should be network requests. This is a constant initialized |
| 376 // in the constructor and read in IO and UI threads. |
| 377 const bool is_for_static_file_requests_; |
| 378 |
| 379 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| 380 // Current page URL, as far as we know. |
| 381 GURL page_url_; |
| 382 // Userinfo attached to the page, passed back by the delegate. |
| 383 base::scoped_nsobject<id> user_info_; |
| 384 // A tracker identifier (a simple increasing number) used to store |
| 385 // certificates. |
| 386 int identifier_; |
| 387 // The string that identifies the tab this tracker serves. Used to index |
| 388 // g_trackers. |
| 389 base::scoped_nsobject<NSString> request_group_id_; |
| 390 // Flag to synchronize deletion and callback creation. Lives on the IO thread. |
| 391 // True when this tracker has beed Close()d. If this is the case, no further |
| 392 // references to it should be generated (for example by binding it into a |
| 393 // callback), and the expectation is that it will soon be deleted. |
| 394 bool is_closing_; |
| 395 }; |
| 396 |
| 397 } // namespace web |
| 398 |
| 399 #endif // IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_ |
OLD | NEW |