1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @constructor 31 * @extends {WebInspector.Object} 32 * @implements {WebInspector.ContentProvider} 33 * @param {?WebInspector.NetworkRequest} request 34 * @param {string} url 35 * @param {string} documentURL 36 * @param {NetworkAgent.FrameId} frameId 37 * @param {NetworkAgent.LoaderId} loaderId 38 * @param {WebInspector.ResourceType} type 39 * @param {string} mimeType 40 * @param {boolean=} isHidden 41 */ 42 WebInspector.Resource = function(request, url, documentURL, frameId, loaderId, type, mimeType, isHidden) 43 { 44 this._request = request; 45 this.url = url; 46 this._documentURL = documentURL; 47 this._frameId = frameId; 48 this._loaderId = loaderId; 49 this._type = type || WebInspector.resourceTypes.Other; 50 this._mimeType = mimeType; 51 this._isHidden = isHidden; 52 53 /** @type {?string} */ this._content; 54 /** @type {boolean} */ this._contentEncoded; 55 this._pendingContentCallbacks = []; 56 if (this._request && !this._request.finished) 57 this._request.addEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this); 58 } 59 60 WebInspector.Resource.Events = { 61 MessageAdded: "message-added", 62 MessagesCleared: "messages-cleared", 63 } 64 65 WebInspector.Resource.prototype = { 66 /** 67 * @return {?WebInspector.NetworkRequest} 68 */ 69 get request() 70 { 71 return this._request; 72 }, 73 74 /** 75 * @return {string} 76 */ 77 get url() 78 { 79 return this._url; 80 }, 81 82 set url(x) 83 { 84 this._url = x; 85 this._parsedURL = new WebInspector.ParsedURL(x); 86 }, 87 88 get parsedURL() 89 { 90 return this._parsedURL; 91 }, 92 93 /** 94 * @return {string} 95 */ 96 get documentURL() 97 { 98 return this._documentURL; 99 }, 100 101 /** 102 * @return {NetworkAgent.FrameId} 103 */ 104 get frameId() 105 { 106 return this._frameId; 107 }, 108 109 /** 110 * @return {NetworkAgent.LoaderId} 111 */ 112 get loaderId() 113 { 114 return this._loaderId; 115 }, 116 117 /** 118 * @return {string} 119 */ 120 get displayName() 121 { 122 return this._parsedURL.displayName; 123 }, 124 125 /** 126 * @return {WebInspector.ResourceType} 127 */ 128 get type() 129 { 130 return this._request ? this._request.type : this._type; 131 }, 132 133 /** 134 * @return {string} 135 */ 136 get mimeType() 137 { 138 return this._request ? this._request.mimeType : this._mimeType; 139 }, 140 141 /** 142 * @return {Array.<WebInspector.ConsoleMessage>} 143 */ 144 get messages() 145 { 146 return this._messages || []; 147 }, 148 149 /** 150 * @param {WebInspector.ConsoleMessage} msg 151 */ 152 addMessage: function(msg) 153 { 154 if (!msg.isErrorOrWarning() || !msg.message) 155 return; 156 157 if (!this._messages) 158 this._messages = []; 159 this._messages.push(msg); 160 this.dispatchEventToListeners(WebInspector.Resource.Events.MessageAdded, msg); 161 }, 162 163 /** 164 * @return {number} 165 */ 166 get errors() 167 { 168 return this._errors || 0; 169 }, 170 171 set errors(x) 172 { 173 this._errors = x; 174 }, 175 176 /** 177 * @return {number} 178 */ 179 get warnings() 180 { 181 return this._warnings || 0; 182 }, 183 184 set warnings(x) 185 { 186 this._warnings = x; 187 }, 188 189 clearErrorsAndWarnings: function() 190 { 191 this._messages = []; 192 this._warnings = 0; 193 this._errors = 0; 194 this.dispatchEventToListeners(WebInspector.Resource.Events.MessagesCleared); 195 }, 196 197 /** 198 * @return {?string} 199 */ 200 get content() 201 { 202 return this._content; 203 }, 204 205 /** 206 * @return {boolean} 207 */ 208 get contentEncoded() 209 { 210 return this._contentEncoded; 211 }, 212 213 /** 214 * @return {string} 215 */ 216 contentURL: function() 217 { 218 return this._url; 219 }, 220 221 /** 222 * @return {WebInspector.ResourceType} 223 */ 224 contentType: function() 225 { 226 return this.type; 227 }, 228 229 /** 230 * @param {function(?string, boolean, string)} callback 231 */ 232 requestContent: function(callback) 233 { 234 if (typeof this._content !== "undefined") { 235 callback(this._content, !!this._contentEncoded, this.canonicalMimeType()); 236 return; 237 } 238 239 this._pendingContentCallbacks.push(callback); 240 if (!this._request || this._request.finished) 241 this._innerRequestContent(); 242 }, 243 244 canonicalMimeType: function() 245 { 246 return this.type.canonicalMimeType() || this.mimeType; 247 }, 248 249 /** 250 * @param {string} query 251 * @param {boolean} caseSensitive 252 * @param {boolean} isRegex 253 * @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback 254 */ 255 searchInContent: function(query, caseSensitive, isRegex, callback) 256 { 257 /** 258 * @param {?Protocol.Error} error 259 * @param {Array.<PageAgent.SearchMatch>} searchMatches 260 */ 261 function callbackWrapper(error, searchMatches) 262 { 263 callback(searchMatches || []); 264 } 265 266 if (this.type === WebInspector.resourceTypes.Document) { 267 /** 268 * @param {?string} content 269 * @param {boolean} contentEncoded 270 * @param {string} mimeType 271 */ 272 function documentContentLoaded(content, contentEncoded, mimeType) 273 { 274 if (content === null) { 275 callback([]); 276 return; 277 } 278 279 var result = WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex); 280 callback(result); 281 } 282 283 this.requestContent(documentContentLoaded); 284 return; 285 } 286 287 if (this.frameId) 288 PageAgent.searchInResource(this.frameId, this.url, query, caseSensitive, isRegex, callbackWrapper); 289 else 290 callback([]); 291 }, 292 293 /** 294 * @param {Element} image 295 */ 296 populateImageSource: function(image) 297 { 298 function onResourceContent() 299 { 300 var imageSrc = WebInspector.contentAsDataURL(this._content, this.mimeType, this._contentEncoded); 301 if (imageSrc === null) 302 imageSrc = this.url; 303 image.src = imageSrc; 304 } 305 306 this.requestContent(onResourceContent.bind(this)); 307 }, 308 309 _requestFinished: function() 310 { 311 this._request.removeEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this); 312 if (this._pendingContentCallbacks.length) 313 this._innerRequestContent(); 314 }, 315 316 317 _innerRequestContent: function() 318 { 319 if (this._contentRequested) 320 return; 321 this._contentRequested = true; 322 323 /** 324 * @param {?Protocol.Error} error 325 * @param {?string} content 326 * @param {boolean} contentEncoded 327 */ 328 function contentLoaded(error, content, contentEncoded) 329 { 330 if (error || content === null) { 331 loadFallbackContent.call(this, error); 332 return; 333 } 334 replyWithContent.call(this, content, contentEncoded); 335 } 336 337 /** 338 * @param {?string} content 339 * @param {boolean} contentEncoded 340 */ 341 function replyWithContent(content, contentEncoded) 342 { 343 this._content = content; 344 this._contentEncoded = contentEncoded; 345 var callbacks = this._pendingContentCallbacks.slice(); 346 for (var i = 0; i < callbacks.length; ++i) 347 callbacks[i](this._content, this._contentEncoded, this.canonicalMimeType()); 348 this._pendingContentCallbacks.length = 0; 349 delete this._contentRequested; 350 } 351 352 /** 353 * @param {?Protocol.Error} error 354 * @param {string} content 355 * @param {boolean} contentEncoded 356 */ 357 function resourceContentLoaded(error, content, contentEncoded) 358 { 359 contentLoaded.call(this, error, content, contentEncoded); 360 } 361 362 /** 363 * @param {?Protocol.Error} error 364 */ 365 function loadFallbackContent(error) 366 { 367 var scripts = WebInspector.debuggerModel.scriptsForSourceURL(this.url); 368 if (!scripts.length) { 369 console.error("Resource content request failed: " + error); 370 replyWithContent.call(this, null, false); 371 return; 372 } 373 374 var contentProvider; 375 if (this.type === WebInspector.resourceTypes.Document) 376 contentProvider = new WebInspector.ConcatenatedScriptsContentProvider(scripts); 377 else if (this.type === WebInspector.resourceTypes.Script) 378 contentProvider = scripts[0]; 379 380 if (!contentProvider) { 381 console.error("Resource content request failed: " + error); 382 replyWithContent.call(this, null, false); 383 return; 384 } 385 386 contentProvider.requestContent(fallbackContentLoaded.bind(this)); 387 } 388 389 /** 390 * @param {?string} content 391 * @param {boolean} contentEncoded 392 * @param {string} mimeType 393 */ 394 function fallbackContentLoaded(content, contentEncoded, mimeType) 395 { 396 replyWithContent.call(this, content, contentEncoded); 397 } 398 399 if (this.request) { 400 /** 401 * @param {?string} content 402 * @param {boolean} contentEncoded 403 * @param {string} mimeType 404 */ 405 function requestContentLoaded(content, contentEncoded, mimeType) 406 { 407 contentLoaded.call(this, null, content, contentEncoded); 408 } 409 410 this.request.requestContent(requestContentLoaded.bind(this)); 411 return; 412 } 413 PageAgent.getResourceContent(this.frameId, this.url, resourceContentLoaded.bind(this)); 414 }, 415 416 /** 417 * @return {boolean} 418 */ 419 isHidden: function() 420 { 421 return !!this._isHidden; 422 }, 423 424 __proto__: WebInspector.Object.prototype 425 } 426 427