Home | History | Annotate | Download | only in prerender
      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/sparse_histogram.h"
      9 #include "base/strings/string_util.h"
     10 #include "content/public/browser/resource_request_info.h"
     11 #include "net/http/http_response_headers.h"
     12 #include "net/url_request/url_request.h"
     13 #include "url/url_canon.h"
     14 #include "url/url_parse.h"
     15 #include "url/url_util.h"
     16 
     17 namespace prerender {
     18 
     19 bool MaybeGetQueryStringBasedAliasURL(
     20     const GURL& url, GURL* alias_url) {
     21   DCHECK(alias_url);
     22   url_parse::Parsed parsed;
     23   url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(),
     24                               &parsed);
     25   url_parse::Component query = parsed.query;
     26   url_parse::Component key, value;
     27   while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key,
     28                                          &value)) {
     29     if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "url", key.len))
     30       continue;
     31     // We found a url= query string component.
     32     if (value.len < 1)
     33       continue;
     34     url_canon::RawCanonOutputW<1024> decoded_url;
     35     url_util::DecodeURLEscapeSequences(url.spec().c_str() + value.begin,
     36                                        value.len, &decoded_url);
     37     GURL new_url(string16(decoded_url.data(), decoded_url.length()));
     38     if (!new_url.is_empty() && new_url.is_valid()) {
     39       *alias_url = new_url;
     40       return true;
     41     }
     42     return false;
     43   }
     44   return false;
     45 }
     46 
     47 uint8 GetQueryStringBasedExperiment(const GURL& url) {
     48   url_parse::Parsed parsed;
     49   url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(),
     50                               &parsed);
     51   url_parse::Component query = parsed.query;
     52   url_parse::Component key, value;
     53   while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key,
     54                                          &value)) {
     55     if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "lpe", key.len))
     56       continue;
     57 
     58     // We found a lpe= query string component.
     59     if (value.len != 1)
     60       continue;
     61     uint8 exp = *(url.spec().c_str() + value.begin) - '0';
     62     if (exp < 1 || exp > 9)
     63       continue;
     64     return exp;
     65   }
     66   return kNoExperiment;
     67 }
     68 
     69 bool IsGoogleDomain(const GURL& url) {
     70   return StartsWithASCII(url.host(), std::string("www.google."), true);
     71 }
     72 
     73 bool IsGoogleSearchResultURL(const GURL& url) {
     74   if (!IsGoogleDomain(url))
     75     return false;
     76   return (url.path().empty() ||
     77           StartsWithASCII(url.path(), std::string("/search"), true) ||
     78           (url.path() == "/") ||
     79           StartsWithASCII(url.path(), std::string("/webhp"), true));
     80 }
     81 
     82 bool IsWebURL(const GURL& url) {
     83   return url.SchemeIs("http") || url.SchemeIs("https");
     84 }
     85 
     86 bool IsNoSwapInExperiment(uint8 experiment_id) {
     87   // Currently, experiments 5 and 6 fall in this category.
     88   return experiment_id == 5 || experiment_id == 6;
     89 }
     90 
     91 bool IsControlGroupExperiment(uint8 experiment_id) {
     92   // Currently, experiments 7 and 8 fall in this category.
     93   return experiment_id == 7 || experiment_id == 8;
     94 }
     95 
     96 void URLRequestResponseStarted(net::URLRequest* request) {
     97   static const char* kModPagespeedHeader = "X-Mod-Pagespeed";
     98   static const char* kModPagespeedHistogram = "Prerender.ModPagespeedHeader";
     99   const content::ResourceRequestInfo* info =
    100       content::ResourceRequestInfo::ForRequest(request);
    101   // Gather histogram information about the X-Mod-Pagespeed header.
    102   if (info->GetResourceType() == ResourceType::MAIN_FRAME &&
    103       IsWebURL(request->url())) {
    104     UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 0);
    105     if (request->response_headers() &&
    106         request->response_headers()->HasHeader(kModPagespeedHeader)) {
    107       UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 1);
    108 
    109       // Attempt to parse the version number, and encode it in buckets
    110       // 2 through 99. 0 and 1 are used to store all pageviews and
    111       // # pageviews with the MPS header (see above).
    112       void* iter = NULL;
    113       std::string mps_version;
    114       if (request->response_headers()->EnumerateHeader(
    115               &iter, kModPagespeedHeader, &mps_version) &&
    116           !mps_version.empty()) {
    117         // Mod Pagespeed versions are of the form a.b.c.d-e
    118         int a, b, c, d, e;
    119         int num_parsed = sscanf(mps_version.c_str(), "%d.%d.%d.%d-%d",
    120                                 &a, &b, &c, &d, &e);
    121         if (num_parsed == 5) {
    122           int output = 2;
    123           if (c > 10)
    124             output += 2 * (c - 10);
    125           if (d > 1)
    126             output++;
    127           if (output < 2 || output >= 99)
    128             output = 99;
    129           UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, output);
    130         }
    131       }
    132     }
    133   }
    134 }
    135 
    136 }  // namespace prerender
    137