| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/page_load_histograms.h" | 5 #include "chrome/renderer/page_load_histograms.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/metrics/field_trial.h" | 11 #include "base/metrics/field_trial.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_split.h" |
| 14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 17 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 18 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
| 19 #include "chrome/renderer/chrome_content_renderer_client.h" | 20 #include "chrome/renderer/chrome_content_renderer_client.h" |
| 20 #include "content/public/common/content_constants.h" | 21 #include "content/public/common/content_constants.h" |
| 21 #include "content/public/renderer/document_state.h" | 22 #include "content/public/renderer/document_state.h" |
| 22 #include "content/public/renderer/render_thread.h" | 23 #include "content/public/renderer/render_thread.h" |
| 23 #include "content/public/renderer/render_view.h" | 24 #include "content/public/renderer/render_view.h" |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 return static_cast<URLPattern::SchemeMasks>(0); | 167 return static_cast<URLPattern::SchemeMasks>(0); |
| 167 } | 168 } |
| 168 | 169 |
| 169 // Returns true if the data reduction proxy was used. Note, this function will | 170 // Returns true if the data reduction proxy was used. Note, this function will |
| 170 // produce a false positive if a page is fetched using SPDY and using a proxy, | 171 // produce a false positive if a page is fetched using SPDY and using a proxy, |
| 171 // and |kDatReductionProxyViaValue| is added to the Via header. | 172 // and |kDatReductionProxyViaValue| is added to the Via header. |
| 172 // TODO(bengr): Plumb the hostname of the proxy from |HttpNetworkTransaction| | 173 // TODO(bengr): Plumb the hostname of the proxy from |HttpNetworkTransaction| |
| 173 // and check if it matches |SPDY_PROXY_AUTH_ORIGIN|. | 174 // and check if it matches |SPDY_PROXY_AUTH_ORIGIN|. |
| 174 bool DataReductionProxyWasUsed(WebFrame* frame) { | 175 bool DataReductionProxyWasUsed(WebFrame* frame) { |
| 175 #if defined(SPDY_PROXY_AUTH_ORIGIN) | 176 #if defined(SPDY_PROXY_AUTH_ORIGIN) |
| 177 const char kDatReductionProxyViaValue[] = "1.1 Chrome Compression Proxy"; |
| 178 return ViaHeaderContains(frame, kDatReductionProxyViaValue); |
| 179 #endif |
| 180 return false; |
| 181 } |
| 182 |
| 183 // Helper function to check for string in 'via' header. Returns true if |
| 184 // |via_value| is one of the values listed in the Via header and the response |
| 185 // was fetched via a proxy. |
| 186 bool ViaHeaderContains(WebFrame* frame, const std::string& via_value) { |
| 176 const char kViaHeaderName[] = "Via"; | 187 const char kViaHeaderName[] = "Via"; |
| 177 const char kDatReductionProxyViaValue[] = "1.1 Chrome Compression Proxy"; | |
| 178 | 188 |
| 179 DocumentState* document_state = | 189 DocumentState* document_state = |
| 180 DocumentState::FromDataSource(frame->dataSource()); | 190 DocumentState::FromDataSource(frame->dataSource()); |
| 181 if (!document_state->was_fetched_via_proxy()) | 191 if (!document_state->was_fetched_via_proxy()) |
| 182 return false; | 192 return false; |
| 183 | 193 |
| 184 std::string via_header(base::UTF16ToUTF8( | 194 std::vector<std::string> values; |
| 185 frame->dataSource()->response().httpHeaderField(kViaHeaderName))); | 195 // Multiple via headers have already been coalesced and hence each value |
| 186 return via_header.find(kDatReductionProxyViaValue) != std::string::npos; | 196 // separated by a comma corresponds to a proxy. The value added by a proxy is |
| 187 #endif | 197 // not expected to contain any commas. |
| 188 return false; | 198 // Example., Via: 1.0 Compression proxy, 1.1 Google promise preview |
| 199 base::SplitString( |
| 200 frame->dataSource()->response().httpHeaderField(kViaHeaderName).utf8(), |
| 201 ',', &values); |
| 202 return std::find(values.begin(), values.end(), via_value) != values.end(); |
| 189 } | 203 } |
| 190 | 204 |
| 191 // Returns true if the provided URL is a referrer string that came from | 205 // Returns true if the provided URL is a referrer string that came from |
| 192 // a Google Web Search results page. This is a little non-deterministic | 206 // a Google Web Search results page. This is a little non-deterministic |
| 193 // because desktop and mobile websearch differ and sometimes just provide | 207 // because desktop and mobile websearch differ and sometimes just provide |
| 194 // http://www.google.com/ as the referrer. In the case of /url we can be sure | 208 // http://www.google.com/ as the referrer. In the case of /url we can be sure |
| 195 // that it came from websearch but we will be generous and allow for cases | 209 // that it came from websearch but we will be generous and allow for cases |
| 196 // where a non-Google URL was provided a bare Google URL as a referrer. | 210 // where a non-Google URL was provided a bare Google URL as a referrer. |
| 197 // The domain validation matches the code used by the prerenderer for similar | 211 // The domain validation matches the code used by the prerenderer for similar |
| 198 // purposes. | 212 // purposes. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 222 return kNoExperiment; | 236 return kNoExperiment; |
| 223 | 237 |
| 224 int experiment_id; | 238 int experiment_id; |
| 225 if (!base::StringToInt(value, &experiment_id)) | 239 if (!base::StringToInt(value, &experiment_id)) |
| 226 return kNoExperiment; | 240 return kNoExperiment; |
| 227 if (0 < experiment_id && experiment_id <= kMaxExperimentID) | 241 if (0 < experiment_id && experiment_id <= kMaxExperimentID) |
| 228 return experiment_id; | 242 return experiment_id; |
| 229 return kNoExperiment; | 243 return kNoExperiment; |
| 230 } | 244 } |
| 231 | 245 |
| 232 // Appends "cerivrj_*" and "gcjeid" query parameters from preview_url to url. | |
| 233 // Returns true if "cerivrj_*" query is found. | |
| 234 // This will be used only for search results URLs. | |
| 235 bool AppendPreviewQueryFromURL(const GURL& preview_url, GURL* url) { | |
| 236 bool preview_query_found = false; | |
| 237 for (net::QueryIterator it(preview_url); !it.IsAtEnd(); it.Advance()) { | |
| 238 const std::string param_name = it.GetKey(); | |
| 239 bool is_preview = StartsWithASCII(param_name, "cerivrj_", true); | |
| 240 if (url && (is_preview || param_name == "gcjeid")) | |
| 241 net::AppendQueryParameter(*url, param_name, it.GetValue()); | |
| 242 preview_query_found = preview_query_found || is_preview; | |
| 243 } | |
| 244 return preview_query_found; | |
| 245 } | |
| 246 | |
| 247 // Returns true if the provided referrer URL is the preview URL of the current | |
| 248 // URL. Preview URL differs from original only with "cerivrj_*", "gcjeid" query | |
| 249 // parameters. | |
| 250 bool IsReferrerPreviewOfURL(const GURL& url, | |
| 251 const base::string16& referrer_str) { | |
| 252 GURL referrer(referrer_str); | |
| 253 if (referrer.is_valid()) { | |
| 254 GURL generated_preview_url(url); | |
| 255 // Now try to copy "cerivrj_*" and "gcjeid" paramters to url and check if | |
| 256 // they exactly match. | |
| 257 if (AppendPreviewQueryFromURL(referrer, &generated_preview_url)) | |
| 258 return generated_preview_url == referrer; | |
| 259 } | |
| 260 return false; | |
| 261 } | |
| 262 | |
| 263 // Returns preview state by looking at url and referer url. | 246 // Returns preview state by looking at url and referer url. |
| 264 void GetPreviewState(const GURL& url, | 247 void GetPreviewState(WebFrame* frame, |
| 265 const base::string16& referrer, | |
| 266 bool came_from_websearch, | 248 bool came_from_websearch, |
| 267 bool data_reduction_proxy_was_used, | 249 bool data_reduction_proxy_was_used, |
| 268 GwsPreviewState* preview_state, | 250 GwsPreviewState* preview_state, |
| 269 int* preview_experiment_id) { | 251 int* preview_experiment_id) { |
| 270 // Conditions for GWS preview are, | 252 // Conditions for GWS preview are, |
| 271 // 1. Data reduction proxy was used. | 253 // 1. Data reduction proxy was used. |
| 272 // 2. URL is loaded from web search. | 254 // Determine the preview state (PREVIEW, PREVIEW_WAS_SHOWN, PREVIEW_NOT_USED) |
| 273 // If the URL contains "cerivrj_*' query parameter record under | 255 // by inspecting the Via header. |
| 274 // "Preview". | |
| 275 if (data_reduction_proxy_was_used) { | 256 if (data_reduction_proxy_was_used) { |
| 276 if (came_from_websearch) { | 257 if (came_from_websearch) { |
| 277 *preview_state = | 258 *preview_state = ViaHeaderContains( |
| 278 AppendPreviewQueryFromURL(url, NULL) ? PREVIEW : PREVIEW_NOT_USED; | 259 frame, "1.1 Google Promise Preview") ? PREVIEW : PREVIEW_NOT_USED; |
| 279 } else if (IsReferrerPreviewOfURL(url, referrer)) { | 260 } else if (ViaHeaderContains(frame, "1.1 Google Promise Original")) { |
| 280 *preview_state = PREVIEW_WAS_SHOWN; | 261 *preview_state = PREVIEW_WAS_SHOWN; |
| 281 *preview_experiment_id = GetQueryStringBasedExperiment(GURL(referrer)); | 262 *preview_experiment_id = GetQueryStringBasedExperiment( |
| 263 GURL(frame->document().referrer())); |
| 282 } | 264 } |
| 283 } | 265 } |
| 284 } | 266 } |
| 285 | 267 |
| 286 void DumpPerformanceTiming(const WebPerformance& performance, | 268 void DumpPerformanceTiming(const WebPerformance& performance, |
| 287 DocumentState* document_state, | 269 DocumentState* document_state, |
| 288 bool data_reduction_proxy_was_used, | 270 bool data_reduction_proxy_was_used, |
| 289 bool came_from_websearch, | 271 bool came_from_websearch, |
| 290 int websearch_chrome_joint_experiment_id, | 272 int websearch_chrome_joint_experiment_id, |
| 291 GwsPreviewState preview_state, | 273 GwsPreviewState preview_state, |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 IsFromGoogleSearchResult(frame->document().url(), | 535 IsFromGoogleSearchResult(frame->document().url(), |
| 554 GURL(frame->document().referrer())); | 536 GURL(frame->document().referrer())); |
| 555 int websearch_chrome_joint_experiment_id = kNoExperiment; | 537 int websearch_chrome_joint_experiment_id = kNoExperiment; |
| 556 if (came_from_websearch) { | 538 if (came_from_websearch) { |
| 557 websearch_chrome_joint_experiment_id = | 539 websearch_chrome_joint_experiment_id = |
| 558 GetQueryStringBasedExperiment(GURL(frame->document().referrer())); | 540 GetQueryStringBasedExperiment(GURL(frame->document().referrer())); |
| 559 } | 541 } |
| 560 | 542 |
| 561 GwsPreviewState preview_state = PREVIEW_NONE; | 543 GwsPreviewState preview_state = PREVIEW_NONE; |
| 562 int preview_experiment_id = websearch_chrome_joint_experiment_id; | 544 int preview_experiment_id = websearch_chrome_joint_experiment_id; |
| 563 GetPreviewState(frame->document().url(), frame->document().referrer(), | 545 GetPreviewState(frame, came_from_websearch, data_reduction_proxy_was_used, |
| 564 came_from_websearch, data_reduction_proxy_was_used, | |
| 565 &preview_state, &preview_experiment_id); | 546 &preview_state, &preview_experiment_id); |
| 566 | 547 |
| 567 // Times based on the Web Timing metrics. | 548 // Times based on the Web Timing metrics. |
| 568 // http://www.w3.org/TR/navigation-timing/ | 549 // http://www.w3.org/TR/navigation-timing/ |
| 569 // TODO(tonyg, jar): We are in the process of vetting these metrics against | 550 // TODO(tonyg, jar): We are in the process of vetting these metrics against |
| 570 // the existing ones. Once we understand any differences, we will standardize | 551 // the existing ones. Once we understand any differences, we will standardize |
| 571 // on a single set of metrics. | 552 // on a single set of metrics. |
| 572 DumpPerformanceTiming(frame->performance(), document_state, | 553 DumpPerformanceTiming(frame->performance(), document_state, |
| 573 data_reduction_proxy_was_used, | 554 data_reduction_proxy_was_used, |
| 574 came_from_websearch, | 555 came_from_websearch, |
| (...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 | 1028 |
| 1048 DCHECK(document_state); | 1029 DCHECK(document_state); |
| 1049 DCHECK(ds); | 1030 DCHECK(ds); |
| 1050 GURL url(ds->request().url()); | 1031 GURL url(ds->request().url()); |
| 1051 Time start = document_state->start_load_time(); | 1032 Time start = document_state->start_load_time(); |
| 1052 Time finish = document_state->finish_load_time(); | 1033 Time finish = document_state->finish_load_time(); |
| 1053 // TODO(mbelshe): should we log more stats? | 1034 // TODO(mbelshe): should we log more stats? |
| 1054 VLOG(1) << "PLT: " << (finish - start).InMilliseconds() << "ms " | 1035 VLOG(1) << "PLT: " << (finish - start).InMilliseconds() << "ms " |
| 1055 << url.spec(); | 1036 << url.spec(); |
| 1056 } | 1037 } |
| OLD | NEW |