| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| 11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
| 12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
| 13 * distribution. | 13 * distribution. |
| 14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
| 15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
| 16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
| 17 * | 17 * |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 WebInspector.AuditRules.IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
; | 30 Audits.AuditRules.IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; |
| 31 | 31 |
| 32 WebInspector.AuditRules.CacheableResponseCodes = { | 32 Audits.AuditRules.CacheableResponseCodes = { |
| 33 200: true, | 33 200: true, |
| 34 203: true, | 34 203: true, |
| 35 206: true, | 35 206: true, |
| 36 300: true, | 36 300: true, |
| 37 301: true, | 37 301: true, |
| 38 410: true, | 38 410: true, |
| 39 | 39 |
| 40 304: true // Underlying request is cacheable | 40 304: true // Underlying request is cacheable |
| 41 }; | 41 }; |
| 42 | 42 |
| 43 /** | 43 /** |
| 44 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 44 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 45 * @param {?Array.<!WebInspector.ResourceType>} types | 45 * @param {?Array.<!Common.ResourceType>} types |
| 46 * @param {boolean} needFullResources | 46 * @param {boolean} needFullResources |
| 47 * @return {!Object.<string, !Array.<!WebInspector.NetworkRequest|string>>} | 47 * @return {!Object.<string, !Array.<!SDK.NetworkRequest|string>>} |
| 48 */ | 48 */ |
| 49 WebInspector.AuditRules.getDomainToResourcesMap = function(requests, types, need
FullResources) { | 49 Audits.AuditRules.getDomainToResourcesMap = function(requests, types, needFullRe
sources) { |
| 50 var domainToResourcesMap = {}; | 50 var domainToResourcesMap = {}; |
| 51 for (var i = 0, size = requests.length; i < size; ++i) { | 51 for (var i = 0, size = requests.length; i < size; ++i) { |
| 52 var request = requests[i]; | 52 var request = requests[i]; |
| 53 if (types && types.indexOf(request.resourceType()) === -1) | 53 if (types && types.indexOf(request.resourceType()) === -1) |
| 54 continue; | 54 continue; |
| 55 var parsedURL = request.url.asParsedURL(); | 55 var parsedURL = request.url.asParsedURL(); |
| 56 if (!parsedURL) | 56 if (!parsedURL) |
| 57 continue; | 57 continue; |
| 58 var domain = parsedURL.host; | 58 var domain = parsedURL.host; |
| 59 var domainResources = domainToResourcesMap[domain]; | 59 var domainResources = domainToResourcesMap[domain]; |
| 60 if (domainResources === undefined) { | 60 if (domainResources === undefined) { |
| 61 domainResources = []; | 61 domainResources = []; |
| 62 domainToResourcesMap[domain] = domainResources; | 62 domainToResourcesMap[domain] = domainResources; |
| 63 } | 63 } |
| 64 domainResources.push(needFullResources ? request : request.url); | 64 domainResources.push(needFullResources ? request : request.url); |
| 65 } | 65 } |
| 66 return domainToResourcesMap; | 66 return domainToResourcesMap; |
| 67 }; | 67 }; |
| 68 | 68 |
| 69 /** | 69 /** |
| 70 * @unrestricted | 70 * @unrestricted |
| 71 */ | 71 */ |
| 72 WebInspector.AuditRules.GzipRule = class extends WebInspector.AuditRule { | 72 Audits.AuditRules.GzipRule = class extends Audits.AuditRule { |
| 73 constructor() { | 73 constructor() { |
| 74 super('network-gzip', WebInspector.UIString('Enable gzip compression')); | 74 super('network-gzip', Common.UIString('Enable gzip compression')); |
| 75 } | 75 } |
| 76 | 76 |
| 77 /** | 77 /** |
| 78 * @override | 78 * @override |
| 79 * @param {!WebInspector.Target} target | 79 * @param {!SDK.Target} target |
| 80 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 80 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 81 * @param {!WebInspector.AuditRuleResult} result | 81 * @param {!Audits.AuditRuleResult} result |
| 82 * @param {function(?WebInspector.AuditRuleResult)} callback | 82 * @param {function(?Audits.AuditRuleResult)} callback |
| 83 * @param {!WebInspector.Progress} progress | 83 * @param {!Common.Progress} progress |
| 84 */ | 84 */ |
| 85 doRun(target, requests, result, callback, progress) { | 85 doRun(target, requests, result, callback, progress) { |
| 86 var totalSavings = 0; | 86 var totalSavings = 0; |
| 87 var compressedSize = 0; | 87 var compressedSize = 0; |
| 88 var candidateSize = 0; | 88 var candidateSize = 0; |
| 89 var summary = result.addChild('', true); | 89 var summary = result.addChild('', true); |
| 90 for (var i = 0, length = requests.length; i < length; ++i) { | 90 for (var i = 0, length = requests.length; i < length; ++i) { |
| 91 var request = requests[i]; | 91 var request = requests[i]; |
| 92 if (request.cached() || request.statusCode === 304) | 92 if (request.cached() || request.statusCode === 304) |
| 93 continue; // Do not test cached resources. | 93 continue; // Do not test cached resources. |
| 94 if (this._shouldCompress(request)) { | 94 if (this._shouldCompress(request)) { |
| 95 var size = request.resourceSize; | 95 var size = request.resourceSize; |
| 96 candidateSize += size; | 96 candidateSize += size; |
| 97 if (this._isCompressed(request)) { | 97 if (this._isCompressed(request)) { |
| 98 compressedSize += size; | 98 compressedSize += size; |
| 99 continue; | 99 continue; |
| 100 } | 100 } |
| 101 var savings = 2 * size / 3; | 101 var savings = 2 * size / 3; |
| 102 totalSavings += savings; | 102 totalSavings += savings; |
| 103 summary.addFormatted('%r could save ~%s', request.url, Number.bytesToStr
ing(savings)); | 103 summary.addFormatted('%r could save ~%s', request.url, Number.bytesToStr
ing(savings)); |
| 104 result.violationCount++; | 104 result.violationCount++; |
| 105 } | 105 } |
| 106 } | 106 } |
| 107 if (!totalSavings) { | 107 if (!totalSavings) { |
| 108 callback(null); | 108 callback(null); |
| 109 return; | 109 return; |
| 110 } | 110 } |
| 111 summary.value = WebInspector.UIString( | 111 summary.value = Common.UIString( |
| 112 'Compressing the following resources with gzip could reduce their transf
er size by about two thirds (~%s):', | 112 'Compressing the following resources with gzip could reduce their transf
er size by about two thirds (~%s):', |
| 113 Number.bytesToString(totalSavings)); | 113 Number.bytesToString(totalSavings)); |
| 114 callback(result); | 114 callback(result); |
| 115 } | 115 } |
| 116 | 116 |
| 117 /** | 117 /** |
| 118 * @param {!WebInspector.NetworkRequest} request | 118 * @param {!SDK.NetworkRequest} request |
| 119 */ | 119 */ |
| 120 _isCompressed(request) { | 120 _isCompressed(request) { |
| 121 var encodingHeader = request.responseHeaderValue('Content-Encoding'); | 121 var encodingHeader = request.responseHeaderValue('Content-Encoding'); |
| 122 if (!encodingHeader) | 122 if (!encodingHeader) |
| 123 return false; | 123 return false; |
| 124 | 124 |
| 125 return /\b(?:gzip|deflate)\b/.test(encodingHeader); | 125 return /\b(?:gzip|deflate)\b/.test(encodingHeader); |
| 126 } | 126 } |
| 127 | 127 |
| 128 /** | 128 /** |
| 129 * @param {!WebInspector.NetworkRequest} request | 129 * @param {!SDK.NetworkRequest} request |
| 130 */ | 130 */ |
| 131 _shouldCompress(request) { | 131 _shouldCompress(request) { |
| 132 return request.resourceType().isTextType() && request.parsedURL.host && requ
est.resourceSize !== undefined && | 132 return request.resourceType().isTextType() && request.parsedURL.host && requ
est.resourceSize !== undefined && |
| 133 request.resourceSize > 150; | 133 request.resourceSize > 150; |
| 134 } | 134 } |
| 135 }; | 135 }; |
| 136 | 136 |
| 137 /** | 137 /** |
| 138 * @unrestricted | 138 * @unrestricted |
| 139 */ | 139 */ |
| 140 WebInspector.AuditRules.CombineExternalResourcesRule = class extends WebInspecto
r.AuditRule { | 140 Audits.AuditRules.CombineExternalResourcesRule = class extends Audits.AuditRule
{ |
| 141 /** | 141 /** |
| 142 * @param {string} id | 142 * @param {string} id |
| 143 * @param {string} name | 143 * @param {string} name |
| 144 * @param {!WebInspector.ResourceType} type | 144 * @param {!Common.ResourceType} type |
| 145 * @param {string} resourceTypeName | 145 * @param {string} resourceTypeName |
| 146 * @param {boolean} allowedPerDomain | 146 * @param {boolean} allowedPerDomain |
| 147 */ | 147 */ |
| 148 constructor(id, name, type, resourceTypeName, allowedPerDomain) { | 148 constructor(id, name, type, resourceTypeName, allowedPerDomain) { |
| 149 super(id, name); | 149 super(id, name); |
| 150 this._type = type; | 150 this._type = type; |
| 151 this._resourceTypeName = resourceTypeName; | 151 this._resourceTypeName = resourceTypeName; |
| 152 this._allowedPerDomain = allowedPerDomain; | 152 this._allowedPerDomain = allowedPerDomain; |
| 153 } | 153 } |
| 154 | 154 |
| 155 /** | 155 /** |
| 156 * @override | 156 * @override |
| 157 * @param {!WebInspector.Target} target | 157 * @param {!SDK.Target} target |
| 158 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 158 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 159 * @param {!WebInspector.AuditRuleResult} result | 159 * @param {!Audits.AuditRuleResult} result |
| 160 * @param {function(?WebInspector.AuditRuleResult)} callback | 160 * @param {function(?Audits.AuditRuleResult)} callback |
| 161 * @param {!WebInspector.Progress} progress | 161 * @param {!Common.Progress} progress |
| 162 */ | 162 */ |
| 163 doRun(target, requests, result, callback, progress) { | 163 doRun(target, requests, result, callback, progress) { |
| 164 var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(r
equests, [this._type], false); | 164 var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(request
s, [this._type], false); |
| 165 var penalizedResourceCount = 0; | 165 var penalizedResourceCount = 0; |
| 166 // TODO: refactor according to the chosen i18n approach | 166 // TODO: refactor according to the chosen i18n approach |
| 167 var summary = result.addChild('', true); | 167 var summary = result.addChild('', true); |
| 168 for (var domain in domainToResourcesMap) { | 168 for (var domain in domainToResourcesMap) { |
| 169 var domainResources = domainToResourcesMap[domain]; | 169 var domainResources = domainToResourcesMap[domain]; |
| 170 var extraResourceCount = domainResources.length - this._allowedPerDomain; | 170 var extraResourceCount = domainResources.length - this._allowedPerDomain; |
| 171 if (extraResourceCount <= 0) | 171 if (extraResourceCount <= 0) |
| 172 continue; | 172 continue; |
| 173 penalizedResourceCount += extraResourceCount - 1; | 173 penalizedResourceCount += extraResourceCount - 1; |
| 174 summary.addChild(WebInspector.UIString( | 174 summary.addChild(Common.UIString( |
| 175 '%d %s resources served from %s.', domainResources.length, this._resou
rceTypeName, | 175 '%d %s resources served from %s.', domainResources.length, this._resou
rceTypeName, |
| 176 WebInspector.AuditRuleResult.resourceDomain(domain))); | 176 Audits.AuditRuleResult.resourceDomain(domain))); |
| 177 result.violationCount += domainResources.length; | 177 result.violationCount += domainResources.length; |
| 178 } | 178 } |
| 179 if (!penalizedResourceCount) { | 179 if (!penalizedResourceCount) { |
| 180 callback(null); | 180 callback(null); |
| 181 return; | 181 return; |
| 182 } | 182 } |
| 183 | 183 |
| 184 summary.value = WebInspector.UIString( | 184 summary.value = Common.UIString( |
| 185 'There are multiple resources served from same domain. Consider combinin
g them into as few files as possible.'); | 185 'There are multiple resources served from same domain. Consider combinin
g them into as few files as possible.'); |
| 186 callback(result); | 186 callback(result); |
| 187 } | 187 } |
| 188 }; | 188 }; |
| 189 | 189 |
| 190 /** | 190 /** |
| 191 * @unrestricted | 191 * @unrestricted |
| 192 */ | 192 */ |
| 193 WebInspector.AuditRules.CombineJsResourcesRule = class extends WebInspector.Audi
tRules.CombineExternalResourcesRule { | 193 Audits.AuditRules.CombineJsResourcesRule = class extends Audits.AuditRules.Combi
neExternalResourcesRule { |
| 194 constructor(allowedPerDomain) { | 194 constructor(allowedPerDomain) { |
| 195 super( | 195 super( |
| 196 'page-externaljs', WebInspector.UIString('Combine external JavaScript'),
WebInspector.resourceTypes.Script, | 196 'page-externaljs', Common.UIString('Combine external JavaScript'), Commo
n.resourceTypes.Script, |
| 197 'JavaScript', allowedPerDomain); | 197 'JavaScript', allowedPerDomain); |
| 198 } | 198 } |
| 199 }; | 199 }; |
| 200 | 200 |
| 201 /** | 201 /** |
| 202 * @unrestricted | 202 * @unrestricted |
| 203 */ | 203 */ |
| 204 WebInspector.AuditRules.CombineCssResourcesRule = class extends WebInspector.Aud
itRules.CombineExternalResourcesRule { | 204 Audits.AuditRules.CombineCssResourcesRule = class extends Audits.AuditRules.Comb
ineExternalResourcesRule { |
| 205 constructor(allowedPerDomain) { | 205 constructor(allowedPerDomain) { |
| 206 super( | 206 super( |
| 207 'page-externalcss', WebInspector.UIString('Combine external CSS'), WebIn
spector.resourceTypes.Stylesheet, 'CSS', | 207 'page-externalcss', Common.UIString('Combine external CSS'), Common.reso
urceTypes.Stylesheet, 'CSS', |
| 208 allowedPerDomain); | 208 allowedPerDomain); |
| 209 } | 209 } |
| 210 }; | 210 }; |
| 211 | 211 |
| 212 /** | 212 /** |
| 213 * @unrestricted | 213 * @unrestricted |
| 214 */ | 214 */ |
| 215 WebInspector.AuditRules.MinimizeDnsLookupsRule = class extends WebInspector.Audi
tRule { | 215 Audits.AuditRules.MinimizeDnsLookupsRule = class extends Audits.AuditRule { |
| 216 constructor(hostCountThreshold) { | 216 constructor(hostCountThreshold) { |
| 217 super('network-minimizelookups', WebInspector.UIString('Minimize DNS lookups
')); | 217 super('network-minimizelookups', Common.UIString('Minimize DNS lookups')); |
| 218 this._hostCountThreshold = hostCountThreshold; | 218 this._hostCountThreshold = hostCountThreshold; |
| 219 } | 219 } |
| 220 | 220 |
| 221 /** | 221 /** |
| 222 * @override | 222 * @override |
| 223 * @param {!WebInspector.Target} target | 223 * @param {!SDK.Target} target |
| 224 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 224 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 225 * @param {!WebInspector.AuditRuleResult} result | 225 * @param {!Audits.AuditRuleResult} result |
| 226 * @param {function(?WebInspector.AuditRuleResult)} callback | 226 * @param {function(?Audits.AuditRuleResult)} callback |
| 227 * @param {!WebInspector.Progress} progress | 227 * @param {!Common.Progress} progress |
| 228 */ | 228 */ |
| 229 doRun(target, requests, result, callback, progress) { | 229 doRun(target, requests, result, callback, progress) { |
| 230 var summary = result.addChild(''); | 230 var summary = result.addChild(''); |
| 231 var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(r
equests, null, false); | 231 var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(request
s, null, false); |
| 232 for (var domain in domainToResourcesMap) { | 232 for (var domain in domainToResourcesMap) { |
| 233 if (domainToResourcesMap[domain].length > 1) | 233 if (domainToResourcesMap[domain].length > 1) |
| 234 continue; | 234 continue; |
| 235 var parsedURL = domain.asParsedURL(); | 235 var parsedURL = domain.asParsedURL(); |
| 236 if (!parsedURL) | 236 if (!parsedURL) |
| 237 continue; | 237 continue; |
| 238 if (!parsedURL.host.search(WebInspector.AuditRules.IPAddressRegexp)) | 238 if (!parsedURL.host.search(Audits.AuditRules.IPAddressRegexp)) |
| 239 continue; // an IP address | 239 continue; // an IP address |
| 240 summary.addSnippet(domain); | 240 summary.addSnippet(domain); |
| 241 result.violationCount++; | 241 result.violationCount++; |
| 242 } | 242 } |
| 243 if (!summary.children || summary.children.length <= this._hostCountThreshold
) { | 243 if (!summary.children || summary.children.length <= this._hostCountThreshold
) { |
| 244 callback(null); | 244 callback(null); |
| 245 return; | 245 return; |
| 246 } | 246 } |
| 247 | 247 |
| 248 summary.value = WebInspector.UIString( | 248 summary.value = Common.UIString( |
| 249 'The following domains only serve one resource each. If possible, avoid
the extra DNS lookups by serving these resources from existing domains.'); | 249 'The following domains only serve one resource each. If possible, avoid
the extra DNS lookups by serving these resources from existing domains.'); |
| 250 callback(result); | 250 callback(result); |
| 251 } | 251 } |
| 252 }; | 252 }; |
| 253 | 253 |
| 254 /** | 254 /** |
| 255 * @unrestricted | 255 * @unrestricted |
| 256 */ | 256 */ |
| 257 WebInspector.AuditRules.ParallelizeDownloadRule = class extends WebInspector.Aud
itRule { | 257 Audits.AuditRules.ParallelizeDownloadRule = class extends Audits.AuditRule { |
| 258 constructor(optimalHostnameCount, minRequestThreshold, minBalanceThreshold) { | 258 constructor(optimalHostnameCount, minRequestThreshold, minBalanceThreshold) { |
| 259 super('network-parallelizehosts', WebInspector.UIString('Parallelize downloa
ds across hostnames')); | 259 super('network-parallelizehosts', Common.UIString('Parallelize downloads acr
oss hostnames')); |
| 260 this._optimalHostnameCount = optimalHostnameCount; | 260 this._optimalHostnameCount = optimalHostnameCount; |
| 261 this._minRequestThreshold = minRequestThreshold; | 261 this._minRequestThreshold = minRequestThreshold; |
| 262 this._minBalanceThreshold = minBalanceThreshold; | 262 this._minBalanceThreshold = minBalanceThreshold; |
| 263 } | 263 } |
| 264 | 264 |
| 265 /** | 265 /** |
| 266 * @override | 266 * @override |
| 267 * @param {!WebInspector.Target} target | 267 * @param {!SDK.Target} target |
| 268 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 268 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 269 * @param {!WebInspector.AuditRuleResult} result | 269 * @param {!Audits.AuditRuleResult} result |
| 270 * @param {function(?WebInspector.AuditRuleResult)} callback | 270 * @param {function(?Audits.AuditRuleResult)} callback |
| 271 * @param {!WebInspector.Progress} progress | 271 * @param {!Common.Progress} progress |
| 272 */ | 272 */ |
| 273 doRun(target, requests, result, callback, progress) { | 273 doRun(target, requests, result, callback, progress) { |
| 274 /** | 274 /** |
| 275 * @param {string} a | 275 * @param {string} a |
| 276 * @param {string} b | 276 * @param {string} b |
| 277 */ | 277 */ |
| 278 function hostSorter(a, b) { | 278 function hostSorter(a, b) { |
| 279 var aCount = domainToResourcesMap[a].length; | 279 var aCount = domainToResourcesMap[a].length; |
| 280 var bCount = domainToResourcesMap[b].length; | 280 var bCount = domainToResourcesMap[b].length; |
| 281 return (aCount < bCount) ? 1 : (aCount === bCount) ? 0 : -1; | 281 return (aCount < bCount) ? 1 : (aCount === bCount) ? 0 : -1; |
| 282 } | 282 } |
| 283 | 283 |
| 284 var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap( | 284 var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap( |
| 285 requests, [WebInspector.resourceTypes.Stylesheet, WebInspector.resourceT
ypes.Image], true); | 285 requests, [Common.resourceTypes.Stylesheet, Common.resourceTypes.Image],
true); |
| 286 | 286 |
| 287 var hosts = []; | 287 var hosts = []; |
| 288 for (var url in domainToResourcesMap) | 288 for (var url in domainToResourcesMap) |
| 289 hosts.push(url); | 289 hosts.push(url); |
| 290 | 290 |
| 291 if (!hosts.length) { | 291 if (!hosts.length) { |
| 292 callback(null); // no hosts (local file or something) | 292 callback(null); // no hosts (local file or something) |
| 293 return; | 293 return; |
| 294 } | 294 } |
| 295 | 295 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 316 | 316 |
| 317 var pctAboveAvg = (requestCountAboveThreshold / avgResourcesPerHost) - 1.0; | 317 var pctAboveAvg = (requestCountAboveThreshold / avgResourcesPerHost) - 1.0; |
| 318 var minBalanceThreshold = this._minBalanceThreshold; | 318 var minBalanceThreshold = this._minBalanceThreshold; |
| 319 if (pctAboveAvg < minBalanceThreshold) { | 319 if (pctAboveAvg < minBalanceThreshold) { |
| 320 callback(null); | 320 callback(null); |
| 321 return; | 321 return; |
| 322 } | 322 } |
| 323 | 323 |
| 324 var requestsOnBusiestHost = domainToResourcesMap[hosts[0]]; | 324 var requestsOnBusiestHost = domainToResourcesMap[hosts[0]]; |
| 325 var entry = result.addChild( | 325 var entry = result.addChild( |
| 326 WebInspector.UIString( | 326 Common.UIString( |
| 327 'This page makes %d parallelizable requests to %s. Increase download
parallelization by distributing the following requests across multiple hostname
s.', | 327 'This page makes %d parallelizable requests to %s. Increase download
parallelization by distributing the following requests across multiple hostname
s.', |
| 328 busiestHostResourceCount, hosts[0]), | 328 busiestHostResourceCount, hosts[0]), |
| 329 true); | 329 true); |
| 330 for (var i = 0; i < requestsOnBusiestHost.length; ++i) | 330 for (var i = 0; i < requestsOnBusiestHost.length; ++i) |
| 331 entry.addURL(requestsOnBusiestHost[i].url); | 331 entry.addURL(requestsOnBusiestHost[i].url); |
| 332 | 332 |
| 333 result.violationCount = requestsOnBusiestHost.length; | 333 result.violationCount = requestsOnBusiestHost.length; |
| 334 callback(result); | 334 callback(result); |
| 335 } | 335 } |
| 336 }; | 336 }; |
| 337 | 337 |
| 338 /** | 338 /** |
| 339 * @unrestricted | 339 * @unrestricted |
| 340 */ | 340 */ |
| 341 WebInspector.AuditRules.UnusedCssRule = class extends WebInspector.AuditRule { | 341 Audits.AuditRules.UnusedCssRule = class extends Audits.AuditRule { |
| 342 /** | 342 /** |
| 343 * The reported CSS rule size is incorrect (parsed != original in WebKit), | 343 * The reported CSS rule size is incorrect (parsed != original in WebKit), |
| 344 * so use percentages instead, which gives a better approximation. | 344 * so use percentages instead, which gives a better approximation. |
| 345 */ | 345 */ |
| 346 constructor() { | 346 constructor() { |
| 347 super('page-unusedcss', WebInspector.UIString('Remove unused CSS rules')); | 347 super('page-unusedcss', Common.UIString('Remove unused CSS rules')); |
| 348 } | 348 } |
| 349 | 349 |
| 350 /** | 350 /** |
| 351 * @override | 351 * @override |
| 352 * @param {!WebInspector.Target} target | 352 * @param {!SDK.Target} target |
| 353 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 353 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 354 * @param {!WebInspector.AuditRuleResult} result | 354 * @param {!Audits.AuditRuleResult} result |
| 355 * @param {function(?WebInspector.AuditRuleResult)} callback | 355 * @param {function(?Audits.AuditRuleResult)} callback |
| 356 * @param {!WebInspector.Progress} progress | 356 * @param {!Common.Progress} progress |
| 357 */ | 357 */ |
| 358 doRun(target, requests, result, callback, progress) { | 358 doRun(target, requests, result, callback, progress) { |
| 359 var domModel = WebInspector.DOMModel.fromTarget(target); | 359 var domModel = SDK.DOMModel.fromTarget(target); |
| 360 var cssModel = WebInspector.CSSModel.fromTarget(target); | 360 var cssModel = SDK.CSSModel.fromTarget(target); |
| 361 if (!domModel || !cssModel) { | 361 if (!domModel || !cssModel) { |
| 362 callback(null); | 362 callback(null); |
| 363 return; | 363 return; |
| 364 } | 364 } |
| 365 | 365 |
| 366 /** | 366 /** |
| 367 * @param {!Array.<!WebInspector.AuditRules.ParsedStyleSheet>} styleSheets | 367 * @param {!Array.<!Audits.AuditRules.ParsedStyleSheet>} styleSheets |
| 368 */ | 368 */ |
| 369 function evalCallback(styleSheets) { | 369 function evalCallback(styleSheets) { |
| 370 if (!styleSheets.length) | 370 if (!styleSheets.length) |
| 371 return callback(null); | 371 return callback(null); |
| 372 | 372 |
| 373 var selectors = []; | 373 var selectors = []; |
| 374 var testedSelectors = {}; | 374 var testedSelectors = {}; |
| 375 for (var i = 0; i < styleSheets.length; ++i) { | 375 for (var i = 0; i < styleSheets.length; ++i) { |
| 376 var styleSheet = styleSheets[i]; | 376 var styleSheet = styleSheets[i]; |
| 377 for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) { | 377 for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) { |
| 378 var selectorText = styleSheet.rules[curRule].selectorText; | 378 var selectorText = styleSheet.rules[curRule].selectorText; |
| 379 if (testedSelectors[selectorText]) | 379 if (testedSelectors[selectorText]) |
| 380 continue; | 380 continue; |
| 381 selectors.push(selectorText); | 381 selectors.push(selectorText); |
| 382 testedSelectors[selectorText] = 1; | 382 testedSelectors[selectorText] = 1; |
| 383 } | 383 } |
| 384 } | 384 } |
| 385 | 385 |
| 386 var foundSelectors = {}; | 386 var foundSelectors = {}; |
| 387 | 387 |
| 388 /** | 388 /** |
| 389 * @param {!Array.<!WebInspector.AuditRules.ParsedStyleSheet>} styleSheets | 389 * @param {!Array.<!Audits.AuditRules.ParsedStyleSheet>} styleSheets |
| 390 */ | 390 */ |
| 391 function selectorsCallback(styleSheets) { | 391 function selectorsCallback(styleSheets) { |
| 392 if (progress.isCanceled()) { | 392 if (progress.isCanceled()) { |
| 393 callback(null); | 393 callback(null); |
| 394 return; | 394 return; |
| 395 } | 395 } |
| 396 | 396 |
| 397 var inlineBlockOrdinal = 0; | 397 var inlineBlockOrdinal = 0; |
| 398 var totalStylesheetSize = 0; | 398 var totalStylesheetSize = 0; |
| 399 var totalUnusedStylesheetSize = 0; | 399 var totalUnusedStylesheetSize = 0; |
| 400 var summary; | 400 var summary; |
| 401 | 401 |
| 402 for (var i = 0; i < styleSheets.length; ++i) { | 402 for (var i = 0; i < styleSheets.length; ++i) { |
| 403 var styleSheet = styleSheets[i]; | 403 var styleSheet = styleSheets[i]; |
| 404 var unusedRules = []; | 404 var unusedRules = []; |
| 405 for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) { | 405 for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) { |
| 406 var rule = styleSheet.rules[curRule]; | 406 var rule = styleSheet.rules[curRule]; |
| 407 if (!testedSelectors[rule.selectorText] || foundSelectors[rule.selec
torText]) | 407 if (!testedSelectors[rule.selectorText] || foundSelectors[rule.selec
torText]) |
| 408 continue; | 408 continue; |
| 409 unusedRules.push(rule.selectorText); | 409 unusedRules.push(rule.selectorText); |
| 410 } | 410 } |
| 411 totalStylesheetSize += styleSheet.rules.length; | 411 totalStylesheetSize += styleSheet.rules.length; |
| 412 totalUnusedStylesheetSize += unusedRules.length; | 412 totalUnusedStylesheetSize += unusedRules.length; |
| 413 | 413 |
| 414 if (!unusedRules.length) | 414 if (!unusedRules.length) |
| 415 continue; | 415 continue; |
| 416 | 416 |
| 417 var resource = WebInspector.resourceForURL(styleSheet.sourceURL); | 417 var resource = Bindings.resourceForURL(styleSheet.sourceURL); |
| 418 var isInlineBlock = | 418 var isInlineBlock = |
| 419 resource && resource.request && resource.request.resourceType() ==
= WebInspector.resourceTypes.Document; | 419 resource && resource.request && resource.request.resourceType() ==
= Common.resourceTypes.Document; |
| 420 var url = !isInlineBlock ? WebInspector.AuditRuleResult.linkifyDisplay
Name(styleSheet.sourceURL) : | 420 var url = !isInlineBlock ? Audits.AuditRuleResult.linkifyDisplayName(s
tyleSheet.sourceURL) : |
| 421 WebInspector.UIString('Inline block #%d', +
+inlineBlockOrdinal); | 421 Common.UIString('Inline block #%d', ++inlin
eBlockOrdinal); |
| 422 var pctUnused = Math.round(100 * unusedRules.length / styleSheet.rules
.length); | 422 var pctUnused = Math.round(100 * unusedRules.length / styleSheet.rules
.length); |
| 423 if (!summary) | 423 if (!summary) |
| 424 summary = result.addChild('', true); | 424 summary = result.addChild('', true); |
| 425 var entry = summary.addFormatted('%s: %d% is not used by the current p
age.', url, pctUnused); | 425 var entry = summary.addFormatted('%s: %d% is not used by the current p
age.', url, pctUnused); |
| 426 | 426 |
| 427 for (var j = 0; j < unusedRules.length; ++j) | 427 for (var j = 0; j < unusedRules.length; ++j) |
| 428 entry.addSnippet(unusedRules[j]); | 428 entry.addSnippet(unusedRules[j]); |
| 429 | 429 |
| 430 result.violationCount += unusedRules.length; | 430 result.violationCount += unusedRules.length; |
| 431 } | 431 } |
| 432 | 432 |
| 433 if (!totalUnusedStylesheetSize) | 433 if (!totalUnusedStylesheetSize) |
| 434 return callback(null); | 434 return callback(null); |
| 435 | 435 |
| 436 var totalUnusedPercent = Math.round(100 * totalUnusedStylesheetSize / to
talStylesheetSize); | 436 var totalUnusedPercent = Math.round(100 * totalUnusedStylesheetSize / to
talStylesheetSize); |
| 437 summary.value = WebInspector.UIString( | 437 summary.value = Common.UIString( |
| 438 '%s rules (%d%) of CSS not used by the current page.', totalUnusedSt
ylesheetSize, totalUnusedPercent); | 438 '%s rules (%d%) of CSS not used by the current page.', totalUnusedSt
ylesheetSize, totalUnusedPercent); |
| 439 | 439 |
| 440 callback(result); | 440 callback(result); |
| 441 } | 441 } |
| 442 | 442 |
| 443 /** | 443 /** |
| 444 * @param {?function()} boundSelectorsCallback | 444 * @param {?function()} boundSelectorsCallback |
| 445 * @param {string} selector | 445 * @param {string} selector |
| 446 * @param {?Protocol.DOM.NodeId} nodeId | 446 * @param {?Protocol.DOM.NodeId} nodeId |
| 447 */ | 447 */ |
| 448 function queryCallback(boundSelectorsCallback, selector, nodeId) { | 448 function queryCallback(boundSelectorsCallback, selector, nodeId) { |
| 449 if (nodeId) | 449 if (nodeId) |
| 450 foundSelectors[selector] = true; | 450 foundSelectors[selector] = true; |
| 451 if (boundSelectorsCallback) | 451 if (boundSelectorsCallback) |
| 452 boundSelectorsCallback(); | 452 boundSelectorsCallback(); |
| 453 } | 453 } |
| 454 | 454 |
| 455 /** | 455 /** |
| 456 * @param {!Array.<string>} selectors | 456 * @param {!Array.<string>} selectors |
| 457 * @param {!WebInspector.DOMDocument} document | 457 * @param {!SDK.DOMDocument} document |
| 458 */ | 458 */ |
| 459 function documentLoaded(selectors, document) { | 459 function documentLoaded(selectors, document) { |
| 460 var pseudoSelectorRegexp = /::?(?:[\w-]+)(?:\(.*?\))?/g; | 460 var pseudoSelectorRegexp = /::?(?:[\w-]+)(?:\(.*?\))?/g; |
| 461 if (!selectors.length) { | 461 if (!selectors.length) { |
| 462 selectorsCallback([]); | 462 selectorsCallback([]); |
| 463 return; | 463 return; |
| 464 } | 464 } |
| 465 for (var i = 0; i < selectors.length; ++i) { | 465 for (var i = 0; i < selectors.length; ++i) { |
| 466 if (progress.isCanceled()) { | 466 if (progress.isCanceled()) { |
| 467 callback(null); | 467 callback(null); |
| 468 return; | 468 return; |
| 469 } | 469 } |
| 470 var effectiveSelector = selectors[i].replace(pseudoSelectorRegexp, '')
; | 470 var effectiveSelector = selectors[i].replace(pseudoSelectorRegexp, '')
; |
| 471 domModel.querySelector( | 471 domModel.querySelector( |
| 472 document.id, effectiveSelector, | 472 document.id, effectiveSelector, |
| 473 queryCallback.bind( | 473 queryCallback.bind( |
| 474 null, i === selectors.length - 1 ? selectorsCallback.bind(null
, styleSheets) : null, selectors[i])); | 474 null, i === selectors.length - 1 ? selectorsCallback.bind(null
, styleSheets) : null, selectors[i])); |
| 475 } | 475 } |
| 476 } | 476 } |
| 477 | 477 |
| 478 domModel.requestDocument(documentLoaded.bind(null, selectors)); | 478 domModel.requestDocument(documentLoaded.bind(null, selectors)); |
| 479 } | 479 } |
| 480 | 480 |
| 481 var styleSheetInfos = cssModel.allStyleSheets(); | 481 var styleSheetInfos = cssModel.allStyleSheets(); |
| 482 if (!styleSheetInfos || !styleSheetInfos.length) { | 482 if (!styleSheetInfos || !styleSheetInfos.length) { |
| 483 evalCallback([]); | 483 evalCallback([]); |
| 484 return; | 484 return; |
| 485 } | 485 } |
| 486 var styleSheetProcessor = new WebInspector.AuditRules.StyleSheetProcessor(st
yleSheetInfos, progress, evalCallback); | 486 var styleSheetProcessor = new Audits.AuditRules.StyleSheetProcessor(styleShe
etInfos, progress, evalCallback); |
| 487 styleSheetProcessor.run(); | 487 styleSheetProcessor.run(); |
| 488 } | 488 } |
| 489 }; | 489 }; |
| 490 | 490 |
| 491 /** | 491 /** |
| 492 * @typedef {!{sourceURL: string, rules: !Array.<!WebInspector.CSSParser.StyleRu
le>}} | 492 * @typedef {!{sourceURL: string, rules: !Array.<!SDK.CSSParser.StyleRule>}} |
| 493 */ | 493 */ |
| 494 WebInspector.AuditRules.ParsedStyleSheet; | 494 Audits.AuditRules.ParsedStyleSheet; |
| 495 | 495 |
| 496 /** | 496 /** |
| 497 * @unrestricted | 497 * @unrestricted |
| 498 */ | 498 */ |
| 499 WebInspector.AuditRules.StyleSheetProcessor = class { | 499 Audits.AuditRules.StyleSheetProcessor = class { |
| 500 /** | 500 /** |
| 501 * @param {!Array.<!WebInspector.CSSStyleSheetHeader>} styleSheetHeaders | 501 * @param {!Array.<!SDK.CSSStyleSheetHeader>} styleSheetHeaders |
| 502 * @param {!WebInspector.Progress} progress | 502 * @param {!Common.Progress} progress |
| 503 * @param {function(!Array.<!WebInspector.AuditRules.ParsedStyleSheet>)} style
SheetsParsedCallback | 503 * @param {function(!Array.<!Audits.AuditRules.ParsedStyleSheet>)} styleSheets
ParsedCallback |
| 504 */ | 504 */ |
| 505 constructor(styleSheetHeaders, progress, styleSheetsParsedCallback) { | 505 constructor(styleSheetHeaders, progress, styleSheetsParsedCallback) { |
| 506 this._styleSheetHeaders = styleSheetHeaders; | 506 this._styleSheetHeaders = styleSheetHeaders; |
| 507 this._progress = progress; | 507 this._progress = progress; |
| 508 this._styleSheets = []; | 508 this._styleSheets = []; |
| 509 this._styleSheetsParsedCallback = styleSheetsParsedCallback; | 509 this._styleSheetsParsedCallback = styleSheetsParsedCallback; |
| 510 } | 510 } |
| 511 | 511 |
| 512 run() { | 512 run() { |
| 513 this._parser = new WebInspector.CSSParser(); | 513 this._parser = new SDK.CSSParser(); |
| 514 this._processNextStyleSheet(); | 514 this._processNextStyleSheet(); |
| 515 } | 515 } |
| 516 | 516 |
| 517 _terminateWorker() { | 517 _terminateWorker() { |
| 518 if (this._parser) { | 518 if (this._parser) { |
| 519 this._parser.dispose(); | 519 this._parser.dispose(); |
| 520 delete this._parser; | 520 delete this._parser; |
| 521 } | 521 } |
| 522 } | 522 } |
| 523 | 523 |
| 524 _finish() { | 524 _finish() { |
| 525 this._terminateWorker(); | 525 this._terminateWorker(); |
| 526 this._styleSheetsParsedCallback(this._styleSheets); | 526 this._styleSheetsParsedCallback(this._styleSheets); |
| 527 } | 527 } |
| 528 | 528 |
| 529 _processNextStyleSheet() { | 529 _processNextStyleSheet() { |
| 530 if (!this._styleSheetHeaders.length) { | 530 if (!this._styleSheetHeaders.length) { |
| 531 this._finish(); | 531 this._finish(); |
| 532 return; | 532 return; |
| 533 } | 533 } |
| 534 this._currentStyleSheetHeader = this._styleSheetHeaders.shift(); | 534 this._currentStyleSheetHeader = this._styleSheetHeaders.shift(); |
| 535 this._parser.fetchAndParse(this._currentStyleSheetHeader, this._onStyleSheet
Parsed.bind(this)); | 535 this._parser.fetchAndParse(this._currentStyleSheetHeader, this._onStyleSheet
Parsed.bind(this)); |
| 536 } | 536 } |
| 537 | 537 |
| 538 /** | 538 /** |
| 539 * @param {!Array.<!WebInspector.CSSParser.Rule>} rules | 539 * @param {!Array.<!SDK.CSSParser.Rule>} rules |
| 540 */ | 540 */ |
| 541 _onStyleSheetParsed(rules) { | 541 _onStyleSheetParsed(rules) { |
| 542 if (this._progress.isCanceled()) { | 542 if (this._progress.isCanceled()) { |
| 543 this._finish(); | 543 this._finish(); |
| 544 return; | 544 return; |
| 545 } | 545 } |
| 546 | 546 |
| 547 var styleRules = []; | 547 var styleRules = []; |
| 548 for (var i = 0; i < rules.length; ++i) { | 548 for (var i = 0; i < rules.length; ++i) { |
| 549 var rule = rules[i]; | 549 var rule = rules[i]; |
| 550 if (rule.selectorText) | 550 if (rule.selectorText) |
| 551 styleRules.push(rule); | 551 styleRules.push(rule); |
| 552 } | 552 } |
| 553 this._styleSheets.push({sourceURL: this._currentStyleSheetHeader.sourceURL,
rules: styleRules}); | 553 this._styleSheets.push({sourceURL: this._currentStyleSheetHeader.sourceURL,
rules: styleRules}); |
| 554 this._processNextStyleSheet(); | 554 this._processNextStyleSheet(); |
| 555 } | 555 } |
| 556 }; | 556 }; |
| 557 | 557 |
| 558 /** | 558 /** |
| 559 * @unrestricted | 559 * @unrestricted |
| 560 */ | 560 */ |
| 561 WebInspector.AuditRules.CacheControlRule = class extends WebInspector.AuditRule
{ | 561 Audits.AuditRules.CacheControlRule = class extends Audits.AuditRule { |
| 562 constructor(id, name) { | 562 constructor(id, name) { |
| 563 super(id, name); | 563 super(id, name); |
| 564 } | 564 } |
| 565 | 565 |
| 566 /** | 566 /** |
| 567 * @override | 567 * @override |
| 568 * @param {!WebInspector.Target} target | 568 * @param {!SDK.Target} target |
| 569 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 569 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 570 * @param {!WebInspector.AuditRuleResult} result | 570 * @param {!Audits.AuditRuleResult} result |
| 571 * @param {function(!WebInspector.AuditRuleResult)} callback | 571 * @param {function(!Audits.AuditRuleResult)} callback |
| 572 * @param {!WebInspector.Progress} progress | 572 * @param {!Common.Progress} progress |
| 573 */ | 573 */ |
| 574 doRun(target, requests, result, callback, progress) { | 574 doRun(target, requests, result, callback, progress) { |
| 575 var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResour
ces(requests); | 575 var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResour
ces(requests); |
| 576 if (cacheableAndNonCacheableResources[0].length) | 576 if (cacheableAndNonCacheableResources[0].length) |
| 577 this.runChecks(cacheableAndNonCacheableResources[0], result); | 577 this.runChecks(cacheableAndNonCacheableResources[0], result); |
| 578 this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], resul
t); | 578 this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], resul
t); |
| 579 | 579 |
| 580 callback(result); | 580 callback(result); |
| 581 } | 581 } |
| 582 | 582 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 605 urls.push(requests[i].url); | 605 urls.push(requests[i].url); |
| 606 } | 606 } |
| 607 if (urls.length) { | 607 if (urls.length) { |
| 608 var entry = result.addChild(messageText, true); | 608 var entry = result.addChild(messageText, true); |
| 609 entry.addURLs(urls); | 609 entry.addURLs(urls); |
| 610 result.violationCount += urls.length; | 610 result.violationCount += urls.length; |
| 611 } | 611 } |
| 612 } | 612 } |
| 613 | 613 |
| 614 /** | 614 /** |
| 615 * @param {!WebInspector.NetworkRequest} request | 615 * @param {!SDK.NetworkRequest} request |
| 616 * @param {number} timeMs | 616 * @param {number} timeMs |
| 617 * @return {boolean} | 617 * @return {boolean} |
| 618 */ | 618 */ |
| 619 freshnessLifetimeGreaterThan(request, timeMs) { | 619 freshnessLifetimeGreaterThan(request, timeMs) { |
| 620 var dateHeader = this.responseHeader(request, 'Date'); | 620 var dateHeader = this.responseHeader(request, 'Date'); |
| 621 if (!dateHeader) | 621 if (!dateHeader) |
| 622 return false; | 622 return false; |
| 623 | 623 |
| 624 var dateHeaderMs = Date.parse(dateHeader); | 624 var dateHeaderMs = Date.parse(dateHeader); |
| 625 if (isNaN(dateHeaderMs)) | 625 if (isNaN(dateHeaderMs)) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 636 var expDate = Date.parse(expiresHeader); | 636 var expDate = Date.parse(expiresHeader); |
| 637 if (!isNaN(expDate)) | 637 if (!isNaN(expDate)) |
| 638 freshnessLifetimeMs = expDate - dateHeaderMs; | 638 freshnessLifetimeMs = expDate - dateHeaderMs; |
| 639 } | 639 } |
| 640 } | 640 } |
| 641 | 641 |
| 642 return (isNaN(freshnessLifetimeMs)) ? false : freshnessLifetimeMs > timeMs; | 642 return (isNaN(freshnessLifetimeMs)) ? false : freshnessLifetimeMs > timeMs; |
| 643 } | 643 } |
| 644 | 644 |
| 645 /** | 645 /** |
| 646 * @param {!WebInspector.NetworkRequest} request | 646 * @param {!SDK.NetworkRequest} request |
| 647 * @param {string} header | 647 * @param {string} header |
| 648 * @return {string|undefined} | 648 * @return {string|undefined} |
| 649 */ | 649 */ |
| 650 responseHeader(request, header) { | 650 responseHeader(request, header) { |
| 651 return request.responseHeaderValue(header); | 651 return request.responseHeaderValue(header); |
| 652 } | 652 } |
| 653 | 653 |
| 654 /** | 654 /** |
| 655 * @param {!WebInspector.NetworkRequest} request | 655 * @param {!SDK.NetworkRequest} request |
| 656 * @param {string} header | 656 * @param {string} header |
| 657 * @return {boolean} | 657 * @return {boolean} |
| 658 */ | 658 */ |
| 659 hasResponseHeader(request, header) { | 659 hasResponseHeader(request, header) { |
| 660 return request.responseHeaderValue(header) !== undefined; | 660 return request.responseHeaderValue(header) !== undefined; |
| 661 } | 661 } |
| 662 | 662 |
| 663 /** | 663 /** |
| 664 * @param {!WebInspector.NetworkRequest} request | 664 * @param {!SDK.NetworkRequest} request |
| 665 * @return {boolean} | 665 * @return {boolean} |
| 666 */ | 666 */ |
| 667 isCompressible(request) { | 667 isCompressible(request) { |
| 668 return request.resourceType().isTextType(); | 668 return request.resourceType().isTextType(); |
| 669 } | 669 } |
| 670 | 670 |
| 671 /** | 671 /** |
| 672 * @param {!WebInspector.NetworkRequest} request | 672 * @param {!SDK.NetworkRequest} request |
| 673 * @return {boolean} | 673 * @return {boolean} |
| 674 */ | 674 */ |
| 675 isPubliclyCacheable(request) { | 675 isPubliclyCacheable(request) { |
| 676 if (this._isExplicitlyNonCacheable(request)) | 676 if (this._isExplicitlyNonCacheable(request)) |
| 677 return false; | 677 return false; |
| 678 | 678 |
| 679 if (this.responseHeaderMatch(request, 'Cache-Control', 'public')) | 679 if (this.responseHeaderMatch(request, 'Cache-Control', 'public')) |
| 680 return true; | 680 return true; |
| 681 | 681 |
| 682 return request.url.indexOf('?') === -1 && !this.responseHeaderMatch(request,
'Cache-Control', 'private'); | 682 return request.url.indexOf('?') === -1 && !this.responseHeaderMatch(request,
'Cache-Control', 'private'); |
| 683 } | 683 } |
| 684 | 684 |
| 685 /** | 685 /** |
| 686 * @param {!WebInspector.NetworkRequest} request | 686 * @param {!SDK.NetworkRequest} request |
| 687 * @param {string} header | 687 * @param {string} header |
| 688 * @param {string} regexp | 688 * @param {string} regexp |
| 689 * @return {?Array.<string>} | 689 * @return {?Array.<string>} |
| 690 */ | 690 */ |
| 691 responseHeaderMatch(request, header, regexp) { | 691 responseHeaderMatch(request, header, regexp) { |
| 692 return request.responseHeaderValue(header) ? request.responseHeaderValue(hea
der).match(new RegExp(regexp, 'im')) : | 692 return request.responseHeaderValue(header) ? request.responseHeaderValue(hea
der).match(new RegExp(regexp, 'im')) : |
| 693 null; | 693 null; |
| 694 } | 694 } |
| 695 | 695 |
| 696 /** | 696 /** |
| 697 * @param {!WebInspector.NetworkRequest} request | 697 * @param {!SDK.NetworkRequest} request |
| 698 * @return {boolean} | 698 * @return {boolean} |
| 699 */ | 699 */ |
| 700 hasExplicitExpiration(request) { | 700 hasExplicitExpiration(request) { |
| 701 return this.hasResponseHeader(request, 'Date') && | 701 return this.hasResponseHeader(request, 'Date') && |
| 702 (this.hasResponseHeader(request, 'Expires') || !!this.responseHeaderMatc
h(request, 'Cache-Control', 'max-age')); | 702 (this.hasResponseHeader(request, 'Expires') || !!this.responseHeaderMatc
h(request, 'Cache-Control', 'max-age')); |
| 703 } | 703 } |
| 704 | 704 |
| 705 /** | 705 /** |
| 706 * @param {!WebInspector.NetworkRequest} request | 706 * @param {!SDK.NetworkRequest} request |
| 707 * @return {boolean} | 707 * @return {boolean} |
| 708 */ | 708 */ |
| 709 _isExplicitlyNonCacheable(request) { | 709 _isExplicitlyNonCacheable(request) { |
| 710 var hasExplicitExp = this.hasExplicitExpiration(request); | 710 var hasExplicitExp = this.hasExplicitExpiration(request); |
| 711 return !!this.responseHeaderMatch(request, 'Cache-Control', '(no-cache|no-st
ore)') || | 711 return !!this.responseHeaderMatch(request, 'Cache-Control', '(no-cache|no-st
ore)') || |
| 712 !!this.responseHeaderMatch(request, 'Pragma', 'no-cache') || | 712 !!this.responseHeaderMatch(request, 'Pragma', 'no-cache') || |
| 713 (hasExplicitExp && !this.freshnessLifetimeGreaterThan(request, 0)) || | 713 (hasExplicitExp && !this.freshnessLifetimeGreaterThan(request, 0)) || |
| 714 (!hasExplicitExp && !!request.url && request.url.indexOf('?') >= 0) || | 714 (!hasExplicitExp && !!request.url && request.url.indexOf('?') >= 0) || |
| 715 (!hasExplicitExp && !this.isCacheableResource(request)); | 715 (!hasExplicitExp && !this.isCacheableResource(request)); |
| 716 } | 716 } |
| 717 | 717 |
| 718 /** | 718 /** |
| 719 * @param {!WebInspector.NetworkRequest} request | 719 * @param {!SDK.NetworkRequest} request |
| 720 * @return {boolean} | 720 * @return {boolean} |
| 721 */ | 721 */ |
| 722 isCacheableResource(request) { | 722 isCacheableResource(request) { |
| 723 return request.statusCode !== undefined && WebInspector.AuditRules.Cacheable
ResponseCodes[request.statusCode]; | 723 return request.statusCode !== undefined && Audits.AuditRules.CacheableRespon
seCodes[request.statusCode]; |
| 724 } | 724 } |
| 725 }; | 725 }; |
| 726 | 726 |
| 727 WebInspector.AuditRules.CacheControlRule.MillisPerMonth = 1000 * 60 * 60 * 24 *
30; | 727 Audits.AuditRules.CacheControlRule.MillisPerMonth = 1000 * 60 * 60 * 24 * 30; |
| 728 | 728 |
| 729 /** | 729 /** |
| 730 * @unrestricted | 730 * @unrestricted |
| 731 */ | 731 */ |
| 732 WebInspector.AuditRules.BrowserCacheControlRule = class extends WebInspector.Aud
itRules.CacheControlRule { | 732 Audits.AuditRules.BrowserCacheControlRule = class extends Audits.AuditRules.Cach
eControlRule { |
| 733 constructor() { | 733 constructor() { |
| 734 super('http-browsercache', WebInspector.UIString('Leverage browser caching')
); | 734 super('http-browsercache', Common.UIString('Leverage browser caching')); |
| 735 } | 735 } |
| 736 | 736 |
| 737 /** | 737 /** |
| 738 * @override | 738 * @override |
| 739 */ | 739 */ |
| 740 handleNonCacheableResources(requests, result) { | 740 handleNonCacheableResources(requests, result) { |
| 741 if (requests.length) { | 741 if (requests.length) { |
| 742 var entry = result.addChild( | 742 var entry = result.addChild( |
| 743 WebInspector.UIString( | 743 Common.UIString( |
| 744 'The following resources are explicitly non-cacheable. Consider ma
king them cacheable if possible:'), | 744 'The following resources are explicitly non-cacheable. Consider ma
king them cacheable if possible:'), |
| 745 true); | 745 true); |
| 746 result.violationCount += requests.length; | 746 result.violationCount += requests.length; |
| 747 for (var i = 0; i < requests.length; ++i) | 747 for (var i = 0; i < requests.length; ++i) |
| 748 entry.addURL(requests[i].url); | 748 entry.addURL(requests[i].url); |
| 749 } | 749 } |
| 750 } | 750 } |
| 751 | 751 |
| 752 runChecks(requests, result, callback) { | 752 runChecks(requests, result, callback) { |
| 753 this.execCheck( | 753 this.execCheck( |
| 754 WebInspector.UIString( | 754 Common.UIString( |
| 755 'The following resources are missing a cache expiration. Resources t
hat do not specify an expiration may not be cached by browsers:'), | 755 'The following resources are missing a cache expiration. Resources t
hat do not specify an expiration may not be cached by browsers:'), |
| 756 this._missingExpirationCheck, requests, result); | 756 this._missingExpirationCheck, requests, result); |
| 757 this.execCheck( | 757 this.execCheck( |
| 758 WebInspector.UIString( | 758 Common.UIString( |
| 759 'The following resources specify a "Vary" header that disables cachi
ng in most versions of Internet Explorer:'), | 759 'The following resources specify a "Vary" header that disables cachi
ng in most versions of Internet Explorer:'), |
| 760 this._varyCheck, requests, result); | 760 this._varyCheck, requests, result); |
| 761 this.execCheck( | 761 this.execCheck( |
| 762 WebInspector.UIString('The following cacheable resources have a short fr
eshness lifetime:'), | 762 Common.UIString('The following cacheable resources have a short freshnes
s lifetime:'), |
| 763 this._oneMonthExpirationCheck, requests, result); | 763 this._oneMonthExpirationCheck, requests, result); |
| 764 | 764 |
| 765 // Unable to implement the favicon check due to the WebKit limitations. | 765 // Unable to implement the favicon check due to the WebKit limitations. |
| 766 this.execCheck( | 766 this.execCheck( |
| 767 WebInspector.UIString( | 767 Common.UIString( |
| 768 'To further improve cache hit rate, specify an expiration one year i
n the future for the following cacheable resources:'), | 768 'To further improve cache hit rate, specify an expiration one year i
n the future for the following cacheable resources:'), |
| 769 this._oneYearExpirationCheck, requests, result); | 769 this._oneYearExpirationCheck, requests, result); |
| 770 } | 770 } |
| 771 | 771 |
| 772 _missingExpirationCheck(request) { | 772 _missingExpirationCheck(request) { |
| 773 return this.isCacheableResource(request) && !this.hasResponseHeader(request,
'Set-Cookie') && | 773 return this.isCacheableResource(request) && !this.hasResponseHeader(request,
'Set-Cookie') && |
| 774 !this.hasExplicitExpiration(request); | 774 !this.hasExplicitExpiration(request); |
| 775 } | 775 } |
| 776 | 776 |
| 777 _varyCheck(request) { | 777 _varyCheck(request) { |
| 778 var varyHeader = this.responseHeader(request, 'Vary'); | 778 var varyHeader = this.responseHeader(request, 'Vary'); |
| 779 if (varyHeader) { | 779 if (varyHeader) { |
| 780 varyHeader = varyHeader.replace(/User-Agent/gi, ''); | 780 varyHeader = varyHeader.replace(/User-Agent/gi, ''); |
| 781 varyHeader = varyHeader.replace(/Accept-Encoding/gi, ''); | 781 varyHeader = varyHeader.replace(/Accept-Encoding/gi, ''); |
| 782 varyHeader = varyHeader.replace(/[, ]*/g, ''); | 782 varyHeader = varyHeader.replace(/[, ]*/g, ''); |
| 783 } | 783 } |
| 784 return varyHeader && varyHeader.length && this.isCacheableResource(request)
&& | 784 return varyHeader && varyHeader.length && this.isCacheableResource(request)
&& |
| 785 this.freshnessLifetimeGreaterThan(request, 0); | 785 this.freshnessLifetimeGreaterThan(request, 0); |
| 786 } | 786 } |
| 787 | 787 |
| 788 _oneMonthExpirationCheck(request) { | 788 _oneMonthExpirationCheck(request) { |
| 789 return this.isCacheableResource(request) && !this.hasResponseHeader(request,
'Set-Cookie') && | 789 return this.isCacheableResource(request) && !this.hasResponseHeader(request,
'Set-Cookie') && |
| 790 !this.freshnessLifetimeGreaterThan(request, WebInspector.AuditRules.Cach
eControlRule.MillisPerMonth) && | 790 !this.freshnessLifetimeGreaterThan(request, Audits.AuditRules.CacheContr
olRule.MillisPerMonth) && |
| 791 this.freshnessLifetimeGreaterThan(request, 0); | 791 this.freshnessLifetimeGreaterThan(request, 0); |
| 792 } | 792 } |
| 793 | 793 |
| 794 _oneYearExpirationCheck(request) { | 794 _oneYearExpirationCheck(request) { |
| 795 return this.isCacheableResource(request) && !this.hasResponseHeader(request,
'Set-Cookie') && | 795 return this.isCacheableResource(request) && !this.hasResponseHeader(request,
'Set-Cookie') && |
| 796 !this.freshnessLifetimeGreaterThan(request, 11 * WebInspector.AuditRules
.CacheControlRule.MillisPerMonth) && | 796 !this.freshnessLifetimeGreaterThan(request, 11 * Audits.AuditRules.Cache
ControlRule.MillisPerMonth) && |
| 797 this.freshnessLifetimeGreaterThan(request, WebInspector.AuditRules.Cache
ControlRule.MillisPerMonth); | 797 this.freshnessLifetimeGreaterThan(request, Audits.AuditRules.CacheContro
lRule.MillisPerMonth); |
| 798 } | 798 } |
| 799 }; | 799 }; |
| 800 | 800 |
| 801 /** | 801 /** |
| 802 * @unrestricted | 802 * @unrestricted |
| 803 */ | 803 */ |
| 804 WebInspector.AuditRules.ImageDimensionsRule = class extends WebInspector.AuditRu
le { | 804 Audits.AuditRules.ImageDimensionsRule = class extends Audits.AuditRule { |
| 805 constructor() { | 805 constructor() { |
| 806 super('page-imagedims', WebInspector.UIString('Specify image dimensions')); | 806 super('page-imagedims', Common.UIString('Specify image dimensions')); |
| 807 } | 807 } |
| 808 | 808 |
| 809 /** | 809 /** |
| 810 * @override | 810 * @override |
| 811 * @param {!WebInspector.Target} target | 811 * @param {!SDK.Target} target |
| 812 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 812 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 813 * @param {!WebInspector.AuditRuleResult} result | 813 * @param {!Audits.AuditRuleResult} result |
| 814 * @param {function(?WebInspector.AuditRuleResult)} callback | 814 * @param {function(?Audits.AuditRuleResult)} callback |
| 815 * @param {!WebInspector.Progress} progress | 815 * @param {!Common.Progress} progress |
| 816 */ | 816 */ |
| 817 doRun(target, requests, result, callback, progress) { | 817 doRun(target, requests, result, callback, progress) { |
| 818 var domModel = WebInspector.DOMModel.fromTarget(target); | 818 var domModel = SDK.DOMModel.fromTarget(target); |
| 819 var cssModel = WebInspector.CSSModel.fromTarget(target); | 819 var cssModel = SDK.CSSModel.fromTarget(target); |
| 820 if (!domModel || !cssModel) { | 820 if (!domModel || !cssModel) { |
| 821 callback(null); | 821 callback(null); |
| 822 return; | 822 return; |
| 823 } | 823 } |
| 824 | 824 |
| 825 var urlToNoDimensionCount = {}; | 825 var urlToNoDimensionCount = {}; |
| 826 | 826 |
| 827 function doneCallback() { | 827 function doneCallback() { |
| 828 for (var url in urlToNoDimensionCount) { | 828 for (var url in urlToNoDimensionCount) { |
| 829 var entry = entry || | 829 var entry = entry || |
| 830 result.addChild( | 830 result.addChild( |
| 831 WebInspector.UIString( | 831 Common.UIString( |
| 832 'A width and height should be specified for all images in or
der to speed up page display. The following image(s) are missing a width and/or
height:'), | 832 'A width and height should be specified for all images in or
der to speed up page display. The following image(s) are missing a width and/or
height:'), |
| 833 true); | 833 true); |
| 834 var format = '%r'; | 834 var format = '%r'; |
| 835 if (urlToNoDimensionCount[url] > 1) | 835 if (urlToNoDimensionCount[url] > 1) |
| 836 format += ' (%d uses)'; | 836 format += ' (%d uses)'; |
| 837 entry.addFormatted(format, url, urlToNoDimensionCount[url]); | 837 entry.addFormatted(format, url, urlToNoDimensionCount[url]); |
| 838 result.violationCount++; | 838 result.violationCount++; |
| 839 } | 839 } |
| 840 callback(entry ? result : null); | 840 callback(entry ? result : null); |
| 841 } | 841 } |
| 842 | 842 |
| 843 function imageStylesReady(imageId, styles) { | 843 function imageStylesReady(imageId, styles) { |
| 844 if (progress.isCanceled()) { | 844 if (progress.isCanceled()) { |
| 845 callback(null); | 845 callback(null); |
| 846 return; | 846 return; |
| 847 } | 847 } |
| 848 | 848 |
| 849 const node = domModel.nodeForId(imageId); | 849 const node = domModel.nodeForId(imageId); |
| 850 var src = node.getAttribute('src'); | 850 var src = node.getAttribute('src'); |
| 851 if (!src.asParsedURL()) { | 851 if (!src.asParsedURL()) { |
| 852 for (var frameOwnerCandidate = node; frameOwnerCandidate; | 852 for (var frameOwnerCandidate = node; frameOwnerCandidate; |
| 853 frameOwnerCandidate = frameOwnerCandidate.parentNode) { | 853 frameOwnerCandidate = frameOwnerCandidate.parentNode) { |
| 854 if (frameOwnerCandidate.baseURL) { | 854 if (frameOwnerCandidate.baseURL) { |
| 855 var completeSrc = WebInspector.ParsedURL.completeURL(frameOwnerCandi
date.baseURL, src); | 855 var completeSrc = Common.ParsedURL.completeURL(frameOwnerCandidate.b
aseURL, src); |
| 856 break; | 856 break; |
| 857 } | 857 } |
| 858 } | 858 } |
| 859 } | 859 } |
| 860 if (completeSrc) | 860 if (completeSrc) |
| 861 src = completeSrc; | 861 src = completeSrc; |
| 862 | 862 |
| 863 if (styles.computedStyle.get('position') === 'absolute') | 863 if (styles.computedStyle.get('position') === 'absolute') |
| 864 return; | 864 return; |
| 865 | 865 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 885 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds | 885 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds |
| 886 */ | 886 */ |
| 887 function getStyles(nodeIds) { | 887 function getStyles(nodeIds) { |
| 888 if (progress.isCanceled()) { | 888 if (progress.isCanceled()) { |
| 889 callback(null); | 889 callback(null); |
| 890 return; | 890 return; |
| 891 } | 891 } |
| 892 var targetResult = {}; | 892 var targetResult = {}; |
| 893 | 893 |
| 894 /** | 894 /** |
| 895 * @param {?WebInspector.CSSMatchedStyles} matchedStyleResult | 895 * @param {?SDK.CSSMatchedStyles} matchedStyleResult |
| 896 */ | 896 */ |
| 897 function matchedCallback(matchedStyleResult) { | 897 function matchedCallback(matchedStyleResult) { |
| 898 if (!matchedStyleResult) | 898 if (!matchedStyleResult) |
| 899 return; | 899 return; |
| 900 targetResult.nodeStyles = matchedStyleResult.nodeStyles(); | 900 targetResult.nodeStyles = matchedStyleResult.nodeStyles(); |
| 901 } | 901 } |
| 902 | 902 |
| 903 /** | 903 /** |
| 904 * @param {?Map.<string, string>} computedStyle | 904 * @param {?Map.<string, string>} computedStyle |
| 905 */ | 905 */ |
| (...skipping 28 matching lines...) Expand all Loading... |
| 934 callback(null); | 934 callback(null); |
| 935 return; | 935 return; |
| 936 } | 936 } |
| 937 domModel.requestDocument(onDocumentAvailable); | 937 domModel.requestDocument(onDocumentAvailable); |
| 938 } | 938 } |
| 939 }; | 939 }; |
| 940 | 940 |
| 941 /** | 941 /** |
| 942 * @unrestricted | 942 * @unrestricted |
| 943 */ | 943 */ |
| 944 WebInspector.AuditRules.CssInHeadRule = class extends WebInspector.AuditRule { | 944 Audits.AuditRules.CssInHeadRule = class extends Audits.AuditRule { |
| 945 constructor() { | 945 constructor() { |
| 946 super('page-cssinhead', WebInspector.UIString('Put CSS in the document head'
)); | 946 super('page-cssinhead', Common.UIString('Put CSS in the document head')); |
| 947 } | 947 } |
| 948 | 948 |
| 949 /** | 949 /** |
| 950 * @override | 950 * @override |
| 951 * @param {!WebInspector.Target} target | 951 * @param {!SDK.Target} target |
| 952 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 952 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 953 * @param {!WebInspector.AuditRuleResult} result | 953 * @param {!Audits.AuditRuleResult} result |
| 954 * @param {function(?WebInspector.AuditRuleResult)} callback | 954 * @param {function(?Audits.AuditRuleResult)} callback |
| 955 * @param {!WebInspector.Progress} progress | 955 * @param {!Common.Progress} progress |
| 956 */ | 956 */ |
| 957 doRun(target, requests, result, callback, progress) { | 957 doRun(target, requests, result, callback, progress) { |
| 958 var domModel = WebInspector.DOMModel.fromTarget(target); | 958 var domModel = SDK.DOMModel.fromTarget(target); |
| 959 if (!domModel) { | 959 if (!domModel) { |
| 960 callback(null); | 960 callback(null); |
| 961 return; | 961 return; |
| 962 } | 962 } |
| 963 | 963 |
| 964 function evalCallback(evalResult) { | 964 function evalCallback(evalResult) { |
| 965 if (progress.isCanceled()) { | 965 if (progress.isCanceled()) { |
| 966 callback(null); | 966 callback(null); |
| 967 return; | 967 return; |
| 968 } | 968 } |
| 969 | 969 |
| 970 if (!evalResult) | 970 if (!evalResult) |
| 971 return callback(null); | 971 return callback(null); |
| 972 | 972 |
| 973 var summary = result.addChild(''); | 973 var summary = result.addChild(''); |
| 974 | 974 |
| 975 for (var url in evalResult) { | 975 for (var url in evalResult) { |
| 976 var urlViolations = evalResult[url]; | 976 var urlViolations = evalResult[url]; |
| 977 if (urlViolations[0]) { | 977 if (urlViolations[0]) { |
| 978 result.addFormatted( | 978 result.addFormatted( |
| 979 '%s style block(s) in the %r body should be moved to the document
head.', urlViolations[0], url); | 979 '%s style block(s) in the %r body should be moved to the document
head.', urlViolations[0], url); |
| 980 result.violationCount += urlViolations[0]; | 980 result.violationCount += urlViolations[0]; |
| 981 } | 981 } |
| 982 for (var i = 0; i < urlViolations[1].length; ++i) | 982 for (var i = 0; i < urlViolations[1].length; ++i) |
| 983 result.addFormatted('Link node %r should be moved to the document head
in %r', urlViolations[1][i], url); | 983 result.addFormatted('Link node %r should be moved to the document head
in %r', urlViolations[1][i], url); |
| 984 result.violationCount += urlViolations[1].length; | 984 result.violationCount += urlViolations[1].length; |
| 985 } | 985 } |
| 986 summary.value = WebInspector.UIString('CSS in the document body adversely
impacts rendering performance.'); | 986 summary.value = Common.UIString('CSS in the document body adversely impact
s rendering performance.'); |
| 987 callback(result); | 987 callback(result); |
| 988 } | 988 } |
| 989 | 989 |
| 990 /** | 990 /** |
| 991 * @param {!WebInspector.DOMNode} root | 991 * @param {!SDK.DOMNode} root |
| 992 * @param {!Array.<!Protocol.DOM.NodeId>=} inlineStyleNodeIds | 992 * @param {!Array.<!Protocol.DOM.NodeId>=} inlineStyleNodeIds |
| 993 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds | 993 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds |
| 994 */ | 994 */ |
| 995 function externalStylesheetsReceived(root, inlineStyleNodeIds, nodeIds) { | 995 function externalStylesheetsReceived(root, inlineStyleNodeIds, nodeIds) { |
| 996 if (progress.isCanceled()) { | 996 if (progress.isCanceled()) { |
| 997 callback(null); | 997 callback(null); |
| 998 return; | 998 return; |
| 999 } | 999 } |
| 1000 | 1000 |
| 1001 if (!nodeIds) | 1001 if (!nodeIds) |
| 1002 return; | 1002 return; |
| 1003 var externalStylesheetNodeIds = nodeIds; | 1003 var externalStylesheetNodeIds = nodeIds; |
| 1004 var result = null; | 1004 var result = null; |
| 1005 if (inlineStyleNodeIds.length || externalStylesheetNodeIds.length) { | 1005 if (inlineStyleNodeIds.length || externalStylesheetNodeIds.length) { |
| 1006 var urlToViolationsArray = {}; | 1006 var urlToViolationsArray = {}; |
| 1007 var externalStylesheetHrefs = []; | 1007 var externalStylesheetHrefs = []; |
| 1008 for (var j = 0; j < externalStylesheetNodeIds.length; ++j) { | 1008 for (var j = 0; j < externalStylesheetNodeIds.length; ++j) { |
| 1009 var linkNode = domModel.nodeForId(externalStylesheetNodeIds[j]); | 1009 var linkNode = domModel.nodeForId(externalStylesheetNodeIds[j]); |
| 1010 var completeHref = | 1010 var completeHref = |
| 1011 WebInspector.ParsedURL.completeURL(linkNode.ownerDocument.baseURL,
linkNode.getAttribute('href')); | 1011 Common.ParsedURL.completeURL(linkNode.ownerDocument.baseURL, linkN
ode.getAttribute('href')); |
| 1012 externalStylesheetHrefs.push(completeHref || '<empty>'); | 1012 externalStylesheetHrefs.push(completeHref || '<empty>'); |
| 1013 } | 1013 } |
| 1014 urlToViolationsArray[root.documentURL] = [inlineStyleNodeIds.length, ext
ernalStylesheetHrefs]; | 1014 urlToViolationsArray[root.documentURL] = [inlineStyleNodeIds.length, ext
ernalStylesheetHrefs]; |
| 1015 result = urlToViolationsArray; | 1015 result = urlToViolationsArray; |
| 1016 } | 1016 } |
| 1017 evalCallback(result); | 1017 evalCallback(result); |
| 1018 } | 1018 } |
| 1019 | 1019 |
| 1020 /** | 1020 /** |
| 1021 * @param {!WebInspector.DOMNode} root | 1021 * @param {!SDK.DOMNode} root |
| 1022 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds | 1022 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds |
| 1023 */ | 1023 */ |
| 1024 function inlineStylesReceived(root, nodeIds) { | 1024 function inlineStylesReceived(root, nodeIds) { |
| 1025 if (progress.isCanceled()) { | 1025 if (progress.isCanceled()) { |
| 1026 callback(null); | 1026 callback(null); |
| 1027 return; | 1027 return; |
| 1028 } | 1028 } |
| 1029 | 1029 |
| 1030 if (!nodeIds) | 1030 if (!nodeIds) |
| 1031 return; | 1031 return; |
| 1032 domModel.querySelectorAll( | 1032 domModel.querySelectorAll( |
| 1033 root.id, 'body link[rel~=\'stylesheet\'][href]', externalStylesheetsRe
ceived.bind(null, root, nodeIds)); | 1033 root.id, 'body link[rel~=\'stylesheet\'][href]', externalStylesheetsRe
ceived.bind(null, root, nodeIds)); |
| 1034 } | 1034 } |
| 1035 | 1035 |
| 1036 /** | 1036 /** |
| 1037 * @param {!WebInspector.DOMNode} root | 1037 * @param {!SDK.DOMNode} root |
| 1038 */ | 1038 */ |
| 1039 function onDocumentAvailable(root) { | 1039 function onDocumentAvailable(root) { |
| 1040 if (progress.isCanceled()) { | 1040 if (progress.isCanceled()) { |
| 1041 callback(null); | 1041 callback(null); |
| 1042 return; | 1042 return; |
| 1043 } | 1043 } |
| 1044 | 1044 |
| 1045 domModel.querySelectorAll(root.id, 'body style', inlineStylesReceived.bind
(null, root)); | 1045 domModel.querySelectorAll(root.id, 'body style', inlineStylesReceived.bind
(null, root)); |
| 1046 } | 1046 } |
| 1047 | 1047 |
| 1048 domModel.requestDocument(onDocumentAvailable); | 1048 domModel.requestDocument(onDocumentAvailable); |
| 1049 } | 1049 } |
| 1050 }; | 1050 }; |
| 1051 | 1051 |
| 1052 /** | 1052 /** |
| 1053 * @unrestricted | 1053 * @unrestricted |
| 1054 */ | 1054 */ |
| 1055 WebInspector.AuditRules.StylesScriptsOrderRule = class extends WebInspector.Audi
tRule { | 1055 Audits.AuditRules.StylesScriptsOrderRule = class extends Audits.AuditRule { |
| 1056 constructor() { | 1056 constructor() { |
| 1057 super('page-stylescriptorder', WebInspector.UIString('Optimize the order of
styles and scripts')); | 1057 super('page-stylescriptorder', Common.UIString('Optimize the order of styles
and scripts')); |
| 1058 } | 1058 } |
| 1059 | 1059 |
| 1060 /** | 1060 /** |
| 1061 * @override | 1061 * @override |
| 1062 * @param {!WebInspector.Target} target | 1062 * @param {!SDK.Target} target |
| 1063 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 1063 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 1064 * @param {!WebInspector.AuditRuleResult} result | 1064 * @param {!Audits.AuditRuleResult} result |
| 1065 * @param {function(?WebInspector.AuditRuleResult)} callback | 1065 * @param {function(?Audits.AuditRuleResult)} callback |
| 1066 * @param {!WebInspector.Progress} progress | 1066 * @param {!Common.Progress} progress |
| 1067 */ | 1067 */ |
| 1068 doRun(target, requests, result, callback, progress) { | 1068 doRun(target, requests, result, callback, progress) { |
| 1069 var domModel = WebInspector.DOMModel.fromTarget(target); | 1069 var domModel = SDK.DOMModel.fromTarget(target); |
| 1070 if (!domModel) { | 1070 if (!domModel) { |
| 1071 callback(null); | 1071 callback(null); |
| 1072 return; | 1072 return; |
| 1073 } | 1073 } |
| 1074 | 1074 |
| 1075 function evalCallback(resultValue) { | 1075 function evalCallback(resultValue) { |
| 1076 if (progress.isCanceled()) { | 1076 if (progress.isCanceled()) { |
| 1077 callback(null); | 1077 callback(null); |
| 1078 return; | 1078 return; |
| 1079 } | 1079 } |
| 1080 | 1080 |
| 1081 if (!resultValue) | 1081 if (!resultValue) |
| 1082 return callback(null); | 1082 return callback(null); |
| 1083 | 1083 |
| 1084 var lateCssUrls = resultValue[0]; | 1084 var lateCssUrls = resultValue[0]; |
| 1085 var cssBeforeInlineCount = resultValue[1]; | 1085 var cssBeforeInlineCount = resultValue[1]; |
| 1086 | 1086 |
| 1087 if (lateCssUrls.length) { | 1087 if (lateCssUrls.length) { |
| 1088 var entry = result.addChild( | 1088 var entry = result.addChild( |
| 1089 WebInspector.UIString( | 1089 Common.UIString( |
| 1090 'The following external CSS files were included after an externa
l JavaScript file in the document head. To ensure CSS files are downloaded in pa
rallel, always include external CSS before external JavaScript.'), | 1090 'The following external CSS files were included after an externa
l JavaScript file in the document head. To ensure CSS files are downloaded in pa
rallel, always include external CSS before external JavaScript.'), |
| 1091 true); | 1091 true); |
| 1092 entry.addURLs(lateCssUrls); | 1092 entry.addURLs(lateCssUrls); |
| 1093 result.violationCount += lateCssUrls.length; | 1093 result.violationCount += lateCssUrls.length; |
| 1094 } | 1094 } |
| 1095 | 1095 |
| 1096 if (cssBeforeInlineCount) { | 1096 if (cssBeforeInlineCount) { |
| 1097 result.addChild(WebInspector.UIString( | 1097 result.addChild(Common.UIString( |
| 1098 ' %d inline script block%s found in the head between an external CSS
file and another resource. To allow parallel downloading, move the inline scrip
t before the external CSS file, or after the next resource.', | 1098 ' %d inline script block%s found in the head between an external CSS
file and another resource. To allow parallel downloading, move the inline scrip
t before the external CSS file, or after the next resource.', |
| 1099 cssBeforeInlineCount, cssBeforeInlineCount > 1 ? 's were' : ' was'))
; | 1099 cssBeforeInlineCount, cssBeforeInlineCount > 1 ? 's were' : ' was'))
; |
| 1100 result.violationCount += cssBeforeInlineCount; | 1100 result.violationCount += cssBeforeInlineCount; |
| 1101 } | 1101 } |
| 1102 callback(result); | 1102 callback(result); |
| 1103 } | 1103 } |
| 1104 | 1104 |
| 1105 /** | 1105 /** |
| 1106 * @param {!Array.<!Protocol.DOM.NodeId>} lateStyleIds | 1106 * @param {!Array.<!Protocol.DOM.NodeId>} lateStyleIds |
| 1107 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds | 1107 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds |
| 1108 */ | 1108 */ |
| 1109 function cssBeforeInlineReceived(lateStyleIds, nodeIds) { | 1109 function cssBeforeInlineReceived(lateStyleIds, nodeIds) { |
| 1110 if (progress.isCanceled()) { | 1110 if (progress.isCanceled()) { |
| 1111 callback(null); | 1111 callback(null); |
| 1112 return; | 1112 return; |
| 1113 } | 1113 } |
| 1114 | 1114 |
| 1115 if (!nodeIds) | 1115 if (!nodeIds) |
| 1116 return; | 1116 return; |
| 1117 | 1117 |
| 1118 var cssBeforeInlineCount = nodeIds.length; | 1118 var cssBeforeInlineCount = nodeIds.length; |
| 1119 var result = null; | 1119 var result = null; |
| 1120 if (lateStyleIds.length || cssBeforeInlineCount) { | 1120 if (lateStyleIds.length || cssBeforeInlineCount) { |
| 1121 var lateStyleUrls = []; | 1121 var lateStyleUrls = []; |
| 1122 for (var i = 0; i < lateStyleIds.length; ++i) { | 1122 for (var i = 0; i < lateStyleIds.length; ++i) { |
| 1123 var lateStyleNode = domModel.nodeForId(lateStyleIds[i]); | 1123 var lateStyleNode = domModel.nodeForId(lateStyleIds[i]); |
| 1124 var completeHref = WebInspector.ParsedURL.completeURL( | 1124 var completeHref = Common.ParsedURL.completeURL( |
| 1125 lateStyleNode.ownerDocument.baseURL, lateStyleNode.getAttribute('h
ref')); | 1125 lateStyleNode.ownerDocument.baseURL, lateStyleNode.getAttribute('h
ref')); |
| 1126 lateStyleUrls.push(completeHref || '<empty>'); | 1126 lateStyleUrls.push(completeHref || '<empty>'); |
| 1127 } | 1127 } |
| 1128 result = [lateStyleUrls, cssBeforeInlineCount]; | 1128 result = [lateStyleUrls, cssBeforeInlineCount]; |
| 1129 } | 1129 } |
| 1130 | 1130 |
| 1131 evalCallback(result); | 1131 evalCallback(result); |
| 1132 } | 1132 } |
| 1133 | 1133 |
| 1134 /** | 1134 /** |
| 1135 * @param {!WebInspector.DOMDocument} root | 1135 * @param {!SDK.DOMDocument} root |
| 1136 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds | 1136 * @param {!Array.<!Protocol.DOM.NodeId>=} nodeIds |
| 1137 */ | 1137 */ |
| 1138 function lateStylesReceived(root, nodeIds) { | 1138 function lateStylesReceived(root, nodeIds) { |
| 1139 if (progress.isCanceled()) { | 1139 if (progress.isCanceled()) { |
| 1140 callback(null); | 1140 callback(null); |
| 1141 return; | 1141 return; |
| 1142 } | 1142 } |
| 1143 | 1143 |
| 1144 if (!nodeIds) | 1144 if (!nodeIds) |
| 1145 return; | 1145 return; |
| 1146 | 1146 |
| 1147 domModel.querySelectorAll( | 1147 domModel.querySelectorAll( |
| 1148 root.id, 'head link[rel~=\'stylesheet\'][href] ~ script:not([src])', | 1148 root.id, 'head link[rel~=\'stylesheet\'][href] ~ script:not([src])', |
| 1149 cssBeforeInlineReceived.bind(null, nodeIds)); | 1149 cssBeforeInlineReceived.bind(null, nodeIds)); |
| 1150 } | 1150 } |
| 1151 | 1151 |
| 1152 /** | 1152 /** |
| 1153 * @param {!WebInspector.DOMDocument} root | 1153 * @param {!SDK.DOMDocument} root |
| 1154 */ | 1154 */ |
| 1155 function onDocumentAvailable(root) { | 1155 function onDocumentAvailable(root) { |
| 1156 if (progress.isCanceled()) { | 1156 if (progress.isCanceled()) { |
| 1157 callback(null); | 1157 callback(null); |
| 1158 return; | 1158 return; |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 domModel.querySelectorAll( | 1161 domModel.querySelectorAll( |
| 1162 root.id, 'head script[src] ~ link[rel~=\'stylesheet\'][href]', lateSty
lesReceived.bind(null, root)); | 1162 root.id, 'head script[src] ~ link[rel~=\'stylesheet\'][href]', lateSty
lesReceived.bind(null, root)); |
| 1163 } | 1163 } |
| 1164 | 1164 |
| 1165 domModel.requestDocument(onDocumentAvailable); | 1165 domModel.requestDocument(onDocumentAvailable); |
| 1166 } | 1166 } |
| 1167 }; | 1167 }; |
| 1168 | 1168 |
| 1169 /** | 1169 /** |
| 1170 * @unrestricted | 1170 * @unrestricted |
| 1171 */ | 1171 */ |
| 1172 WebInspector.AuditRules.CSSRuleBase = class extends WebInspector.AuditRule { | 1172 Audits.AuditRules.CSSRuleBase = class extends Audits.AuditRule { |
| 1173 constructor(id, name) { | 1173 constructor(id, name) { |
| 1174 super(id, name); | 1174 super(id, name); |
| 1175 } | 1175 } |
| 1176 | 1176 |
| 1177 /** | 1177 /** |
| 1178 * @override | 1178 * @override |
| 1179 * @param {!WebInspector.Target} target | 1179 * @param {!SDK.Target} target |
| 1180 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 1180 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 1181 * @param {!WebInspector.AuditRuleResult} result | 1181 * @param {!Audits.AuditRuleResult} result |
| 1182 * @param {function(?WebInspector.AuditRuleResult)} callback | 1182 * @param {function(?Audits.AuditRuleResult)} callback |
| 1183 * @param {!WebInspector.Progress} progress | 1183 * @param {!Common.Progress} progress |
| 1184 */ | 1184 */ |
| 1185 doRun(target, requests, result, callback, progress) { | 1185 doRun(target, requests, result, callback, progress) { |
| 1186 var cssModel = WebInspector.CSSModel.fromTarget(target); | 1186 var cssModel = SDK.CSSModel.fromTarget(target); |
| 1187 if (!cssModel) { | 1187 if (!cssModel) { |
| 1188 callback(null); | 1188 callback(null); |
| 1189 return; | 1189 return; |
| 1190 } | 1190 } |
| 1191 | 1191 |
| 1192 var headers = cssModel.allStyleSheets(); | 1192 var headers = cssModel.allStyleSheets(); |
| 1193 if (!headers.length) { | 1193 if (!headers.length) { |
| 1194 callback(null); | 1194 callback(null); |
| 1195 return; | 1195 return; |
| 1196 } | 1196 } |
| 1197 var activeHeaders = []; | 1197 var activeHeaders = []; |
| 1198 for (var i = 0; i < headers.length; ++i) { | 1198 for (var i = 0; i < headers.length; ++i) { |
| 1199 if (!headers[i].disabled) | 1199 if (!headers[i].disabled) |
| 1200 activeHeaders.push(headers[i]); | 1200 activeHeaders.push(headers[i]); |
| 1201 } | 1201 } |
| 1202 | 1202 |
| 1203 var styleSheetProcessor = new WebInspector.AuditRules.StyleSheetProcessor( | 1203 var styleSheetProcessor = new Audits.AuditRules.StyleSheetProcessor( |
| 1204 activeHeaders, progress, this._styleSheetsLoaded.bind(this, result, call
back, progress)); | 1204 activeHeaders, progress, this._styleSheetsLoaded.bind(this, result, call
back, progress)); |
| 1205 styleSheetProcessor.run(); | 1205 styleSheetProcessor.run(); |
| 1206 } | 1206 } |
| 1207 | 1207 |
| 1208 /** | 1208 /** |
| 1209 * @param {!WebInspector.AuditRuleResult} result | 1209 * @param {!Audits.AuditRuleResult} result |
| 1210 * @param {function(!WebInspector.AuditRuleResult)} callback | 1210 * @param {function(!Audits.AuditRuleResult)} callback |
| 1211 * @param {!WebInspector.Progress} progress | 1211 * @param {!Common.Progress} progress |
| 1212 * @param {!Array.<!WebInspector.AuditRules.ParsedStyleSheet>} styleSheets | 1212 * @param {!Array.<!Audits.AuditRules.ParsedStyleSheet>} styleSheets |
| 1213 */ | 1213 */ |
| 1214 _styleSheetsLoaded(result, callback, progress, styleSheets) { | 1214 _styleSheetsLoaded(result, callback, progress, styleSheets) { |
| 1215 for (var i = 0; i < styleSheets.length; ++i) | 1215 for (var i = 0; i < styleSheets.length; ++i) |
| 1216 this._visitStyleSheet(styleSheets[i], result); | 1216 this._visitStyleSheet(styleSheets[i], result); |
| 1217 callback(result); | 1217 callback(result); |
| 1218 } | 1218 } |
| 1219 | 1219 |
| 1220 /** | 1220 /** |
| 1221 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1221 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1222 * @param {!WebInspector.AuditRuleResult} result | 1222 * @param {!Audits.AuditRuleResult} result |
| 1223 */ | 1223 */ |
| 1224 _visitStyleSheet(styleSheet, result) { | 1224 _visitStyleSheet(styleSheet, result) { |
| 1225 this.visitStyleSheet(styleSheet, result); | 1225 this.visitStyleSheet(styleSheet, result); |
| 1226 | 1226 |
| 1227 for (var i = 0; i < styleSheet.rules.length; ++i) | 1227 for (var i = 0; i < styleSheet.rules.length; ++i) |
| 1228 this._visitRule(styleSheet, styleSheet.rules[i], result); | 1228 this._visitRule(styleSheet, styleSheet.rules[i], result); |
| 1229 | 1229 |
| 1230 this.didVisitStyleSheet(styleSheet, result); | 1230 this.didVisitStyleSheet(styleSheet, result); |
| 1231 } | 1231 } |
| 1232 | 1232 |
| 1233 /** | 1233 /** |
| 1234 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1234 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1235 * @param {!WebInspector.CSSParser.StyleRule} rule | 1235 * @param {!SDK.CSSParser.StyleRule} rule |
| 1236 * @param {!WebInspector.AuditRuleResult} result | 1236 * @param {!Audits.AuditRuleResult} result |
| 1237 */ | 1237 */ |
| 1238 _visitRule(styleSheet, rule, result) { | 1238 _visitRule(styleSheet, rule, result) { |
| 1239 this.visitRule(styleSheet, rule, result); | 1239 this.visitRule(styleSheet, rule, result); |
| 1240 var allProperties = rule.properties; | 1240 var allProperties = rule.properties; |
| 1241 for (var i = 0; i < allProperties.length; ++i) | 1241 for (var i = 0; i < allProperties.length; ++i) |
| 1242 this.visitProperty(styleSheet, rule, allProperties[i], result); | 1242 this.visitProperty(styleSheet, rule, allProperties[i], result); |
| 1243 this.didVisitRule(styleSheet, rule, result); | 1243 this.didVisitRule(styleSheet, rule, result); |
| 1244 } | 1244 } |
| 1245 | 1245 |
| 1246 /** | 1246 /** |
| 1247 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1247 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1248 * @param {!WebInspector.AuditRuleResult} result | 1248 * @param {!Audits.AuditRuleResult} result |
| 1249 */ | 1249 */ |
| 1250 visitStyleSheet(styleSheet, result) { | 1250 visitStyleSheet(styleSheet, result) { |
| 1251 // Subclasses can implement. | 1251 // Subclasses can implement. |
| 1252 } | 1252 } |
| 1253 | 1253 |
| 1254 /** | 1254 /** |
| 1255 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1255 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1256 * @param {!WebInspector.AuditRuleResult} result | 1256 * @param {!Audits.AuditRuleResult} result |
| 1257 */ | 1257 */ |
| 1258 didVisitStyleSheet(styleSheet, result) { | 1258 didVisitStyleSheet(styleSheet, result) { |
| 1259 // Subclasses can implement. | 1259 // Subclasses can implement. |
| 1260 } | 1260 } |
| 1261 | 1261 |
| 1262 /** | 1262 /** |
| 1263 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1263 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1264 * @param {!WebInspector.CSSParser.StyleRule} rule | 1264 * @param {!SDK.CSSParser.StyleRule} rule |
| 1265 * @param {!WebInspector.AuditRuleResult} result | 1265 * @param {!Audits.AuditRuleResult} result |
| 1266 */ | 1266 */ |
| 1267 visitRule(styleSheet, rule, result) { | 1267 visitRule(styleSheet, rule, result) { |
| 1268 // Subclasses can implement. | 1268 // Subclasses can implement. |
| 1269 } | 1269 } |
| 1270 | 1270 |
| 1271 /** | 1271 /** |
| 1272 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1272 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1273 * @param {!WebInspector.CSSParser.StyleRule} rule | 1273 * @param {!SDK.CSSParser.StyleRule} rule |
| 1274 * @param {!WebInspector.AuditRuleResult} result | 1274 * @param {!Audits.AuditRuleResult} result |
| 1275 */ | 1275 */ |
| 1276 didVisitRule(styleSheet, rule, result) { | 1276 didVisitRule(styleSheet, rule, result) { |
| 1277 // Subclasses can implement. | 1277 // Subclasses can implement. |
| 1278 } | 1278 } |
| 1279 | 1279 |
| 1280 /** | 1280 /** |
| 1281 * @param {!WebInspector.AuditRules.ParsedStyleSheet} styleSheet | 1281 * @param {!Audits.AuditRules.ParsedStyleSheet} styleSheet |
| 1282 * @param {!WebInspector.CSSParser.StyleRule} rule | 1282 * @param {!SDK.CSSParser.StyleRule} rule |
| 1283 * @param {!WebInspector.CSSParser.Property} property | 1283 * @param {!SDK.CSSParser.Property} property |
| 1284 * @param {!WebInspector.AuditRuleResult} result | 1284 * @param {!Audits.AuditRuleResult} result |
| 1285 */ | 1285 */ |
| 1286 visitProperty(styleSheet, rule, property, result) { | 1286 visitProperty(styleSheet, rule, property, result) { |
| 1287 // Subclasses can implement. | 1287 // Subclasses can implement. |
| 1288 } | 1288 } |
| 1289 }; | 1289 }; |
| 1290 | 1290 |
| 1291 /** | 1291 /** |
| 1292 * @unrestricted | 1292 * @unrestricted |
| 1293 */ | 1293 */ |
| 1294 WebInspector.AuditRules.CookieRuleBase = class extends WebInspector.AuditRule { | 1294 Audits.AuditRules.CookieRuleBase = class extends Audits.AuditRule { |
| 1295 constructor(id, name) { | 1295 constructor(id, name) { |
| 1296 super(id, name); | 1296 super(id, name); |
| 1297 } | 1297 } |
| 1298 | 1298 |
| 1299 /** | 1299 /** |
| 1300 * @override | 1300 * @override |
| 1301 * @param {!WebInspector.Target} target | 1301 * @param {!SDK.Target} target |
| 1302 * @param {!Array.<!WebInspector.NetworkRequest>} requests | 1302 * @param {!Array.<!SDK.NetworkRequest>} requests |
| 1303 * @param {!WebInspector.AuditRuleResult} result | 1303 * @param {!Audits.AuditRuleResult} result |
| 1304 * @param {function(!WebInspector.AuditRuleResult)} callback | 1304 * @param {function(!Audits.AuditRuleResult)} callback |
| 1305 * @param {!WebInspector.Progress} progress | 1305 * @param {!Common.Progress} progress |
| 1306 */ | 1306 */ |
| 1307 doRun(target, requests, result, callback, progress) { | 1307 doRun(target, requests, result, callback, progress) { |
| 1308 var self = this; | 1308 var self = this; |
| 1309 function resultCallback(receivedCookies) { | 1309 function resultCallback(receivedCookies) { |
| 1310 if (progress.isCanceled()) { | 1310 if (progress.isCanceled()) { |
| 1311 callback(result); | 1311 callback(result); |
| 1312 return; | 1312 return; |
| 1313 } | 1313 } |
| 1314 | 1314 |
| 1315 self.processCookies(receivedCookies, requests, result); | 1315 self.processCookies(receivedCookies, requests, result); |
| 1316 callback(result); | 1316 callback(result); |
| 1317 } | 1317 } |
| 1318 | 1318 |
| 1319 WebInspector.Cookies.getCookiesAsync(resultCallback); | 1319 SDK.Cookies.getCookiesAsync(resultCallback); |
| 1320 } | 1320 } |
| 1321 | 1321 |
| 1322 mapResourceCookies(requestsByDomain, allCookies, callback) { | 1322 mapResourceCookies(requestsByDomain, allCookies, callback) { |
| 1323 for (var i = 0; i < allCookies.length; ++i) { | 1323 for (var i = 0; i < allCookies.length; ++i) { |
| 1324 for (var requestDomain in requestsByDomain) { | 1324 for (var requestDomain in requestsByDomain) { |
| 1325 if (WebInspector.Cookies.cookieDomainMatchesResourceDomain(allCookies[i]
.domain(), requestDomain)) | 1325 if (SDK.Cookies.cookieDomainMatchesResourceDomain(allCookies[i].domain()
, requestDomain)) |
| 1326 this._callbackForResourceCookiePairs(requestsByDomain[requestDomain],
allCookies[i], callback); | 1326 this._callbackForResourceCookiePairs(requestsByDomain[requestDomain],
allCookies[i], callback); |
| 1327 } | 1327 } |
| 1328 } | 1328 } |
| 1329 } | 1329 } |
| 1330 | 1330 |
| 1331 _callbackForResourceCookiePairs(requests, cookie, callback) { | 1331 _callbackForResourceCookiePairs(requests, cookie, callback) { |
| 1332 if (!requests) | 1332 if (!requests) |
| 1333 return; | 1333 return; |
| 1334 for (var i = 0; i < requests.length; ++i) { | 1334 for (var i = 0; i < requests.length; ++i) { |
| 1335 if (WebInspector.Cookies.cookieMatchesResourceURL(cookie, requests[i].url)
) | 1335 if (SDK.Cookies.cookieMatchesResourceURL(cookie, requests[i].url)) |
| 1336 callback(requests[i], cookie); | 1336 callback(requests[i], cookie); |
| 1337 } | 1337 } |
| 1338 } | 1338 } |
| 1339 }; | 1339 }; |
| 1340 | 1340 |
| 1341 /** | 1341 /** |
| 1342 * @unrestricted | 1342 * @unrestricted |
| 1343 */ | 1343 */ |
| 1344 WebInspector.AuditRules.CookieSizeRule = class extends WebInspector.AuditRules.C
ookieRuleBase { | 1344 Audits.AuditRules.CookieSizeRule = class extends Audits.AuditRules.CookieRuleBas
e { |
| 1345 constructor(avgBytesThreshold) { | 1345 constructor(avgBytesThreshold) { |
| 1346 super('http-cookiesize', WebInspector.UIString('Minimize cookie size')); | 1346 super('http-cookiesize', Common.UIString('Minimize cookie size')); |
| 1347 this._avgBytesThreshold = avgBytesThreshold; | 1347 this._avgBytesThreshold = avgBytesThreshold; |
| 1348 this._maxBytesThreshold = 1000; | 1348 this._maxBytesThreshold = 1000; |
| 1349 } | 1349 } |
| 1350 | 1350 |
| 1351 _average(cookieArray) { | 1351 _average(cookieArray) { |
| 1352 var total = 0; | 1352 var total = 0; |
| 1353 for (var i = 0; i < cookieArray.length; ++i) | 1353 for (var i = 0; i < cookieArray.length; ++i) |
| 1354 total += cookieArray[i].size(); | 1354 total += cookieArray[i].size(); |
| 1355 return cookieArray.length ? Math.round(total / cookieArray.length) : 0; | 1355 return cookieArray.length ? Math.round(total / cookieArray.length) : 0; |
| 1356 } | 1356 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1380 cookiesPerResourceDomain[request.parsedURL.host] = cookies; | 1380 cookiesPerResourceDomain[request.parsedURL.host] = cookies; |
| 1381 } | 1381 } |
| 1382 cookies.push(cookie); | 1382 cookies.push(cookie); |
| 1383 } | 1383 } |
| 1384 | 1384 |
| 1385 if (!allCookies.length) | 1385 if (!allCookies.length) |
| 1386 return; | 1386 return; |
| 1387 | 1387 |
| 1388 var sortedCookieSizes = []; | 1388 var sortedCookieSizes = []; |
| 1389 | 1389 |
| 1390 var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(r
equests, null, true); | 1390 var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap(request
s, null, true); |
| 1391 this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback)
; | 1391 this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback)
; |
| 1392 | 1392 |
| 1393 for (var requestDomain in cookiesPerResourceDomain) { | 1393 for (var requestDomain in cookiesPerResourceDomain) { |
| 1394 var cookies = cookiesPerResourceDomain[requestDomain]; | 1394 var cookies = cookiesPerResourceDomain[requestDomain]; |
| 1395 sortedCookieSizes.push( | 1395 sortedCookieSizes.push( |
| 1396 {domain: requestDomain, avgCookieSize: this._average(cookies), maxCook
ieSize: this._max(cookies)}); | 1396 {domain: requestDomain, avgCookieSize: this._average(cookies), maxCook
ieSize: this._max(cookies)}); |
| 1397 } | 1397 } |
| 1398 var avgAllCookiesSize = this._average(allCookies); | 1398 var avgAllCookiesSize = this._average(allCookies); |
| 1399 | 1399 |
| 1400 var hugeCookieDomains = []; | 1400 var hugeCookieDomains = []; |
| 1401 sortedCookieSizes.sort(maxSizeSorter); | 1401 sortedCookieSizes.sort(maxSizeSorter); |
| 1402 | 1402 |
| 1403 for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) { | 1403 for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) { |
| 1404 var maxCookieSize = sortedCookieSizes[i].maxCookieSize; | 1404 var maxCookieSize = sortedCookieSizes[i].maxCookieSize; |
| 1405 if (maxCookieSize > this._maxBytesThreshold) | 1405 if (maxCookieSize > this._maxBytesThreshold) |
| 1406 hugeCookieDomains.push( | 1406 hugeCookieDomains.push( |
| 1407 WebInspector.AuditRuleResult.resourceDomain(sortedCookieSizes[i].dom
ain) + ': ' + | 1407 Audits.AuditRuleResult.resourceDomain(sortedCookieSizes[i].domain) +
': ' + |
| 1408 Number.bytesToString(maxCookieSize)); | 1408 Number.bytesToString(maxCookieSize)); |
| 1409 } | 1409 } |
| 1410 | 1410 |
| 1411 var bigAvgCookieDomains = []; | 1411 var bigAvgCookieDomains = []; |
| 1412 sortedCookieSizes.sort(avgSizeSorter); | 1412 sortedCookieSizes.sort(avgSizeSorter); |
| 1413 for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) { | 1413 for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) { |
| 1414 var domain = sortedCookieSizes[i].domain; | 1414 var domain = sortedCookieSizes[i].domain; |
| 1415 var avgCookieSize = sortedCookieSizes[i].avgCookieSize; | 1415 var avgCookieSize = sortedCookieSizes[i].avgCookieSize; |
| 1416 if (avgCookieSize > this._avgBytesThreshold && avgCookieSize < this._maxBy
tesThreshold) | 1416 if (avgCookieSize > this._avgBytesThreshold && avgCookieSize < this._maxBy
tesThreshold) |
| 1417 bigAvgCookieDomains.push( | 1417 bigAvgCookieDomains.push( |
| 1418 WebInspector.AuditRuleResult.resourceDomain(domain) + ': ' + Number.
bytesToString(avgCookieSize)); | 1418 Audits.AuditRuleResult.resourceDomain(domain) + ': ' + Number.bytesT
oString(avgCookieSize)); |
| 1419 } | 1419 } |
| 1420 result.addChild(WebInspector.UIString( | 1420 result.addChild(Common.UIString( |
| 1421 'The average cookie size for all requests on this page is %s', Number.by
tesToString(avgAllCookiesSize))); | 1421 'The average cookie size for all requests on this page is %s', Number.by
tesToString(avgAllCookiesSize))); |
| 1422 | 1422 |
| 1423 if (hugeCookieDomains.length) { | 1423 if (hugeCookieDomains.length) { |
| 1424 var entry = result.addChild( | 1424 var entry = result.addChild( |
| 1425 WebInspector.UIString( | 1425 Common.UIString( |
| 1426 'The following domains have a cookie size in excess of 1KB. This i
s harmful because requests with cookies larger than 1KB typically cannot fit int
o a single network packet.'), | 1426 'The following domains have a cookie size in excess of 1KB. This i
s harmful because requests with cookies larger than 1KB typically cannot fit int
o a single network packet.'), |
| 1427 true); | 1427 true); |
| 1428 entry.addURLs(hugeCookieDomains); | 1428 entry.addURLs(hugeCookieDomains); |
| 1429 result.violationCount += hugeCookieDomains.length; | 1429 result.violationCount += hugeCookieDomains.length; |
| 1430 } | 1430 } |
| 1431 | 1431 |
| 1432 if (bigAvgCookieDomains.length) { | 1432 if (bigAvgCookieDomains.length) { |
| 1433 var entry = result.addChild( | 1433 var entry = result.addChild( |
| 1434 WebInspector.UIString( | 1434 Common.UIString( |
| 1435 '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 ta
kes to send requests.', | 1435 '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 ta
kes to send requests.', |
| 1436 this._avgBytesThreshold), | 1436 this._avgBytesThreshold), |
| 1437 true); | 1437 true); |
| 1438 entry.addURLs(bigAvgCookieDomains); | 1438 entry.addURLs(bigAvgCookieDomains); |
| 1439 result.violationCount += bigAvgCookieDomains.length; | 1439 result.violationCount += bigAvgCookieDomains.length; |
| 1440 } | 1440 } |
| 1441 } | 1441 } |
| 1442 }; | 1442 }; |
| 1443 | 1443 |
| 1444 /** | 1444 /** |
| 1445 * @unrestricted | 1445 * @unrestricted |
| 1446 */ | 1446 */ |
| 1447 WebInspector.AuditRules.StaticCookielessRule = class extends WebInspector.AuditR
ules.CookieRuleBase { | 1447 Audits.AuditRules.StaticCookielessRule = class extends Audits.AuditRules.CookieR
uleBase { |
| 1448 constructor(minResources) { | 1448 constructor(minResources) { |
| 1449 super('http-staticcookieless', WebInspector.UIString('Serve static content f
rom a cookieless domain')); | 1449 super('http-staticcookieless', Common.UIString('Serve static content from a
cookieless domain')); |
| 1450 this._minResources = minResources; | 1450 this._minResources = minResources; |
| 1451 } | 1451 } |
| 1452 | 1452 |
| 1453 processCookies(allCookies, requests, result) { | 1453 processCookies(allCookies, requests, result) { |
| 1454 var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap( | 1454 var domainToResourcesMap = Audits.AuditRules.getDomainToResourcesMap( |
| 1455 requests, [WebInspector.resourceTypes.Stylesheet, WebInspector.resourceT
ypes.Image], true); | 1455 requests, [Common.resourceTypes.Stylesheet, Common.resourceTypes.Image],
true); |
| 1456 var totalStaticResources = 0; | 1456 var totalStaticResources = 0; |
| 1457 for (var domain in domainToResourcesMap) | 1457 for (var domain in domainToResourcesMap) |
| 1458 totalStaticResources += domainToResourcesMap[domain].length; | 1458 totalStaticResources += domainToResourcesMap[domain].length; |
| 1459 if (totalStaticResources < this._minResources) | 1459 if (totalStaticResources < this._minResources) |
| 1460 return; | 1460 return; |
| 1461 var matchingResourceData = {}; | 1461 var matchingResourceData = {}; |
| 1462 this.mapResourceCookies(domainToResourcesMap, allCookies, this._collectorCal
lback.bind(this, matchingResourceData)); | 1462 this.mapResourceCookies(domainToResourcesMap, allCookies, this._collectorCal
lback.bind(this, matchingResourceData)); |
| 1463 | 1463 |
| 1464 var badUrls = []; | 1464 var badUrls = []; |
| 1465 var cookieBytes = 0; | 1465 var cookieBytes = 0; |
| 1466 for (var url in matchingResourceData) { | 1466 for (var url in matchingResourceData) { |
| 1467 badUrls.push(url); | 1467 badUrls.push(url); |
| 1468 cookieBytes += matchingResourceData[url]; | 1468 cookieBytes += matchingResourceData[url]; |
| 1469 } | 1469 } |
| 1470 if (badUrls.length < this._minResources) | 1470 if (badUrls.length < this._minResources) |
| 1471 return; | 1471 return; |
| 1472 | 1472 |
| 1473 var entry = result.addChild( | 1473 var entry = result.addChild( |
| 1474 WebInspector.UIString( | 1474 Common.UIString( |
| 1475 '%s of cookies were sent with the following static resources. Serve
these static resources from a domain that does not set cookies:', | 1475 '%s of cookies were sent with the following static resources. Serve
these static resources from a domain that does not set cookies:', |
| 1476 Number.bytesToString(cookieBytes)), | 1476 Number.bytesToString(cookieBytes)), |
| 1477 true); | 1477 true); |
| 1478 entry.addURLs(badUrls); | 1478 entry.addURLs(badUrls); |
| 1479 result.violationCount = badUrls.length; | 1479 result.violationCount = badUrls.length; |
| 1480 } | 1480 } |
| 1481 | 1481 |
| 1482 _collectorCallback(matchingResourceData, request, cookie) { | 1482 _collectorCallback(matchingResourceData, request, cookie) { |
| 1483 matchingResourceData[request.url] = (matchingResourceData[request.url] || 0)
+ cookie.size(); | 1483 matchingResourceData[request.url] = (matchingResourceData[request.url] || 0)
+ cookie.size(); |
| 1484 } | 1484 } |
| 1485 }; | 1485 }; |
| OLD | NEW |