// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/mod_pagespeed/mod_pagespeed_metrics.h" #include #include #include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" #include "net/http/http_response_headers.h" #include "url/gurl.h" namespace mod_pagespeed { namespace { const char kModPagespeedHeader[] = "X-Mod-Pagespeed"; const char kPageSpeedHeader[] = "X-Page-Speed"; // For historical reasons, mod_pagespeed usage metrics are named with a // prerender prefix. const char kPagespeedServerHistogram[] = "Prerender.PagespeedHeader.ServerCounts"; const char kPagespeedVersionHistogram[] = "Prerender.PagespeedHeader.VersionCounts"; enum PagespeedHeaderServerType { PAGESPEED_TOTAL_RESPONSES = 0, PAGESPEED_MOD_PAGESPEED_SERVER = 1, PAGESPEED_NGX_PAGESPEED_SERVER = 2, PAGESPEED_PAGESPEED_SERVICE_SERVER = 3, PAGESPEED_UNKNOWN_SERVER = 4, PAGESPEED_SERVER_MAXIMUM = 5 }; // Parse the PageSpeed version number and encodes it in buckets 2 through 99: if // it is in the format MAJOR.MINOR.BRANCH.POINT-COMMIT the bucket will be 2 + 2 // * (max(BRANCH, 10) - 10) + (POINT > 1 ? 1 : 0); otherwise the bucket is // zero. int GetXModPagespeedBucketFromVersion(const std::string& version) { int unused_major, unused_minor, branch, point, unused_commit; int num_parsed = sscanf(version.c_str(), "%d.%d.%d.%d-%d", &unused_major, &unused_minor, &branch, &point, &unused_commit); int output = 0; if (num_parsed == 5) { output = 2; if (branch > 10) output += 2 * (branch - 10); if (point > 1) output++; if (output < 2 || output > 99) output = 0; } return output; } // Parse the X-Page-Speed header value and determine whether it is in the // PageSpeed Service format, namely MAJOR_MINOR_AB were MAJOR_MINOR is a version // number and AB is an encoded 2-character value. bool IsPageSpeedServiceVersionNumber(const std::string& version) { int major, minor; // is_eol is to detect EOL as we check that it /isn't/ converted. char a, b, is_eol; int num_parsed = sscanf(version.c_str(), "%d_%d_%c%c%c", &major, &minor, &a, &b, &is_eol); return (num_parsed == 4); } } // namespace void RecordMetrics(const content::ResourceType resource_type, const GURL& request_url, const net::HttpResponseHeaders* response_headers) { if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME || !request_url.SchemeIsHTTPOrHTTPS()) { return; } // Bucket 0 counts every response seen. UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram, PAGESPEED_TOTAL_RESPONSES, PAGESPEED_SERVER_MAXIMUM); if (!response_headers) return; void* iter = nullptr; std::string name; std::string value; while (response_headers->EnumerateHeaderLines(&iter, &name, &value)) { if (name == kModPagespeedHeader) { // Bucket 1 counts occurrences of the X-Mod-Pagespeed header. UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram, PAGESPEED_MOD_PAGESPEED_SERVER, PAGESPEED_SERVER_MAXIMUM); if (!value.empty()) { // If the header value is in the X-Mod-Pagespeed version number format // then increment the appropriate bucket, otherwise increment bucket 1, // which is the catch-all "unknown version number" bucket. int bucket = GetXModPagespeedBucketFromVersion(value); if (bucket > 0) { UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, bucket); } else { UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, 1); } } break; } else if (name == kPageSpeedHeader) { // X-Page-Speed header versions are either in the X-Mod-Pagespeed format, // indicating an nginx installation, or they're in the PageSpeed Service // format, indicating a PSS installation, or in some other format, // indicating an unknown installation [possibly IISpeed]. if (!value.empty()) { int bucket = GetXModPagespeedBucketFromVersion(value); if (bucket > 0) { // Bucket 2 counts occurences of the X-Page-Speed header with a // value in the X-Mod-Pagespeed version number format. We also // count these responses in the version histogram. UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram, PAGESPEED_NGX_PAGESPEED_SERVER, PAGESPEED_SERVER_MAXIMUM); UMA_HISTOGRAM_SPARSE_SLOWLY(kPagespeedVersionHistogram, bucket); } else if (IsPageSpeedServiceVersionNumber(value)) { // Bucket 3 counts occurences of the X-Page-Speed header with a // value in the PageSpeed Service version number format. UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram, PAGESPEED_PAGESPEED_SERVICE_SERVER, PAGESPEED_SERVER_MAXIMUM); } else { // Bucket 4 counts occurences of all other values. UMA_HISTOGRAM_ENUMERATION(kPagespeedServerHistogram, PAGESPEED_UNKNOWN_SERVER, PAGESPEED_SERVER_MAXIMUM); } } break; } } } } // namespace mod_pagespeed