15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2010 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CacheableResponseCodes =
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    200: true,
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    203: true,
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    206: true,
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    300: true,
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    301: true,
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    410: true,
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    304: true // Underlying request is cacheable
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {!Array.<!WebInspector.NetworkRequest>} requests
47a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {?Array.<!WebInspector.resourceTypes>} types
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {boolean} needFullResources
49a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @return {!Object.<string, !Array.<!WebInspector.NetworkRequest|string>>}
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.getDomainToResourcesMap = function(requests, types, needFullResources)
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var domainToResourcesMap = {};
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i = 0, size = requests.length; i < size; ++i) {
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var request = requests[i];
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (types && types.indexOf(request.type) === -1)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var parsedURL = request.url.asParsedURL();
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!parsedURL)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domain = parsedURL.host;
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domainResources = domainToResourcesMap[domain];
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (domainResources === undefined) {
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          domainResources = [];
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          domainToResourcesMap[domain] = domainResources;
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        domainResources.push(needFullResources ? request : request.url);
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return domainToResourcesMap;
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.GzipRule = function()
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "network-gzip", WebInspector.UIString("Enable gzip compression"));
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.GzipRule.prototype = {
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
83aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
86a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
89aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var totalSavings = 0;
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var compressedSize = 0;
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var candidateSize = 0;
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var summary = result.addChild("", true);
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0, length = requests.length; i < length; ++i) {
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var request = requests[i];
9751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            if (request.cached || request.statusCode === 304)
9851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                continue; // Do not test cached resources.
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (this._shouldCompress(request)) {
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var size = request.resourceSize;
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                candidateSize += size;
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (this._isCompressed(request)) {
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    compressedSize += size;
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    continue;
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var savings = 2 * size / 3;
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                totalSavings += savings;
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                summary.addFormatted("%r could save ~%s", request.url, Number.bytesToString(savings));
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                result.violationCount++;
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!totalSavings) {
11309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null);
11409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
11509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
11609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        summary.value = WebInspector.UIString("Compressing the following resources with gzip could reduce their transfer size by about two thirds (~%s):", Number.bytesToString(totalSavings));
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        callback(result);
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
120d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
121d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
122d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _isCompressed: function(request)
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var encodingHeader = request.responseHeaderValue("Content-Encoding");
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!encodingHeader)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return /\b(?:gzip|deflate)\b/.test(encodingHeader);
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
132d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
133d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
134d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _shouldCompress: function(request)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.type.isTextType() && request.parsedURL.host && request.resourceSize !== undefined && request.resourceSize > 150;
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CombineExternalResourcesRule = function(id, name, type, resourceTypeName, allowedPerDomain)
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    WebInspector.AuditRule.call(this, id, name);
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._type = type;
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._resourceTypeName = resourceTypeName;
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._allowedPerDomain = allowedPerDomain;
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CombineExternalResourcesRule.prototype = {
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
157aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
160a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
163aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests, [this._type], false);
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var penalizedResourceCount = 0;
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // TODO: refactor according to the chosen i18n approach
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var summary = result.addChild("", true);
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var domain in domainToResourcesMap) {
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var domainResources = domainToResourcesMap[domain];
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var extraResourceCount = domainResources.length - this._allowedPerDomain;
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (extraResourceCount <= 0)
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            penalizedResourceCount += extraResourceCount - 1;
17509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            summary.addChild(WebInspector.UIString("%d %s resources served from %s.", domainResources.length, this._resourceTypeName, WebInspector.AuditRuleResult.resourceDomain(domain)));
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.violationCount += domainResources.length;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
17809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!penalizedResourceCount) {
17909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null);
18009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
18109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
18309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        summary.value = WebInspector.UIString("There are multiple resources served from same domain. Consider combining them into as few files as possible.");
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        callback(result);
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CombineExternalResourcesRule}
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CombineJsResourcesRule = function(allowedPerDomain) {
19509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externaljs", WebInspector.UIString("Combine external JavaScript"), WebInspector.resourceTypes.Script, "JavaScript", allowedPerDomain);
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CombineJsResourcesRule.prototype = {
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CombineExternalResourcesRule.prototype
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CombineExternalResourcesRule}
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CombineCssResourcesRule = function(allowedPerDomain) {
20709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externalcss", WebInspector.UIString("Combine external CSS"), WebInspector.resourceTypes.Stylesheet, "CSS", allowedPerDomain);
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CombineCssResourcesRule.prototype = {
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CombineExternalResourcesRule.prototype
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.MinimizeDnsLookupsRule = function(hostCountThreshold) {
21909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "network-minimizelookups", WebInspector.UIString("Minimize DNS lookups"));
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._hostCountThreshold = hostCountThreshold;
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.MinimizeDnsLookupsRule.prototype = {
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
225aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
228a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
231aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var summary = result.addChild("");
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests, null, false);
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var domain in domainToResourcesMap) {
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (domainToResourcesMap[domain].length > 1)
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var parsedURL = domain.asParsedURL();
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!parsedURL)
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!parsedURL.host.search(WebInspector.AuditRules.IPAddressRegexp))
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue; // an IP address
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            summary.addSnippet(domain);
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.violationCount++;
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
24609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!summary.children || summary.children.length <= this._hostCountThreshold) {
24709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null);
24809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
24909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
25109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        summary.value = WebInspector.UIString("The following domains only serve one resource each. If possible, avoid the extra DNS lookups by serving these resources from existing domains.");
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        callback(result);
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.ParallelizeDownloadRule = function(optimalHostnameCount, minRequestThreshold, minBalanceThreshold)
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
26409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "network-parallelizehosts", WebInspector.UIString("Parallelize downloads across hostnames"));
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._optimalHostnameCount = optimalHostnameCount;
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._minRequestThreshold = minRequestThreshold;
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._minBalanceThreshold = minBalanceThreshold;
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.ParallelizeDownloadRule.prototype = {
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
272aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
275a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
278aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
280d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        /**
281d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)         * @param {string} a
282d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)         * @param {string} b
283d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)         */
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function hostSorter(a, b)
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var aCount = domainToResourcesMap[a].length;
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var bCount = domainToResourcesMap[b].length;
288d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return (aCount < bCount) ? 1 : (aCount === bCount) ? 0 : -1;
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            requests,
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            [WebInspector.resourceTypes.Stylesheet, WebInspector.resourceTypes.Image],
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            true);
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var hosts = [];
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var url in domainToResourcesMap)
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            hosts.push(url);
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
30009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!hosts.length) {
30109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null); // no hosts (local file or something)
30209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
30309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        hosts.sort(hostSorter);
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var optimalHostnameCount = this._optimalHostnameCount;
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (hosts.length > optimalHostnameCount)
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            hosts.splice(optimalHostnameCount);
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var busiestHostResourceCount = domainToResourcesMap[hosts[0]].length;
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var requestCountAboveThreshold = busiestHostResourceCount - this._minRequestThreshold;
31309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (requestCountAboveThreshold <= 0) {
31409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null);
31509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
31609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var avgResourcesPerHost = 0;
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0, size = hosts.length; i < size; ++i)
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            avgResourcesPerHost += domainToResourcesMap[hosts[i]].length;
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Assume optimal parallelization.
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        avgResourcesPerHost /= optimalHostnameCount;
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        avgResourcesPerHost = Math.max(avgResourcesPerHost, 1);
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var pctAboveAvg = (requestCountAboveThreshold / avgResourcesPerHost) - 1.0;
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var minBalanceThreshold = this._minBalanceThreshold;
32809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (pctAboveAvg < minBalanceThreshold) {
32909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null);
33009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
33109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var requestsOnBusiestHost = domainToResourcesMap[hosts[0]];
33409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var entry = result.addChild(WebInspector.UIString("This page makes %d parallelizable requests to %s. Increase download parallelization by distributing the following requests across multiple hostnames.", busiestHostResourceCount, hosts[0]), true);
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < requestsOnBusiestHost.length; ++i)
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entry.addURL(requestsOnBusiestHost[i].url);
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.violationCount = requestsOnBusiestHost.length;
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        callback(result);
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * The reported CSS rule size is incorrect (parsed != original in WebKit),
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * so use percentages instead, which gives a better approximation.
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.UnusedCssRule = function()
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
35309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "page-unusedcss", WebInspector.UIString("Remove unused CSS rules"));
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.UnusedCssRule.prototype = {
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
358aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
361a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
364aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
36651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        /**
367d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)         * @param {!Array.<!WebInspector.AuditRules.ParsedStyleSheet>} styleSheets
36851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)         */
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function evalCallback(styleSheets) {
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!styleSheets.length)
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return callback(null);
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var selectors = [];
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var testedSelectors = {};
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var i = 0; i < styleSheets.length; ++i) {
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var styleSheet = styleSheets[i];
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) {
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    var selectorText = styleSheet.rules[curRule].selectorText;
37993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                    if (testedSelectors[selectorText])
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        continue;
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    selectors.push(selectorText);
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    testedSelectors[selectorText] = 1;
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
38651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            var foundSelectors = {};
38751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
38851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            /**
389d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)             * @param {!Array.<!WebInspector.AuditRules.ParsedStyleSheet>} styleSheets
39051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)             */
39151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            function selectorsCallback(styleSheets)
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            {
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (progress.isCanceled())
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    return;
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var inlineBlockOrdinal = 0;
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var totalStylesheetSize = 0;
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var totalUnusedStylesheetSize = 0;
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var summary;
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var i = 0; i < styleSheets.length; ++i) {
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    var styleSheet = styleSheets[i];
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    var unusedRules = [];
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) {
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        var rule = styleSheet.rules[curRule];
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        if (!testedSelectors[rule.selectorText] || foundSelectors[rule.selectorText])
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                            continue;
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        unusedRules.push(rule.selectorText);
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    }
410926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                    totalStylesheetSize += styleSheet.rules.length;
411926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                    totalUnusedStylesheetSize += unusedRules.length;
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    if (!unusedRules.length)
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        continue;
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    var resource = WebInspector.resourceForURL(styleSheet.sourceURL);
417d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                    var isInlineBlock = resource && resource.request && resource.request.type === WebInspector.resourceTypes.Document;
41809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                    var url = !isInlineBlock ? WebInspector.AuditRuleResult.linkifyDisplayName(styleSheet.sourceURL) : WebInspector.UIString("Inline block #%d", ++inlineBlockOrdinal);
419926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                    var pctUnused = Math.round(100 * unusedRules.length / styleSheet.rules.length);
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    if (!summary)
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        summary = result.addChild("", true);
422926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                    var entry = summary.addFormatted("%s: %d% is not used by the current page.", url, pctUnused);
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    for (var j = 0; j < unusedRules.length; ++j)
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        entry.addSnippet(unusedRules[j]);
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    result.violationCount += unusedRules.length;
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!totalUnusedStylesheetSize)
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    return callback(null);
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var totalUnusedPercent = Math.round(100 * totalUnusedStylesheetSize / totalStylesheetSize);
43409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                summary.value = WebInspector.UIString("%s rules (%d%) of CSS not used by the current page.", totalUnusedStylesheetSize, totalUnusedPercent);
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                callback(result);
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
43951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            /**
44051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)             * @param {?function()} boundSelectorsCallback
44151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)             * @param {string} selector
44251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)             * @param {?DOMAgent.NodeId} nodeId
44351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)             */
44451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            function queryCallback(boundSelectorsCallback, selector, nodeId)
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            {
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (nodeId)
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    foundSelectors[selector] = true;
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (boundSelectorsCallback)
44951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                    boundSelectorsCallback();
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
45251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)            /**
453a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)             * @param {!Array.<string>} selectors
454a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)             * @param {!WebInspector.DOMDocument} document
45551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)             */
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            function documentLoaded(selectors, document) {
45793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                var pseudoSelectorRegexp = /::?(?:[\w-]+)(?:\(.*?\))?/g;
45851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                if (!selectors.length) {
45951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                    selectorsCallback([]);
46051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                    return;
46151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)                }
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var i = 0; i < selectors.length; ++i) {
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    if (progress.isCanceled())
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        return;
46593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                    var effectiveSelector = selectors[i].replace(pseudoSelectorRegexp, "");
466aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                    target.domModel.querySelector(document.id, effectiveSelector, queryCallback.bind(null, i === selectors.length - 1 ? selectorsCallback.bind(null, styleSheets) : null, selectors[i]));
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
470aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            target.domModel.requestDocument(documentLoaded.bind(null, selectors));
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
473aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        var styleSheetInfos = target.cssModel.allStyleSheets();
47409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!styleSheetInfos || !styleSheetInfos.length) {
47509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            evalCallback([]);
47609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
47709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
478d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        var styleSheetProcessor = new WebInspector.AuditRules.StyleSheetProcessor(styleSheetInfos, progress, evalCallback);
479d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        styleSheetProcessor.run();
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
486d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * @typedef {!{sourceURL: string, rules: !Array.<!WebInspector.CSSParser.StyleRule>}}
487d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) */
488d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)WebInspector.AuditRules.ParsedStyleSheet;
489d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
490d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)/**
491d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * @constructor
492d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * @param {!Array.<!WebInspector.CSSStyleSheetHeader>} styleSheetHeaders
493d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * @param {!WebInspector.Progress} progress
494d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * @param {!function(!Array.<!WebInspector.AuditRules.ParsedStyleSheet>)} styleSheetsParsedCallback
495d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) */
496d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)WebInspector.AuditRules.StyleSheetProcessor = function(styleSheetHeaders, progress, styleSheetsParsedCallback)
497d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
498d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    this._styleSheetHeaders = styleSheetHeaders;
499d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    this._progress = progress;
500d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    this._styleSheets = [];
501d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    this._styleSheetsParsedCallback = styleSheetsParsedCallback;
502d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
503d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
504d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)WebInspector.AuditRules.StyleSheetProcessor.prototype = {
505d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    run: function()
506d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
507d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._parser = new WebInspector.CSSParser();
508d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._processNextStyleSheet();
509d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
510d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
511d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    _terminateWorker: function()
512d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
513d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (this._parser) {
514d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            this._parser.dispose();
515d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            delete this._parser;
516d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
517d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
518d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
519d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    _finish: function()
520d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
521d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._terminateWorker();
522d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._styleSheetsParsedCallback(this._styleSheets);
523d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
524d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
525d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    _processNextStyleSheet: function()
526d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
527d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (!this._styleSheetHeaders.length) {
528d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            this._finish();
529d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return;
530d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
531d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._currentStyleSheetHeader = this._styleSheetHeaders.shift();
532d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._parser.fetchAndParse(this._currentStyleSheetHeader, this._onStyleSheetParsed.bind(this));
533d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
534d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
535d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
536d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!Array.<!WebInspector.CSSParser.Rule>} rules
537d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
538d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    _onStyleSheetParsed: function(rules)
539d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
540d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (this._progress.isCanceled()) {
541d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            this._terminateWorker();
542d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return;
543d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
544d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
545d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        var styleRules = [];
546d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        for (var i = 0; i < rules.length; ++i) {
547d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            var rule = rules[i];
548d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            if (rule.selectorText)
549d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                styleRules.push(rule);
550d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
551d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._styleSheets.push({
552d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            sourceURL: this._currentStyleSheetHeader.sourceURL,
553d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            rules: styleRules
554d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        });
555d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this._processNextStyleSheet();
556d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
557d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
558d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
559d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)/**
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CacheControlRule = function(id, name)
5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    WebInspector.AuditRule.call(this, id, name);
5665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CacheControlRule.MillisPerMonth = 1000 * 60 * 60 * 24 * 30;
5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CacheControlRule.prototype = {
5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
572aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
575a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(!WebInspector.AuditRuleResult)} callback
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
578aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
5805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResources(requests);
5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (cacheableAndNonCacheableResources[0].length)
5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this.runChecks(cacheableAndNonCacheableResources[0], result);
5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], result);
5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        callback(result);
5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    handleNonCacheableResources: function(requests, result)
5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _cacheableAndNonCacheableResources: function(requests)
5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var processedResources = [[], []];
5955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < requests.length; ++i) {
5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var request = requests[i];
5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!this.isCacheableResource(request))
5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (this._isExplicitlyNonCacheable(request))
6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                processedResources[1].push(request);
6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                processedResources[0].push(request);
6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return processedResources;
6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    execCheck: function(messageText, requestCheckFunction, requests, result)
6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var requestCount = requests.length;
6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var urls = [];
6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < requestCount; ++i) {
6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (requestCheckFunction.call(this, requests[i]))
6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                urls.push(requests[i].url);
6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (urls.length) {
6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var entry = result.addChild(messageText, true);
6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entry.addURLs(urls);
6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.violationCount += urls.length;
6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
62209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
62309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
62409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {number} timeMs
62509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
62609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    freshnessLifetimeGreaterThan: function(request, timeMs)
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var dateHeader = this.responseHeader(request, "Date");
6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!dateHeader)
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var dateHeaderMs = Date.parse(dateHeader);
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (isNaN(dateHeaderMs))
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var freshnessLifetimeMs;
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var maxAgeMatch = this.responseHeaderMatch(request, "Cache-Control", "max-age=(\\d+)");
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (maxAgeMatch)
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            freshnessLifetimeMs = (maxAgeMatch[1]) ? 1000 * maxAgeMatch[1] : 0;
6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else {
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var expiresHeader = this.responseHeader(request, "Expires");
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (expiresHeader) {
6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var expDate = Date.parse(expiresHeader);
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!isNaN(expDate))
6475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    freshnessLifetimeMs = expDate - dateHeaderMs;
6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
6495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (isNaN(freshnessLifetimeMs)) ? false : freshnessLifetimeMs > timeMs;
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
65409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
65509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
65609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {string} header
65709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {string|undefined}
65809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    responseHeader: function(request, header)
6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.responseHeaderValue(header);
6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
66409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
66509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
66609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {string} header
66709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
66809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    hasResponseHeader: function(request, header)
6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.responseHeaderValue(header) !== undefined;
6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
67409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
67509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
67609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
67709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    isCompressible: function(request)
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.type.isTextType();
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
68309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
68409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
68509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
68609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    isPubliclyCacheable: function(request)
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this._isExplicitlyNonCacheable(request))
6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this.responseHeaderMatch(request, "Cache-Control", "public"))
6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return true;
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
695d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return request.url.indexOf("?") === -1 && !this.responseHeaderMatch(request, "Cache-Control", "private");
6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
69809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
69909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
70009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {string} header
70109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {string} regexp
70209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {?Array.<string>}
70309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    responseHeaderMatch: function(request, header, regexp)
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.responseHeaderValue(header)
7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ? request.responseHeaderValue(header).match(new RegExp(regexp, "im"))
70809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            : null;
7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
71109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
71209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
71309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
71409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    hasExplicitExpiration: function(request)
7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this.hasResponseHeader(request, "Date") &&
71809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            (this.hasResponseHeader(request, "Expires") || !!this.responseHeaderMatch(request, "Cache-Control", "max-age"));
7195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
72109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
72209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
72309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
72409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _isExplicitlyNonCacheable: function(request)
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var hasExplicitExp = this.hasExplicitExpiration(request);
72809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return !!this.responseHeaderMatch(request, "Cache-Control", "(no-cache|no-store|must-revalidate)") ||
72909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            !!this.responseHeaderMatch(request, "Pragma", "no-cache") ||
7305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            (hasExplicitExp && !this.freshnessLifetimeGreaterThan(request, 0)) ||
73109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            (!hasExplicitExp && !!request.url && request.url.indexOf("?") >= 0) ||
7325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            (!hasExplicitExp && !this.isCacheableResource(request));
7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
73509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    /**
73609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
73709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     * @return {boolean}
73809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)     */
7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    isCacheableResource: function(request)
7405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.statusCode !== undefined && WebInspector.AuditRules.CacheableResponseCodes[request.statusCode];
7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CacheControlRule}
7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
7515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.BrowserCacheControlRule = function()
7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
75309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CacheControlRule.call(this, "http-browsercache", WebInspector.UIString("Leverage browser caching"));
7545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.BrowserCacheControlRule.prototype = {
7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    handleNonCacheableResources: function(requests, result)
7585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (requests.length) {
76009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            var entry = result.addChild(WebInspector.UIString("The following resources are explicitly non-cacheable. Consider making them cacheable if possible:"), true);
7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.violationCount += requests.length;
7625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var i = 0; i < requests.length; ++i)
7635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                entry.addURL(requests[i].url);
7645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    runChecks: function(requests, result, callback)
7685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
76909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:"),
7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._missingExpirationCheck, requests, result);
77109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("The following resources specify a \"Vary\" header that disables caching in most versions of Internet Explorer:"),
7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._varyCheck, requests, result);
77309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("The following cacheable resources have a short freshness lifetime:"),
7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._oneMonthExpirationCheck, requests, result);
7755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Unable to implement the favicon check due to the WebKit limitations.
77709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("To further improve cache hit rate, specify an expiration one year in the future for the following cacheable resources:"),
7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._oneYearExpirationCheck, requests, result);
7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _missingExpirationCheck: function(request)
7825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this.isCacheableResource(request) && !this.hasResponseHeader(request, "Set-Cookie") && !this.hasExplicitExpiration(request);
7845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _varyCheck: function(request)
7875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var varyHeader = this.responseHeader(request, "Vary");
7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (varyHeader) {
7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            varyHeader = varyHeader.replace(/User-Agent/gi, "");
7915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            varyHeader = varyHeader.replace(/Accept-Encoding/gi, "");
7925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            varyHeader = varyHeader.replace(/[, ]*/g, "");
7935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return varyHeader && varyHeader.length && this.isCacheableResource(request) && this.freshnessLifetimeGreaterThan(request, 0);
7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
7965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _oneMonthExpirationCheck: function(request)
7985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
7995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this.isCacheableResource(request) &&
8005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.hasResponseHeader(request, "Set-Cookie") &&
8015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.freshnessLifetimeGreaterThan(request, WebInspector.AuditRules.CacheControlRule.MillisPerMonth) &&
8025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this.freshnessLifetimeGreaterThan(request, 0);
8035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
8045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _oneYearExpirationCheck: function(request)
8065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
8075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this.isCacheableResource(request) &&
8085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.hasResponseHeader(request, "Set-Cookie") &&
8095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.freshnessLifetimeGreaterThan(request, 11 * WebInspector.AuditRules.CacheControlRule.MillisPerMonth) &&
8105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this.freshnessLifetimeGreaterThan(request, WebInspector.AuditRules.CacheControlRule.MillisPerMonth);
8115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
8125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CacheControlRule.prototype
8145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
8175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
8185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CacheControlRule}
8195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
8205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.ProxyCacheControlRule = function() {
82109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CacheControlRule.call(this, "http-proxycache", WebInspector.UIString("Leverage proxy caching"));
8225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.ProxyCacheControlRule.prototype = {
8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    runChecks: function(requests, result, callback)
8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
82709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("Resources with a \"?\" in the URL are not cached by most proxy caching servers:"),
8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._questionMarkCheck, requests, result);
82909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("Consider adding a \"Cache-Control: public\" header to the following resources:"),
8305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._publicCachingCheck, requests, result);
83109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.execCheck(WebInspector.UIString("The following publicly cacheable resources contain a Set-Cookie header. This security vulnerability can cause cookies to be shared by multiple users."),
8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._setCookieCacheableCheck, requests, result);
8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
8345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _questionMarkCheck: function(request)
8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return request.url.indexOf("?") >= 0 && !this.hasResponseHeader(request, "Set-Cookie") && this.isPubliclyCacheable(request);
8385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
8395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _publicCachingCheck: function(request)
8415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
8425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this.isCacheableResource(request) &&
8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.isCompressible(request) &&
8445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.responseHeaderMatch(request, "Cache-Control", "public") &&
8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            !this.hasResponseHeader(request, "Set-Cookie");
8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _setCookieCacheableCheck: function(request)
8495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return this.hasResponseHeader(request, "Set-Cookie") && this.isPubliclyCacheable(request);
8515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
8525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CacheControlRule.prototype
8545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
8575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
8585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
8595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
8605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.ImageDimensionsRule = function()
8615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
86209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "page-imagedims", WebInspector.UIString("Specify image dimensions"));
8635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.ImageDimensionsRule.prototype = {
8665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
867aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
8685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
870a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
8725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
873aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var urlToNoDimensionCount = {};
8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function doneCallback()
8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
8795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var url in urlToNoDimensionCount) {
88009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                var entry = entry || result.addChild(WebInspector.UIString("A width and height should be specified for all images in order to speed up page display. The following image(s) are missing a width and/or height:"), true);
8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var format = "%r";
8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (urlToNoDimensionCount[url] > 1)
8835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    format += " (%d uses)";
8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                entry.addFormatted(format, url, urlToNoDimensionCount[url]);
8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                result.violationCount++;
8865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
8875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            callback(entry ? result : null);
8885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
8895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function imageStylesReady(imageId, styles, isLastStyle, computedStyle)
8915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
8925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
8935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
8945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
895aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            const node = target.domModel.nodeForId(imageId);
8965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var src = node.getAttribute("src");
8975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!src.asParsedURL()) {
8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    if (frameOwnerCandidate.baseURL) {
9005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        var completeSrc = WebInspector.ParsedURL.completeURL(frameOwnerCandidate.baseURL, src);
9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        break;
9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    }
9035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
9045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (completeSrc)
9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                src = completeSrc;
9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (computedStyle.getPropertyValue("position") === "absolute") {
9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (isLastStyle)
9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    doneCallback();
9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (styles.attributesStyle) {
9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var widthFound = !!styles.attributesStyle.getLiveProperty("width");
9165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var heightFound = !!styles.attributesStyle.getLiveProperty("height");
9175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var inlineStyle = styles.inlineStyle;
9205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (inlineStyle) {
9215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (inlineStyle.getPropertyValue("width") !== "")
9225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    widthFound = true;
9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (inlineStyle.getPropertyValue("height") !== "")
9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    heightFound = true;
9255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var i = styles.matchedCSSRules.length - 1; i >= 0 && !(widthFound && heightFound); --i) {
9285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var style = styles.matchedCSSRules[i].style;
9295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (style.getPropertyValue("width") !== "")
9305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    widthFound = true;
9315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (style.getPropertyValue("height") !== "")
9325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    heightFound = true;
9335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!widthFound || !heightFound) {
9365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (src in urlToNoDimensionCount)
9375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    ++urlToNoDimensionCount[src];
9385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                else
9395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    urlToNoDimensionCount[src] = 1;
9405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (isLastStyle)
9435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                doneCallback();
9445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
9455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
946a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
947a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>=} nodeIds
948a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
9495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function getStyles(nodeIds)
9505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
9515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
9525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
9535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var targetResult = {};
9545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            function inlineCallback(inlineStyle, attributesStyle)
9565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            {
9575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                targetResult.inlineStyle = inlineStyle;
9585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                targetResult.attributesStyle = attributesStyle;
9595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            function matchedCallback(result)
9625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            {
9635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (result)
9645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    targetResult.matchedCSSRules = result.matchedCSSRules;
9655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!nodeIds || !nodeIds.length)
9685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                doneCallback();
9695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var i = 0; nodeIds && i < nodeIds.length; ++i) {
971aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                target.cssModel.getMatchedStylesAsync(nodeIds[i], false, false, matchedCallback);
972aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                target.cssModel.getInlineStylesAsync(nodeIds[i], inlineCallback);
973aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                target.cssModel.getComputedStyleAsync(nodeIds[i], imageStylesReady.bind(null, nodeIds[i], targetResult, i === nodeIds.length - 1));
9745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
9755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
9765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function onDocumentAvailable(root)
9785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
9795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
9805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
981aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            target.domModel.querySelectorAll(root.id, "img[src]", getStyles);
9825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
9835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (progress.isCanceled())
9855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
986aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        target.domModel.requestDocument(onDocumentAvailable);
9875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
9885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
9905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
9935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
9945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
9955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
9965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CssInHeadRule = function()
9975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
99809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "page-cssinhead", WebInspector.UIString("Put CSS in the document head"));
9995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
10005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CssInHeadRule.prototype = {
10025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1003aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
10045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
10055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1006a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
10075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
10085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1009aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
10105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
10115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function evalCallback(evalResult)
10125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
10135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
10145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
10155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!evalResult)
10175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return callback(null);
10185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var summary = result.addChild("");
10205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var outputMessages = [];
10225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var url in evalResult) {
10235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var urlViolations = evalResult[url];
10245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (urlViolations[0]) {
10255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    result.addFormatted("%s style block(s) in the %r body should be moved to the document head.", urlViolations[0], url);
10265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    result.violationCount += urlViolations[0];
10275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
10285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var i = 0; i < urlViolations[1].length; ++i)
10295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    result.addFormatted("Link node %r should be moved to the document head in %r", urlViolations[1][i], url);
10305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                result.violationCount += urlViolations[1].length;
10315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
103209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            summary.value = WebInspector.UIString("CSS in the document body adversely impacts rendering performance.");
10335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            callback(result);
10345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1036a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
1037f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)         * @param {!WebInspector.DOMNode} root
1038f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>=} inlineStyleNodeIds
1039a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>=} nodeIds
1040a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
10415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function externalStylesheetsReceived(root, inlineStyleNodeIds, nodeIds)
10425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
10435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
10445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
10455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!nodeIds)
10475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
10485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var externalStylesheetNodeIds = nodeIds;
10495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var result = null;
10505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (inlineStyleNodeIds.length || externalStylesheetNodeIds.length) {
10515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var urlToViolationsArray = {};
10525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var externalStylesheetHrefs = [];
10535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var j = 0; j < externalStylesheetNodeIds.length; ++j) {
1054aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                    var linkNode = target.domModel.nodeForId(externalStylesheetNodeIds[j]);
10555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    var completeHref = WebInspector.ParsedURL.completeURL(linkNode.ownerDocument.baseURL, linkNode.getAttribute("href"));
10565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    externalStylesheetHrefs.push(completeHref || "<empty>");
10575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
10585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                urlToViolationsArray[root.documentURL] = [inlineStyleNodeIds.length, externalStylesheetHrefs];
10595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                result = urlToViolationsArray;
10605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
10615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            evalCallback(result);
10625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1064a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
1065f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)         * @param {!WebInspector.DOMNode} root
1066a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>=} nodeIds
1067a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
10685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function inlineStylesReceived(root, nodeIds)
10695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
10705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
10715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
10725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!nodeIds)
10745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
1075aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            target.domModel.querySelectorAll(root.id, "body link[rel~='stylesheet'][href]", externalStylesheetsReceived.bind(null, root, nodeIds));
10765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1078f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        /**
1079f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)         * @param {!WebInspector.DOMNode} root
1080f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)         */
10815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function onDocumentAvailable(root)
10825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
10835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
10845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
10855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1086aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            target.domModel.querySelectorAll(root.id, "body style", inlineStylesReceived.bind(null, root));
10875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
10885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1089aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        target.domModel.requestDocument(onDocumentAvailable);
10905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
10915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
10935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
10945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
10965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
10975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
10985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
10995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.StylesScriptsOrderRule = function()
11005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
110109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRule.call(this, "page-stylescriptorder", WebInspector.UIString("Optimize the order of styles and scripts"));
11025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.StylesScriptsOrderRule.prototype = {
11055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1106aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
11075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
11085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1109a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
11105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
11115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1112aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
11135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
11145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function evalCallback(resultValue)
11155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
11165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
11175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
11185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!resultValue)
11205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return callback(null);
11215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var lateCssUrls = resultValue[0];
11235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var cssBeforeInlineCount = resultValue[1];
11245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
112506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)            if (lateCssUrls.length) {
112609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                var entry = result.addChild(WebInspector.UIString("The following external CSS files were included after an external JavaScript file in the document head. To ensure CSS files are downloaded in parallel, always include external CSS before external JavaScript."), true);
112706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)                entry.addURLs(lateCssUrls);
112806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)                result.violationCount += lateCssUrls.length;
112906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)            }
11305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (cssBeforeInlineCount) {
113209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                result.addChild(WebInspector.UIString(" %d inline script block%s found in the head between an external CSS file and another resource. To allow parallel downloading, move the inline script before the external CSS file, or after the next resource.", cssBeforeInlineCount, cssBeforeInlineCount > 1 ? "s were" : " was"));
11335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                result.violationCount += cssBeforeInlineCount;
11345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
11355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            callback(result);
11365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1138a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
1139a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>} lateStyleIds
1140a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>=} nodeIds
1141a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
11425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function cssBeforeInlineReceived(lateStyleIds, nodeIds)
11435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
11445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
11455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
11465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!nodeIds)
11485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
11495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var cssBeforeInlineCount = nodeIds.length;
11515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var result = null;
11525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (lateStyleIds.length || cssBeforeInlineCount) {
11535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                var lateStyleUrls = [];
11545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                for (var i = 0; i < lateStyleIds.length; ++i) {
1155aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch                    var lateStyleNode = target.domModel.nodeForId(lateStyleIds[i]);
11565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    var completeHref = WebInspector.ParsedURL.completeURL(lateStyleNode.ownerDocument.baseURL, lateStyleNode.getAttribute("href"));
11575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    lateStyleUrls.push(completeHref || "<empty>");
11585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
11595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                result = [ lateStyleUrls, cssBeforeInlineCount ];
11605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
11615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            evalCallback(result);
11635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1165a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
1166a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!WebInspector.DOMDocument} root
1167a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!Array.<!DOMAgent.NodeId>=} nodeIds
1168a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
11695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function lateStylesReceived(root, nodeIds)
11705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
11715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
11725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
11735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!nodeIds)
11755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
11765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1177aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            target.domModel.querySelectorAll(root.id, "head link[rel~='stylesheet'][href] ~ script:not([src])", cssBeforeInlineReceived.bind(null, nodeIds));
11785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1180a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)        /**
1181a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         * @param {!WebInspector.DOMDocument} root
1182a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)         */
11835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function onDocumentAvailable(root)
11845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
11855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
11865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
11875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1188aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch            target.domModel.querySelectorAll(root.id, "head script[src] ~ link[rel~='stylesheet'][href]", lateStylesReceived.bind(null, root));
11895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1191aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        target.domModel.requestDocument(onDocumentAvailable);
11925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
11935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
11955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
11985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
11995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
12005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
12015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CSSRuleBase = function(id, name)
12025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
12035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    WebInspector.AuditRule.call(this, id, name);
12045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
12055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CSSRuleBase.prototype = {
12075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1208aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
12095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
12105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1211a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(?WebInspector.AuditRuleResult)} callback
12125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
12135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1214aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
12155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1216aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        var headers = target.cssModel.allStyleSheets();
12175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
121809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!headers.length) {
121909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            callback(null);
122009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return;
122109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
1222d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        var activeHeaders = []
122309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        for (var i = 0; i < headers.length; ++i) {
1224d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            if (!headers[i].disabled)
1225d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                activeHeaders.push(headers[i]);
12265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
12275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1228d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        var styleSheetProcessor = new WebInspector.AuditRules.StyleSheetProcessor(activeHeaders, progress, this._styleSheetsLoaded.bind(this, result, callback, progress));
1229d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        styleSheetProcessor.run();
12305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
12315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1232d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1233d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1234d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {function(!WebInspector.AuditRuleResult)} callback
1235d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
1236d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!Array.<!WebInspector.AuditRules.ParsedStyleSheet>} styleSheets
1237d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1238d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    _styleSheetsLoaded: function(result, callback, progress, styleSheets)
12395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1240d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        for (var i = 0; i < styleSheets.length; ++i)
1241d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            this._visitStyleSheet(styleSheets[i], result);
1242d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        callback(result);
1243d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    },
12445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1245d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1246d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1247d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1248d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1249d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    _visitStyleSheet: function(styleSheet, result)
1250d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    {
1251d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this.visitStyleSheet(styleSheet, result);
12525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1253d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        for (var i = 0; i < styleSheet.rules.length; ++i)
1254d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            this._visitRule(styleSheet, styleSheet.rules[i], result);
12555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1256d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        this.didVisitStyleSheet(styleSheet, result);
12575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
12585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1259d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1260d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1261d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.StyleRule} rule
1262d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1263d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
12645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _visitRule: function(styleSheet, rule, result)
12655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
12665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.visitRule(styleSheet, rule, result);
1267d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        var allProperties = rule.properties;
12685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < allProperties.length; ++i)
1269d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            this.visitProperty(styleSheet, rule, allProperties[i], result);
12705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.didVisitRule(styleSheet, rule, result);
12715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
12725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1273d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1274d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1275d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1276d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
12775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    visitStyleSheet: function(styleSheet, result)
12785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
12795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Subclasses can implement.
12805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
12815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1282d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1283d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1284d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1285d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
12865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    didVisitStyleSheet: function(styleSheet, result)
12875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
12885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Subclasses can implement.
12895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1290d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1291d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1292d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1293d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.StyleRule} rule
1294d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1295d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
12965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    visitRule: function(styleSheet, rule, result)
12975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
12985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Subclasses can implement.
12995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1301d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1302d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1303d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.StyleRule} rule
1304d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1305d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
13065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    didVisitRule: function(styleSheet, rule, result)
13075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Subclasses can implement.
13095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1310d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
1311d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1312d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1313d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.StyleRule} rule
1314d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.Property} property
1315d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1316d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1317d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    visitProperty: function(styleSheet, rule, property, result)
13185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Subclasses can implement.
13205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
13235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
13265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
13275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CSSRuleBase}
13285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
13295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.VendorPrefixedCSSProperties = function()
13305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
133109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CSSRuleBase.call(this, "page-vendorprefixedcss", WebInspector.UIString("Use normal CSS property names instead of vendor-prefixed ones"));
13325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._webkitPrefix = "-webkit-";
13335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.VendorPrefixedCSSProperties.supportedProperties = [
13365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "background-clip", "background-origin", "background-size",
13375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "border-radius", "border-bottom-left-radius", "border-bottom-right-radius", "border-top-left-radius", "border-top-right-radius",
13385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "box-shadow", "box-sizing", "opacity", "text-shadow"
13395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)].keySet();
13405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.VendorPrefixedCSSProperties.prototype = {
1342d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1343d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1344d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
13455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    didVisitStyleSheet: function(styleSheet)
13465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        delete this._styleSheetResult;
13485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1350d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1351d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.StyleRule} rule
1352d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
13535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    visitRule: function(rule)
13545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._mentionedProperties = {};
13565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    didVisitRule: function()
13595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        delete this._ruleResult;
13615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        delete this._mentionedProperties;
13625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1364d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    /**
1365d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet
1366d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.StyleRule} rule
1367d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.CSSParser.Property} property
1368d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1369d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)     */
1370d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    visitProperty: function(styleSheet, rule, property, result)
13715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
13725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!property.name.startsWith(this._webkitPrefix))
13735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
13745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var normalPropertyName = property.name.substring(this._webkitPrefix.length).toLowerCase(); // Start just after the "-webkit-" prefix.
13765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (WebInspector.AuditRules.VendorPrefixedCSSProperties.supportedProperties[normalPropertyName] && !this._mentionedProperties[normalPropertyName]) {
13775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._mentionedProperties[normalPropertyName] = true;
13785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!this._styleSheetResult)
1379d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                this._styleSheetResult = result.addChild(styleSheet.sourceURL ? WebInspector.linkifyResourceAsNode(styleSheet.sourceURL) : WebInspector.UIString("<unknown>"));
13805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!this._ruleResult) {
1381d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                var anchor = WebInspector.linkifyURLAsNode(styleSheet.sourceURL, rule.selectorText);
1382d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)                anchor.lineNumber = rule.lineNumber;
13835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                this._ruleResult = this._styleSheetResult.addChild(anchor);
13845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
13855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ++result.violationCount;
138609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            this._ruleResult.addSnippet(WebInspector.UIString("\"%s%s\" is used, but \"%s\" is supported.", this._webkitPrefix, normalPropertyName, normalPropertyName));
13875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
13885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
13895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CSSRuleBase.prototype
13915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
13945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
13955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRule}
13965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
13975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CookieRuleBase = function(id, name)
13985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    WebInspector.AuditRule.call(this, id, name);
14005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CookieRuleBase.prototype = {
14035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1404aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch     * @param {!WebInspector.Target} target
14055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
14065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.AuditRuleResult} result
1407a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {function(!WebInspector.AuditRuleResult)} callback
14085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
14095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1410aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    doRun: function(target, requests, result, callback, progress)
14115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
14125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var self = this;
141353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        function resultCallback(receivedCookies) {
14145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (progress.isCanceled())
14155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
14165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
141753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            self.processCookies(receivedCookies, requests, result);
14185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            callback(result);
14195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
14205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        WebInspector.Cookies.getCookiesAsync(resultCallback);
14225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
14235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    mapResourceCookies: function(requestsByDomain, allCookies, callback)
14255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
14265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < allCookies.length; ++i) {
14275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (var requestDomain in requestsByDomain) {
14285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (WebInspector.Cookies.cookieDomainMatchesResourceDomain(allCookies[i].domain(), requestDomain))
14295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    this._callbackForResourceCookiePairs(requestsByDomain[requestDomain], allCookies[i], callback);
14305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
14315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
14325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
14335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _callbackForResourceCookiePairs: function(requests, cookie, callback)
14355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
14365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!requests)
14375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
14385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < requests.length; ++i) {
14395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (WebInspector.Cookies.cookieMatchesResourceURL(cookie, requests[i].url))
14405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                callback(requests[i], cookie);
14415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
14425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
14435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRule.prototype
14455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
14485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
14495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CookieRuleBase}
14505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
14515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CookieSizeRule = function(avgBytesThreshold)
14525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
145309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CookieRuleBase.call(this, "http-cookiesize", WebInspector.UIString("Minimize cookie size"));
14545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._avgBytesThreshold = avgBytesThreshold;
14555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._maxBytesThreshold = 1000;
14565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.CookieSizeRule.prototype = {
14595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _average: function(cookieArray)
14605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
14615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var total = 0;
14625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < cookieArray.length; ++i)
14635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            total += cookieArray[i].size();
14645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return cookieArray.length ? Math.round(total / cookieArray.length) : 0;
14655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
14665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _max: function(cookieArray)
14685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
14695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var result = 0;
14705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < cookieArray.length; ++i)
14715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result = Math.max(cookieArray[i].size(), result);
14725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return result;
14735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
14745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    processCookies: function(allCookies, requests, result)
14765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
14775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function maxSizeSorter(a, b)
14785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
14795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return b.maxCookieSize - a.maxCookieSize;
14805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
14815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function avgSizeSorter(a, b)
14835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
14845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return b.avgCookieSize - a.avgCookieSize;
14855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
14865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cookiesPerResourceDomain = {};
14885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        function collectorCallback(request, cookie)
14905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
14915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var cookies = cookiesPerResourceDomain[request.parsedURL.host];
14925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!cookies) {
14935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                cookies = [];
14945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                cookiesPerResourceDomain[request.parsedURL.host] = cookies;
14955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
14965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cookies.push(cookie);
14975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
14985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!allCookies.length)
15005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
15015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var sortedCookieSizes = [];
15035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests,
15055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                null,
15065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                true);
15075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var matchingResourceData = {};
150843e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles)        this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback);
15095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var requestDomain in cookiesPerResourceDomain) {
15115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var cookies = cookiesPerResourceDomain[requestDomain];
15125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            sortedCookieSizes.push({
15135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                domain: requestDomain,
15145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                avgCookieSize: this._average(cookies),
15155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                maxCookieSize: this._max(cookies)
15165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            });
15175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
15185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var avgAllCookiesSize = this._average(allCookies);
15195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var hugeCookieDomains = [];
15215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sortedCookieSizes.sort(maxSizeSorter);
15225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
15245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var maxCookieSize = sortedCookieSizes[i].maxCookieSize;
15255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (maxCookieSize > this._maxBytesThreshold)
15265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                hugeCookieDomains.push(WebInspector.AuditRuleResult.resourceDomain(sortedCookieSizes[i].domain) + ": " + Number.bytesToString(maxCookieSize));
15275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
15285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var bigAvgCookieDomains = [];
15305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sortedCookieSizes.sort(avgSizeSorter);
15315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
15325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var domain = sortedCookieSizes[i].domain;
15335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var avgCookieSize = sortedCookieSizes[i].avgCookieSize;
15345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (avgCookieSize > this._avgBytesThreshold && avgCookieSize < this._maxBytesThreshold)
15355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                bigAvgCookieDomains.push(WebInspector.AuditRuleResult.resourceDomain(domain) + ": " + Number.bytesToString(avgCookieSize));
15365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
153709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        result.addChild(WebInspector.UIString("The average cookie size for all requests on this page is %s", Number.bytesToString(avgAllCookiesSize)));
15385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var message;
15405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (hugeCookieDomains.length) {
154109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            var entry = result.addChild(WebInspector.UIString("The following domains have a cookie size in excess of 1KB. This is harmful because requests with cookies larger than 1KB typically cannot fit into a single network packet."), true);
15425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entry.addURLs(hugeCookieDomains);
15435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.violationCount += hugeCookieDomains.length;
15445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
15455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (bigAvgCookieDomains.length) {
154709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            var entry = result.addChild(WebInspector.UIString("The following domains have an average cookie size in excess of %d bytes. Reducing the size of cookies for these domains can reduce the time it takes to send requests.", this._avgBytesThreshold), true);
15485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entry.addURLs(bigAvgCookieDomains);
15495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.violationCount += bigAvgCookieDomains.length;
15505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
15515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
15525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CookieRuleBase.prototype
15545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
15575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
15585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @extends {WebInspector.AuditRules.CookieRuleBase}
15595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
15605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.StaticCookielessRule = function(minResources)
15615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
156209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    WebInspector.AuditRules.CookieRuleBase.call(this, "http-staticcookieless", WebInspector.UIString("Serve static content from a cookieless domain"));
15635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._minResources = minResources;
15645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.AuditRules.StaticCookielessRule.prototype = {
15675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    processCookies: function(allCookies, requests, result)
15685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
15695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests,
15705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                [WebInspector.resourceTypes.Stylesheet,
15715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 WebInspector.resourceTypes.Image],
15725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                true);
15735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var totalStaticResources = 0;
15745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var domain in domainToResourcesMap)
15755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            totalStaticResources += domainToResourcesMap[domain].length;
15765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (totalStaticResources < this._minResources)
15775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
15785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var matchingResourceData = {};
15795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this.mapResourceCookies(domainToResourcesMap, allCookies, this._collectorCallback.bind(this, matchingResourceData));
15805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var badUrls = [];
15825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cookieBytes = 0;
15835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var url in matchingResourceData) {
15845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            badUrls.push(url);
15855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cookieBytes += matchingResourceData[url]
15865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
15875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (badUrls.length < this._minResources)
15885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
15895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
159009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        var entry = result.addChild(WebInspector.UIString("%s of cookies were sent with the following static resources. Serve these static resources from a domain that does not set cookies:", Number.bytesToString(cookieBytes)), true);
15915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        entry.addURLs(badUrls);
15925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.violationCount = badUrls.length;
15935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
15945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _collectorCallback: function(matchingResourceData, request, cookie)
15965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
15975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        matchingResourceData[request.url] = (matchingResourceData[request.url] || 0) + cookie.size();
15985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
15995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    __proto__: WebInspector.AuditRules.CookieRuleBase.prototype
16015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1602