11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/net/resource_prefetch_predictor_observer.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <string> 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/metrics/histogram.h" 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/browser_thread.h" 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/render_frame_host.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/resource_request_info.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/url_request/url_request.h" 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "url/gurl.h" 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing content::BrowserThread; 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing predictors::ResourcePrefetchPredictor; 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace { 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Enum for measuring statistics pertaining to observed request, responses and 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// redirects. 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum RequestStats { 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci REQUEST_STATS_TOTAL_RESPONSES = 0, 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci REQUEST_STATS_TOTAL_PROCESSED_RESPONSES = 1, 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci REQUEST_STATS_NO_RESOURCE_REQUEST_INFO = 2, 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci REQUEST_STATS_NO_RENDER_FRAME_ID_FROM_REQUEST_INFO = 3, 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci REQUEST_STATS_MAX = 4, 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Specific to main frame requests. 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum MainFrameRequestStats { 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_TOTAL_REQUESTS = 0, 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_PROCESSED_REQUESTS = 1, 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_TOTAL_REDIRECTS = 2, 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_PROCESSED_REDIRECTS = 3, 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_TOTAL_RESPONSES = 4, 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_PROCESSED_RESPONSES = 5, 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_MAX = 6, 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ReportRequestStats(RequestStats stat) { 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.RequestStats", 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci stat, 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci REQUEST_STATS_MAX); 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ReportMainFrameRequestStats(MainFrameRequestStats stat) { 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.MainFrameRequestStats", 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci stat, 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MAIN_FRAME_REQUEST_STATS_MAX); 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool SummarizeResponse(net::URLRequest* request, 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ResourcePrefetchPredictor::URLRequestSummary* summary) { 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const content::ResourceRequestInfo* info = 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::ResourceRequestInfo::ForRequest(request); 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!info) { 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportRequestStats(REQUEST_STATS_NO_RESOURCE_REQUEST_INFO); 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int render_process_id, render_frame_id; 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id)) { 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportRequestStats(REQUEST_STATS_NO_RENDER_FRAME_ID_FROM_REQUEST_INFO); 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->navigation_id.render_process_id = render_process_id; 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->navigation_id.render_frame_id = render_frame_id; 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->navigation_id.main_frame_url = request->first_party_for_cookies(); 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->navigation_id.creation_time = request->creation_time(); 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->resource_url = request->original_url(); 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->resource_type = info->GetResourceType(); 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request->GetMimeType(&summary->mime_type); 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->was_cached = request->was_cached(); 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Use the mime_type to determine the resource type for subresources since 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // types such as PREFETCH, SUB_RESOURCE, etc are not useful. 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (summary->resource_type != content::RESOURCE_TYPE_MAIN_FRAME) { 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->resource_type = 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ResourcePrefetchPredictor::GetResourceTypeFromMimeType( 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->mime_type, 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary->resource_type); 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace chrome_browser_net { 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciResourcePrefetchPredictorObserver::ResourcePrefetchPredictorObserver( 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ResourcePrefetchPredictor* predictor) 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : predictor_(predictor->AsWeakPtr()) { 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciResourcePrefetchPredictorObserver::~ResourcePrefetchPredictorObserver() { 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::CurrentlyOn(BrowserThread::IO)); 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ResourcePrefetchPredictorObserver::OnRequestStarted( 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci net::URLRequest* request, 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::ResourceType resource_type, 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int child_id, 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int frame_id) { 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::IO); 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_TOTAL_REQUESTS); 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!ResourcePrefetchPredictor::ShouldRecordRequest(request, resource_type)) 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ResourcePrefetchPredictor::URLRequestSummary summary; 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary.navigation_id.render_process_id = child_id; 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary.navigation_id.render_frame_id = frame_id; 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary.navigation_id.main_frame_url = request->first_party_for_cookies(); 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary.resource_url = request->original_url(); 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary.resource_type = resource_type; 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::PostTask( 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::UI, 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FROM_HERE, 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&ResourcePrefetchPredictor::RecordURLRequest, 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci predictor_, 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary)); 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_PROCESSED_REQUESTS); 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ResourcePrefetchPredictorObserver::OnRequestRedirected( 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const GURL& redirect_url, 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci net::URLRequest* request) { 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::IO); 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const content::ResourceRequestInfo* request_info = 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::ResourceRequestInfo::ForRequest(request); 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (request_info && 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) { 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_TOTAL_REDIRECTS); 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!ResourcePrefetchPredictor::ShouldRecordRedirect(request)) 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ResourcePrefetchPredictor::URLRequestSummary summary; 1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!SummarizeResponse(request, &summary)) 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary.redirect_url = redirect_url; 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::PostTask( 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::UI, 1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FROM_HERE, 1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&ResourcePrefetchPredictor::RecordURLRedirect, 1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci predictor_, 1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary)); 1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (request_info && 1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) { 1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_PROCESSED_REDIRECTS); 1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ResourcePrefetchPredictorObserver::OnResponseStarted( 1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci net::URLRequest* request) { 1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::IO); 1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportRequestStats(REQUEST_STATS_TOTAL_RESPONSES); 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const content::ResourceRequestInfo* request_info = 1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::ResourceRequestInfo::ForRequest(request); 1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (request_info && 1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) { 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_TOTAL_RESPONSES); 1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!ResourcePrefetchPredictor::ShouldRecordResponse(request)) 1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ResourcePrefetchPredictor::URLRequestSummary summary; 1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!SummarizeResponse(request, &summary)) 1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::PostTask( 1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::UI, 1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FROM_HERE, 1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&ResourcePrefetchPredictor::RecordURLResponse, 1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci predictor_, 1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci summary)); 1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportRequestStats(REQUEST_STATS_TOTAL_PROCESSED_RESPONSES); 1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (request_info && 1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) { 1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_PROCESSED_RESPONSES); 1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace chrome_browser_net 203