- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / prerender / prerender_util.cc
1 // Copyright (c) 2011 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 #include "chrome/browser/prerender/prerender_util.h"
6
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/metrics/sparse_histogram.h"
10 #include "base/strings/string_util.h"
11 #include "content/public/browser/resource_request_info.h"
12 #include "net/http/http_response_headers.h"
13 #include "net/url_request/url_request.h"
14 #include "url/url_canon.h"
15 #include "url/url_parse.h"
16 #include "url/url_util.h"
17 #include "webkit/common/resource_type.h"
18
19 namespace prerender {
20
21 namespace {
22
23 const char kModPagespeedHeader[] = "X-Mod-Pagespeed";
24 const char kPageSpeedHeader[] = "X-Page-Speed";
25 const char kPagespeedServerHistogram[] =
26     "Prerender.PagespeedHeader.ServerCounts";
27 const char kPagespeedVersionHistogram[] =
28     "Prerender.PagespeedHeader.VersionCounts";
29
30 enum PagespeedHeaderServerType {
31   PAGESPEED_TOTAL_RESPONSES = 0,
32   PAGESPEED_MOD_PAGESPEED_SERVER = 1,
33   PAGESPEED_NGX_PAGESPEED_SERVER = 2,
34   PAGESPEED_PAGESPEED_SERVICE_SERVER = 3,
35   PAGESPEED_UNKNOWN_SERVER = 4,
36   PAGESPEED_SERVER_MAXIMUM = 5
37 };
38
39 // Private function to parse the PageSpeed version number and encode it in
40 // buckets 2 through 99: if it is in the format a.b.c.d-e the bucket will be
41 // 2 + 2 * (max(c, 10) - 10) + (d > 1 ? 1 : 0); if it is not in this format
42 // we return zero.
43 int GetXModPagespeedBucketFromVersion(const std::string& version) {
44   int a, b, c, d, e;
45   int num_parsed = sscanf(version.c_str(), "%d.%d.%d.%d-%d",
46                           &a, &b, &c, &d, &e);
47   int output = 0;
48   if (num_parsed == 5) {
49     output = 2;
50     if (c > 10)
51       output += 2 * (c - 10);
52     if (d > 1)
53       output++;
54     if (output < 2 || output > 99)
55       output = 0;
56   }
57   return output;
58 }
59
60 // Private function to parse the X-Page-Speed header value and determine
61 // whether it is in the PageSpeed Service format, namely m_n_dc were m_n is
62 // a version number and dc is an encoded 2-character value.
63 bool IsPageSpeedServiceVersionNumber(const std::string& version) {
64   int a, b;
65   char c, d, e;  // e is to detect EOL as we check that it /isn't/ converted.
66   int num_parsed = sscanf(version.c_str(), "%d_%d_%c%c%c", &a, &b, &c, &d, &e);
67   return (num_parsed == 4);
68 }
69
70 }  // namespace
71
72 bool MaybeGetQueryStringBasedAliasURL(
73     const GURL& url, GURL* alias_url) {
74   DCHECK(alias_url);
75   url_parse::Parsed parsed;
76   url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(),
77                               &parsed);
78   url_parse::Component query = parsed.query;
79   url_parse::Component key, value;
80   while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key,
81                                          &value)) {
82     if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "url", key.len))
83       continue;
84     // We found a url= query string component.
85     if (value.len < 1)
86       continue;
87     url_canon::RawCanonOutputW<1024> decoded_url;
88     url_util::DecodeURLEscapeSequences(url.spec().c_str() + value.begin,
89                                        value.len, &decoded_url);
90     GURL new_url(string16(decoded_url.data(), decoded_url.length()));
91     if (!new_url.is_empty() && new_url.is_valid()) {
92       *alias_url = new_url;
93       return true;
94     }
95     return false;
96   }
97   return false;
98 }
99
100 uint8 GetQueryStringBasedExperiment(const GURL& url) {
101   url_parse::Parsed parsed;
102   url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(),
103                               &parsed);
104   url_parse::Component query = parsed.query;
105   url_parse::Component key, value;
106   while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key,
107                                          &value)) {
108     if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "lpe", key.len))
109       continue;
110
111     // We found a lpe= query string component.
112     if (value.len != 1)
113       continue;
114     uint8 exp = *(url.spec().c_str() + value.begin) - '0';
115     if (exp < 1 || exp > 9)
116       continue;
117     return exp;
118   }
119   return kNoExperiment;
120 }
121
122 bool IsGoogleDomain(const GURL& url) {
123   return StartsWithASCII(url.host(), std::string("www.google."), true);
124 }
125
126 bool IsGoogleSearchResultURL(const GURL& url) {
127   if (!IsGoogleDomain(url))
128     return false;
129   return (url.path().empty() ||
130           StartsWithASCII(url.path(), std::string("/search"), true) ||
131           (url.path() == "/") ||
132           StartsWithASCII(url.path(), std::string("/webhp"), true));
133 }
134
135 bool IsNoSwapInExperiment(uint8 experiment_id) {
136   // Currently, experiments 5 and 6 fall in this category.
137   return experiment_id == 5 || experiment_id == 6;
138 }
139
140 bool IsControlGroupExperiment(uint8 experiment_id) {
141   // Currently, experiments 7 and 8 fall in this category.
142   return experiment_id == 7 || experiment_id == 8;
143 }
144
145 void GatherPagespeedData(const ResourceType::Type resource_type,
146                          const GURL& request_url,
147                          const net::HttpResponseHeaders* response_headers) {
148   if (resource_type != ResourceType::MAIN_FRAME ||
149       !request_url.SchemeIsHTTPOrHTTPS())
150     return;
151
152   // bucket 0 counts every response seen.
153   UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
154                             PAGESPEED_TOTAL_RESPONSES,
155                             PAGESPEED_SERVER_MAXIMUM);
156   if (!response_headers)
157     return;
158
159   void* iter = NULL;
160   std::string name;
161   std::string value;
162   while (response_headers->EnumerateHeaderLines(&iter, &name, &value)) {
163     if (name == kModPagespeedHeader) {
164       // Bucket 1 counts occurences of the X-Mod-Pagespeed header.
165       UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
166                                 PAGESPEED_MOD_PAGESPEED_SERVER,
167                                 PAGESPEED_SERVER_MAXIMUM);
168       if (!value.empty()) {
169         // If the header value is in the X-Mod-Pagespeed version number format
170         // then increment the appropriate bucket, otherwise increment bucket 1,
171         // which is the catch-all "unknown version number" bucket.
172         int bucket = GetXModPagespeedBucketFromVersion(value);
173         if (bucket > 0) {
174           UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, bucket);
175         } else {
176           UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, 1);
177         }
178       }
179       break;
180     } else if (name == kPageSpeedHeader) {
181       // X-Page-Speed header versions are either in the X-Mod-Pagespeed format,
182       // indicating an nginx installation, or they're in the PageSpeed Service
183       // format, indicating a PSS installation, or in some other format,
184       // indicating an unknown installation [possibly IISpeed].
185       if (!value.empty()) {
186         int bucket = GetXModPagespeedBucketFromVersion(value);
187         if (bucket > 0) {
188           // Bucket 2 counts occurences of the X-Page-Speed header with a
189           // value in the X-Mod-Pagespeed version number format. We also
190           // count these responses in the version histogram.
191           UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
192                                     PAGESPEED_NGX_PAGESPEED_SERVER,
193                                     PAGESPEED_SERVER_MAXIMUM);
194           UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, bucket);
195         } else if (IsPageSpeedServiceVersionNumber(value)) {
196           // Bucket 3 counts occurences of the X-Page-Speed header with a
197           // value in the PageSpeed Service version number format.
198           UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
199                                     PAGESPEED_PAGESPEED_SERVICE_SERVER,
200                                     PAGESPEED_SERVER_MAXIMUM);
201         } else {
202           // Bucket 4 counts occurences of all other values.
203           UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram,
204                                     PAGESPEED_UNKNOWN_SERVER,
205                                     PAGESPEED_SERVER_MAXIMUM);
206         }
207       }
208       break;
209     }
210   }
211 }
212
213 void URLRequestResponseStarted(net::URLRequest* request) {
214   const content::ResourceRequestInfo* info =
215       content::ResourceRequestInfo::ForRequest(request);
216   GatherPagespeedData(info->GetResourceType(),
217                       request->url(),
218                       request->response_headers());
219 }
220
221 }  // namespace prerender