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.SDKObject} 32 * @implements {WebInspector.ContentProvider} 33 * @param {!WebInspector.Target} target 34 * @param {?WebInspector.NetworkRequest} request 35 * @param {string} url 36 * @param {string} documentURL 37 * @param {!PageAgent.FrameId} frameId 38 * @param {!NetworkAgent.LoaderId} loaderId 39 * @param {!WebInspector.ResourceType} type 40 * @param {string} mimeType 41 * @param {boolean=} isHidden 42 */ 43 WebInspector.Resource = function(target, request, url, documentURL, frameId, loaderId, type, mimeType, isHidden) 44 { 45 WebInspector.SDKObject.call(this, target); 46 this._request = request; 47 this.url = url; 48 this._documentURL = documentURL; 49 this._frameId = frameId; 50 this._loaderId = loaderId; 51 this._type = type || WebInspector.resourceTypes.Other; 52 this._mimeType = mimeType; 53 this._isHidden = isHidden; 54 55 /** @type {?string} */ this._content; 56 /** @type {boolean} */ this._contentEncoded; 57 this._pendingContentCallbacks = []; 58 if (this._request && !this._request.finished) 59 this._request.addEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this); 60 } 61 62 WebInspector.Resource.Events = { 63 MessageAdded: "message-added", 64 MessagesCleared: "messages-cleared", 65 } 66 67 /** 68 * @param {?string} content 69 * @param {string} mimeType 70 * @param {boolean} contentEncoded 71 * @return {?string} 72 */ 73 WebInspector.Resource.contentAsDataURL = function(content, mimeType, contentEncoded) 74 { 75 const maxDataUrlSize = 1024 * 1024; 76 if (content === null || content.length > maxDataUrlSize) 77 return null; 78 79 return "data:" + mimeType + (contentEncoded ? ";base64," : ",") + content; 80 } 81 82 WebInspector.Resource.prototype = { 83 /** 84 * @return {?WebInspector.NetworkRequest} 85 */ 86 get request() 87 { 88 return this._request; 89 }, 90 91 /** 92 * @return {string} 93 */ 94 get url() 95 { 96 return this._url; 97 }, 98 99 set url(x) 100 { 101 this._url = x; 102 this._parsedURL = new WebInspector.ParsedURL(x); 103 }, 104 105 get parsedURL() 106 { 107 return this._parsedURL; 108 }, 109 110 /** 111 * @return {string} 112 */ 113 get documentURL() 114 { 115 return this._documentURL; 116 }, 117 118 /** 119 * @return {!PageAgent.FrameId} 120 */ 121 get frameId() 122 { 123 return this._frameId; 124 }, 125 126 /** 127 * @return {!NetworkAgent.LoaderId} 128 */ 129 get loaderId() 130 { 131 return this._loaderId; 132 }, 133 134 /** 135 * @return {string} 136 */ 137 get displayName() 138 { 139 return this._parsedURL.displayName; 140 }, 141 142 /** 143 * @return {!WebInspector.ResourceType} 144 */ 145 get type() 146 { 147 return this._request ? this._request.type : this._type; 148 }, 149 150 /** 151 * @return {string} 152 */ 153 get mimeType() 154 { 155 return this._request ? this._request.mimeType : this._mimeType; 156 }, 157 158 /** 159 * @return {!Array.<!WebInspector.ConsoleMessage>} 160 */ 161 get messages() 162 { 163 return this._messages || []; 164 }, 165 166 /** 167 * @param {!WebInspector.ConsoleMessage} msg 168 */ 169 addMessage: function(msg) 170 { 171 if (!msg.isErrorOrWarning() || !msg.messageText) 172 return; 173 174 if (!this._messages) 175 this._messages = []; 176 this._messages.push(msg); 177 this.dispatchEventToListeners(WebInspector.Resource.Events.MessageAdded, msg); 178 }, 179 180 /** 181 * @return {number} 182 */ 183 get errors() 184 { 185 return this._errors || 0; 186 }, 187 188 set errors(x) 189 { 190 this._errors = x; 191 }, 192 193 /** 194 * @return {number} 195 */ 196 get warnings() 197 { 198 return this._warnings || 0; 199 }, 200 201 set warnings(x) 202 { 203 this._warnings = x; 204 }, 205 206 clearErrorsAndWarnings: function() 207 { 208 this._messages = []; 209 this._warnings = 0; 210 this._errors = 0; 211 this.dispatchEventToListeners(WebInspector.Resource.Events.MessagesCleared); 212 }, 213 214 /** 215 * @return {?string} 216 */ 217 get content() 218 { 219 return this._content; 220 }, 221 222 /** 223 * @return {boolean} 224 */ 225 get contentEncoded() 226 { 227 return this._contentEncoded; 228 }, 229 230 /** 231 * @return {string} 232 */ 233 contentURL: function() 234 { 235 return this._url; 236 }, 237 238 /** 239 * @return {!WebInspector.ResourceType} 240 */ 241 contentType: function() 242 { 243 return this.type; 244 }, 245 246 /** 247 * @param {function(?string)} callback 248 */ 249 requestContent: function(callback) 250 { 251 if (typeof this._content !== "undefined") { 252 callback(this._content); 253 return; 254 } 255 256 this._pendingContentCallbacks.push(callback); 257 if (!this._request || this._request.finished) 258 this._innerRequestContent(); 259 }, 260 261 /** 262 * @return {string} 263 */ 264 canonicalMimeType: function() 265 { 266 return this.type.canonicalMimeType() || this.mimeType; 267 }, 268 269 /** 270 * @param {string} query 271 * @param {boolean} caseSensitive 272 * @param {boolean} isRegex 273 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 274 */ 275 searchInContent: function(query, caseSensitive, isRegex, callback) 276 { 277 /** 278 * @param {?Protocol.Error} error 279 * @param {!Array.<!PageAgent.SearchMatch>} searchMatches 280 */ 281 function callbackWrapper(error, searchMatches) 282 { 283 callback(searchMatches || []); 284 } 285 286 if (this.type === WebInspector.resourceTypes.Document) { 287 callback([]); 288 return; 289 } 290 291 if (this.frameId) 292 this.target().pageAgent().searchInResource(this.frameId, this.url, query, caseSensitive, isRegex, callbackWrapper); 293 else 294 callback([]); 295 }, 296 297 /** 298 * @param {!Element} image 299 */ 300 populateImageSource: function(image) 301 { 302 /** 303 * @param {?string} content 304 * @this {WebInspector.Resource} 305 */ 306 function onResourceContent(content) 307 { 308 var imageSrc = WebInspector.Resource.contentAsDataURL(this._content, this.mimeType, this._contentEncoded); 309 if (imageSrc === null) 310 imageSrc = this.url; 311 image.src = imageSrc; 312 } 313 314 this.requestContent(onResourceContent.bind(this)); 315 }, 316 317 _requestFinished: function() 318 { 319 this._request.removeEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this); 320 if (this._pendingContentCallbacks.length) 321 this._innerRequestContent(); 322 }, 323 324 325 _innerRequestContent: function() 326 { 327 if (this._contentRequested) 328 return; 329 this._contentRequested = true; 330 331 /** 332 * @param {?Protocol.Error} error 333 * @param {?string} content 334 * @param {boolean} contentEncoded 335 * @this {WebInspector.Resource} 336 */ 337 function contentLoaded(error, content, contentEncoded) 338 { 339 if (error || content === null) { 340 replyWithContent.call(this, null, false); 341 return; 342 } 343 replyWithContent.call(this, content, contentEncoded); 344 } 345 346 /** 347 * @param {?string} content 348 * @param {boolean} contentEncoded 349 * @this {WebInspector.Resource} 350 */ 351 function replyWithContent(content, contentEncoded) 352 { 353 this._content = content; 354 this._contentEncoded = contentEncoded; 355 var callbacks = this._pendingContentCallbacks.slice(); 356 for (var i = 0; i < callbacks.length; ++i) 357 callbacks[i](this._content); 358 this._pendingContentCallbacks.length = 0; 359 delete this._contentRequested; 360 } 361 362 /** 363 * @param {?Protocol.Error} error 364 * @param {string} content 365 * @param {boolean} contentEncoded 366 * @this {WebInspector.Resource} 367 */ 368 function resourceContentLoaded(error, content, contentEncoded) 369 { 370 contentLoaded.call(this, error, content, contentEncoded); 371 } 372 373 if (this.request) { 374 this.request.requestContent(requestContentLoaded.bind(this)); 375 return; 376 } 377 378 /** 379 * @param {?string} content 380 * @this {WebInspector.Resource} 381 */ 382 function requestContentLoaded(content) 383 { 384 contentLoaded.call(this, null, content, this.request.contentEncoded); 385 } 386 387 this.target().pageAgent().getResourceContent(this.frameId, this.url, resourceContentLoaded.bind(this)); 388 }, 389 390 /** 391 * @return {boolean} 392 */ 393 isHidden: function() 394 { 395 return !!this._isHidden; 396 }, 397 398 __proto__: WebInspector.SDKObject.prototype 399 } 400 401