749 lines
22 KiB
JavaScript
749 lines
22 KiB
JavaScript
/*
|
|
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
WebInspector.Resource = function(identifier, url)
|
|
{
|
|
this.identifier = identifier;
|
|
this.url = url;
|
|
this._startTime = -1;
|
|
this._endTime = -1;
|
|
this._category = WebInspector.resourceCategories.other;
|
|
this._pendingContentCallbacks = [];
|
|
this._responseHeadersSize = 0;
|
|
}
|
|
|
|
// Keep these in sync with WebCore::InspectorResource::Type
|
|
WebInspector.Resource.Type = {
|
|
Document: 0,
|
|
Stylesheet: 1,
|
|
Image: 2,
|
|
Font: 3,
|
|
Script: 4,
|
|
XHR: 5,
|
|
WebSocket: 7,
|
|
Other: 8,
|
|
|
|
isTextType: function(type)
|
|
{
|
|
return (type === this.Document) || (type === this.Stylesheet) || (type === this.Script) || (type === this.XHR);
|
|
},
|
|
|
|
toUIString: function(type)
|
|
{
|
|
switch (type) {
|
|
case this.Document:
|
|
return WebInspector.UIString("Document");
|
|
case this.Stylesheet:
|
|
return WebInspector.UIString("Stylesheet");
|
|
case this.Image:
|
|
return WebInspector.UIString("Image");
|
|
case this.Font:
|
|
return WebInspector.UIString("Font");
|
|
case this.Script:
|
|
return WebInspector.UIString("Script");
|
|
case this.XHR:
|
|
return WebInspector.UIString("XHR");
|
|
case this.WebSocket:
|
|
return WebInspector.UIString("WebSocket");
|
|
case this.Other:
|
|
default:
|
|
return WebInspector.UIString("Other");
|
|
}
|
|
},
|
|
|
|
// Returns locale-independent string identifier of resource type (primarily for use in extension API).
|
|
// The IDs need to be kept in sync with webInspector.resoureces.Types object in ExtensionAPI.js.
|
|
toString: function(type)
|
|
{
|
|
switch (type) {
|
|
case this.Document:
|
|
return "document";
|
|
case this.Stylesheet:
|
|
return "stylesheet";
|
|
case this.Image:
|
|
return "image";
|
|
case this.Font:
|
|
return "font";
|
|
case this.Script:
|
|
return "script";
|
|
case this.XHR:
|
|
return "xhr";
|
|
case this.WebSocket:
|
|
return "websocket";
|
|
case this.Other:
|
|
default:
|
|
return "other";
|
|
}
|
|
}
|
|
}
|
|
|
|
WebInspector.Resource.prototype = {
|
|
get url()
|
|
{
|
|
return this._url;
|
|
},
|
|
|
|
set url(x)
|
|
{
|
|
if (this._url === x)
|
|
return;
|
|
|
|
this._url = x;
|
|
delete this._parsedQueryParameters;
|
|
|
|
var parsedURL = x.asParsedURL();
|
|
this.domain = parsedURL ? parsedURL.host : "";
|
|
this.path = parsedURL ? parsedURL.path : "";
|
|
this.lastPathComponent = "";
|
|
if (parsedURL && parsedURL.path) {
|
|
// First cut the query params.
|
|
var path = parsedURL.path;
|
|
var indexOfQuery = path.indexOf("?");
|
|
if (indexOfQuery !== -1)
|
|
path = path.substring(0, indexOfQuery);
|
|
|
|
// Then take last path component.
|
|
var lastSlashIndex = path.lastIndexOf("/");
|
|
if (lastSlashIndex !== -1)
|
|
this.lastPathComponent = path.substring(lastSlashIndex + 1);
|
|
}
|
|
this.lastPathComponentLowerCase = this.lastPathComponent.toLowerCase();
|
|
},
|
|
|
|
get documentURL()
|
|
{
|
|
return this._documentURL;
|
|
},
|
|
|
|
set documentURL(x)
|
|
{
|
|
this._documentURL = x;
|
|
},
|
|
|
|
get displayName()
|
|
{
|
|
if (this._displayName)
|
|
return this._displayName;
|
|
this._displayName = this.lastPathComponent;
|
|
if (!this._displayName)
|
|
this._displayName = this.displayDomain;
|
|
if (!this._displayName && this.url)
|
|
this._displayName = this.url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : "");
|
|
if (this._displayName === "/")
|
|
this._displayName = this.url;
|
|
return this._displayName;
|
|
},
|
|
|
|
get displayDomain()
|
|
{
|
|
// WebInspector.Database calls this, so don't access more than this.domain.
|
|
if (this.domain && (!WebInspector.mainResource || (WebInspector.mainResource && this.domain !== WebInspector.mainResource.domain)))
|
|
return this.domain;
|
|
return "";
|
|
},
|
|
|
|
get startTime()
|
|
{
|
|
return this._startTime || -1;
|
|
},
|
|
|
|
set startTime(x)
|
|
{
|
|
this._startTime = x;
|
|
},
|
|
|
|
get responseReceivedTime()
|
|
{
|
|
return this._responseReceivedTime || -1;
|
|
},
|
|
|
|
set responseReceivedTime(x)
|
|
{
|
|
this._responseReceivedTime = x;
|
|
},
|
|
|
|
get endTime()
|
|
{
|
|
return this._endTime || -1;
|
|
},
|
|
|
|
set endTime(x)
|
|
{
|
|
if (this.timing && this.timing.requestTime) {
|
|
// Check against accurate responseReceivedTime.
|
|
this._endTime = Math.max(x, this.responseReceivedTime);
|
|
} else {
|
|
// Prefer endTime since it might be from the network stack.
|
|
this._endTime = x;
|
|
if (this._responseReceivedTime > x)
|
|
this._responseReceivedTime = x;
|
|
}
|
|
},
|
|
|
|
get duration()
|
|
{
|
|
if (this._endTime === -1 || this._startTime === -1)
|
|
return -1;
|
|
return this._endTime - this._startTime;
|
|
},
|
|
|
|
get latency()
|
|
{
|
|
if (this._responseReceivedTime === -1 || this._startTime === -1)
|
|
return -1;
|
|
return this._responseReceivedTime - this._startTime;
|
|
},
|
|
|
|
get receiveDuration()
|
|
{
|
|
if (this._endTime === -1 || this._responseReceivedTime === -1)
|
|
return -1;
|
|
return this._endTime - this._responseReceivedTime;
|
|
},
|
|
|
|
get resourceSize()
|
|
{
|
|
return this._resourceSize || 0;
|
|
},
|
|
|
|
set resourceSize(x)
|
|
{
|
|
this._resourceSize = x;
|
|
},
|
|
|
|
get transferSize()
|
|
{
|
|
if (this.cached)
|
|
return 0;
|
|
if (this.statusCode === 304) // Not modified
|
|
return this._responseHeadersSize;
|
|
// FIXME: We prefer using Content-Length over resourceSize as
|
|
// resourceSize may differ from actual transfer size if platform's
|
|
// network stack performed decoding (e.g. gzip decompression).
|
|
// The Content-Length, though, is expected to come from raw
|
|
// response headers and will reflect actual transfer length.
|
|
// This won't work for chunked content encoding, so fall back to
|
|
// resourceSize when we don't have Content-Length. This still won't
|
|
// work for chunks with non-trivial encodings. We need a way to
|
|
// get actaul transfer size from the network stack.
|
|
var bodySize = Number(this.responseHeaders["Content-Length"] || this.resourceSize);
|
|
return this._responseHeadersSize + bodySize;
|
|
},
|
|
|
|
get expectedContentLength()
|
|
{
|
|
return this._expectedContentLength || 0;
|
|
},
|
|
|
|
set expectedContentLength(x)
|
|
{
|
|
this._expectedContentLength = x;
|
|
},
|
|
|
|
get finished()
|
|
{
|
|
return this._finished;
|
|
},
|
|
|
|
set finished(x)
|
|
{
|
|
if (this._finished === x)
|
|
return;
|
|
|
|
this._finished = x;
|
|
|
|
if (x) {
|
|
this._checkWarnings();
|
|
this.dispatchEventToListeners("finished");
|
|
if (this._pendingContentCallbacks.length)
|
|
this._innerRequestContent();
|
|
}
|
|
},
|
|
|
|
get failed()
|
|
{
|
|
return this._failed;
|
|
},
|
|
|
|
set failed(x)
|
|
{
|
|
this._failed = x;
|
|
},
|
|
|
|
get category()
|
|
{
|
|
return this._category;
|
|
},
|
|
|
|
set category(x)
|
|
{
|
|
this._category = x;
|
|
},
|
|
|
|
get cached()
|
|
{
|
|
return this._cached;
|
|
},
|
|
|
|
set cached(x)
|
|
{
|
|
this._cached = x;
|
|
if (x)
|
|
delete this._timing;
|
|
},
|
|
|
|
get timing()
|
|
{
|
|
return this._timing;
|
|
},
|
|
|
|
set timing(x)
|
|
{
|
|
if (x && !this._cached) {
|
|
// Take startTime and responseReceivedTime from timing data for better accuracy.
|
|
// Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis.
|
|
this._startTime = x.requestTime;
|
|
this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0;
|
|
|
|
this._timing = x;
|
|
this.dispatchEventToListeners("timing changed");
|
|
}
|
|
},
|
|
|
|
get mimeType()
|
|
{
|
|
return this._mimeType;
|
|
},
|
|
|
|
set mimeType(x)
|
|
{
|
|
this._mimeType = x;
|
|
},
|
|
|
|
get type()
|
|
{
|
|
return this._type;
|
|
},
|
|
|
|
set type(x)
|
|
{
|
|
if (this._type === x)
|
|
return;
|
|
|
|
this._type = x;
|
|
|
|
switch (x) {
|
|
case WebInspector.Resource.Type.Document:
|
|
this.category = WebInspector.resourceCategories.documents;
|
|
break;
|
|
case WebInspector.Resource.Type.Stylesheet:
|
|
this.category = WebInspector.resourceCategories.stylesheets;
|
|
break;
|
|
case WebInspector.Resource.Type.Script:
|
|
this.category = WebInspector.resourceCategories.scripts;
|
|
break;
|
|
case WebInspector.Resource.Type.Image:
|
|
this.category = WebInspector.resourceCategories.images;
|
|
break;
|
|
case WebInspector.Resource.Type.Font:
|
|
this.category = WebInspector.resourceCategories.fonts;
|
|
break;
|
|
case WebInspector.Resource.Type.XHR:
|
|
this.category = WebInspector.resourceCategories.xhr;
|
|
break;
|
|
case WebInspector.Resource.Type.WebSocket:
|
|
this.category = WebInspector.resourceCategories.websockets;
|
|
break;
|
|
case WebInspector.Resource.Type.Other:
|
|
default:
|
|
this.category = WebInspector.resourceCategories.other;
|
|
break;
|
|
}
|
|
},
|
|
|
|
get requestHeaders()
|
|
{
|
|
return this._requestHeaders || {};
|
|
},
|
|
|
|
set requestHeaders(x)
|
|
{
|
|
this._requestHeaders = x;
|
|
delete this._sortedRequestHeaders;
|
|
delete this._requestCookies;
|
|
|
|
this.dispatchEventToListeners("requestHeaders changed");
|
|
},
|
|
|
|
get sortedRequestHeaders()
|
|
{
|
|
if (this._sortedRequestHeaders !== undefined)
|
|
return this._sortedRequestHeaders;
|
|
|
|
this._sortedRequestHeaders = [];
|
|
for (var key in this.requestHeaders)
|
|
this._sortedRequestHeaders.push({header: key, value: this.requestHeaders[key]});
|
|
this._sortedRequestHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
|
|
|
|
return this._sortedRequestHeaders;
|
|
},
|
|
|
|
requestHeaderValue: function(headerName)
|
|
{
|
|
return this._headerValue(this.requestHeaders, headerName);
|
|
},
|
|
|
|
get requestCookies()
|
|
{
|
|
if (!this._requestCookies)
|
|
this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie"));
|
|
return this._requestCookies;
|
|
},
|
|
|
|
get requestFormData()
|
|
{
|
|
return this._requestFormData;
|
|
},
|
|
|
|
set requestFormData(x)
|
|
{
|
|
this._requestFormData = x;
|
|
delete this._parsedFormParameters;
|
|
},
|
|
|
|
get responseHeaders()
|
|
{
|
|
return this._responseHeaders || {};
|
|
},
|
|
|
|
set responseHeaders(x)
|
|
{
|
|
this._responseHeaders = x;
|
|
// FIXME: we should take actual headers size from network stack, when possible.
|
|
this._responseHeadersSize = this._headersSize(x);
|
|
delete this._sortedResponseHeaders;
|
|
delete this._responseCookies;
|
|
|
|
this.dispatchEventToListeners("responseHeaders changed");
|
|
},
|
|
|
|
get sortedResponseHeaders()
|
|
{
|
|
if (this._sortedResponseHeaders !== undefined)
|
|
return this._sortedResponseHeaders;
|
|
|
|
this._sortedResponseHeaders = [];
|
|
for (var key in this.responseHeaders)
|
|
this._sortedResponseHeaders.push({header: key, value: this.responseHeaders[key]});
|
|
this._sortedResponseHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
|
|
|
|
return this._sortedResponseHeaders;
|
|
},
|
|
|
|
responseHeaderValue: function(headerName)
|
|
{
|
|
return this._headerValue(this.responseHeaders, headerName);
|
|
},
|
|
|
|
get responseCookies()
|
|
{
|
|
if (!this._responseCookies)
|
|
this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie"));
|
|
return this._responseCookies;
|
|
},
|
|
|
|
get queryParameters()
|
|
{
|
|
if (this._parsedQueryParameters)
|
|
return this._parsedQueryParameters;
|
|
var queryString = this.url.split("?", 2)[1];
|
|
if (!queryString)
|
|
return;
|
|
this._parsedQueryParameters = this._parseParameters(queryString);
|
|
return this._parsedQueryParameters;
|
|
},
|
|
|
|
get formParameters()
|
|
{
|
|
if (this._parsedFormParameters)
|
|
return this._parsedFormParameters;
|
|
if (!this.requestFormData)
|
|
return;
|
|
var requestContentType = this.requestHeaderValue("Content-Type");
|
|
if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i))
|
|
return;
|
|
this._parsedFormParameters = this._parseParameters(this.requestFormData);
|
|
return this._parsedFormParameters;
|
|
},
|
|
|
|
_parseParameters: function(queryString)
|
|
{
|
|
function parseNameValue(pair)
|
|
{
|
|
var parameter = {};
|
|
var splitPair = pair.split("=", 2);
|
|
|
|
parameter.name = splitPair[0];
|
|
if (splitPair.length === 1)
|
|
parameter.value = "";
|
|
else
|
|
parameter.value = splitPair[1];
|
|
return parameter;
|
|
}
|
|
return queryString.split("&").map(parseNameValue);
|
|
},
|
|
|
|
_headerValue: function(headers, headerName)
|
|
{
|
|
headerName = headerName.toLowerCase();
|
|
for (var header in headers) {
|
|
if (header.toLowerCase() === headerName)
|
|
return headers[header];
|
|
}
|
|
},
|
|
|
|
_headersSize: function(headers)
|
|
{
|
|
var size = 0;
|
|
for (var header in headers)
|
|
size += header.length + headers[header].length + 3; // _typical_ overhead per herader is ": ".length + "\n".length.
|
|
return size;
|
|
},
|
|
|
|
get errors()
|
|
{
|
|
return this._errors || 0;
|
|
},
|
|
|
|
set errors(x)
|
|
{
|
|
this._errors = x;
|
|
this.dispatchEventToListeners("errors-warnings-updated");
|
|
},
|
|
|
|
get warnings()
|
|
{
|
|
return this._warnings || 0;
|
|
},
|
|
|
|
set warnings(x)
|
|
{
|
|
this._warnings = x;
|
|
this.dispatchEventToListeners("errors-warnings-updated");
|
|
},
|
|
|
|
clearErrorsAndWarnings: function()
|
|
{
|
|
this._warnings = 0;
|
|
this._errors = 0;
|
|
this.dispatchEventToListeners("errors-warnings-updated");
|
|
},
|
|
|
|
_mimeTypeIsConsistentWithType: function()
|
|
{
|
|
// If status is an error, content is likely to be of an inconsistent type,
|
|
// as it's going to be an error message. We do not want to emit a warning
|
|
// for this, though, as this will already be reported as resource loading failure.
|
|
if (this.statusCode >= 400)
|
|
return true;
|
|
|
|
if (typeof this.type === "undefined"
|
|
|| this.type === WebInspector.Resource.Type.Other
|
|
|| this.type === WebInspector.Resource.Type.XHR
|
|
|| this.type === WebInspector.Resource.Type.WebSocket)
|
|
return true;
|
|
|
|
if (!this.mimeType)
|
|
return true; // Might be not known for cached resources with null responses.
|
|
|
|
if (this.mimeType in WebInspector.MIMETypes)
|
|
return this.type in WebInspector.MIMETypes[this.mimeType];
|
|
|
|
return false;
|
|
},
|
|
|
|
_checkWarnings: function()
|
|
{
|
|
for (var warning in WebInspector.Warnings)
|
|
this._checkWarning(WebInspector.Warnings[warning]);
|
|
},
|
|
|
|
_checkWarning: function(warning)
|
|
{
|
|
var msg;
|
|
switch (warning.id) {
|
|
case WebInspector.Warnings.IncorrectMIMEType.id:
|
|
if (!this._mimeTypeIsConsistentWithType())
|
|
msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other,
|
|
WebInspector.ConsoleMessage.MessageType.Log,
|
|
WebInspector.ConsoleMessage.MessageLevel.Warning,
|
|
-1,
|
|
this.url,
|
|
1,
|
|
String.sprintf(WebInspector.Warnings.IncorrectMIMEType.message, WebInspector.Resource.Type.toUIString(this.type), this.mimeType),
|
|
null,
|
|
null);
|
|
break;
|
|
}
|
|
|
|
if (msg)
|
|
WebInspector.console.addMessage(msg);
|
|
},
|
|
|
|
get content()
|
|
{
|
|
return this._content;
|
|
},
|
|
|
|
get contentTimestamp()
|
|
{
|
|
return this._contentTimestamp;
|
|
},
|
|
|
|
setInitialContent: function(content)
|
|
{
|
|
this._content = content;
|
|
},
|
|
|
|
isLocallyModified: function()
|
|
{
|
|
return !!this._baseRevision;
|
|
},
|
|
|
|
setContent: function(newContent, onRevert)
|
|
{
|
|
var revisionResource = new WebInspector.Resource(null, this.url);
|
|
revisionResource.type = this.type;
|
|
revisionResource.loader = this.loader;
|
|
revisionResource.timestamp = this.timestamp;
|
|
revisionResource._content = this._content;
|
|
revisionResource._actualResource = this;
|
|
revisionResource._fireOnRevert = onRevert;
|
|
|
|
if (this.finished)
|
|
revisionResource.finished = true;
|
|
else {
|
|
function finished()
|
|
{
|
|
this.removeEventListener("finished", finished);
|
|
revisionResource.finished = true;
|
|
}
|
|
this.addEventListener("finished", finished.bind(this));
|
|
}
|
|
|
|
if (!this._baseRevision)
|
|
this._baseRevision = revisionResource;
|
|
else
|
|
revisionResource._baseRevision = this._baseRevision;
|
|
|
|
var data = { revision: revisionResource };
|
|
this._content = newContent;
|
|
this.timestamp = new Date();
|
|
this.dispatchEventToListeners("content-changed", data);
|
|
},
|
|
|
|
revertToThis: function()
|
|
{
|
|
if (!this._actualResource || !this._fireOnRevert)
|
|
return;
|
|
|
|
function callback(content)
|
|
{
|
|
if (content)
|
|
this._fireOnRevert(content);
|
|
}
|
|
this.requestContent(callback.bind(this));
|
|
},
|
|
|
|
get baseRevision()
|
|
{
|
|
return this._baseRevision;
|
|
},
|
|
|
|
requestContent: function(callback)
|
|
{
|
|
// We do not support content retrieval for WebSockets at the moment.
|
|
// Since WebSockets are potentially long-living, fail requests immediately
|
|
// to prevent caller blocking until resource is marked as finished.
|
|
if (this.type === WebInspector.Resource.Type.WebSocket) {
|
|
callback(null, null);
|
|
return;
|
|
}
|
|
if (typeof this._content !== "undefined") {
|
|
callback(this.content, this._contentEncoded);
|
|
return;
|
|
}
|
|
this._pendingContentCallbacks.push(callback);
|
|
if (this.finished)
|
|
this._innerRequestContent();
|
|
},
|
|
|
|
populateImageSource: function(image)
|
|
{
|
|
function onResourceContent()
|
|
{
|
|
image.src = this._contentURL();
|
|
}
|
|
|
|
if (Preferences.useDataURLForResourceImageIcons)
|
|
this.requestContent(onResourceContent.bind(this));
|
|
else
|
|
image.src = this.url;
|
|
},
|
|
|
|
_contentURL: function()
|
|
{
|
|
var maxDataUrlSize = 1024 * 1024;
|
|
// If resource content is not available or won't fit a data URL, fall back to using original URL.
|
|
if (this._content == null || this._content.length > maxDataUrlSize)
|
|
return this.url;
|
|
|
|
return "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content;
|
|
},
|
|
|
|
_innerRequestContent: function()
|
|
{
|
|
if (this._contentRequested)
|
|
return;
|
|
this._contentRequested = true;
|
|
this._contentEncoded = !WebInspector.Resource.Type.isTextType(this.type);
|
|
|
|
function onResourceContent(data)
|
|
{
|
|
this._content = data;
|
|
var callbacks = this._pendingContentCallbacks.slice();
|
|
for (var i = 0; i < callbacks.length; ++i)
|
|
callbacks[i](this._content, this._contentEncoded);
|
|
this._pendingContentCallbacks.length = 0;
|
|
delete this._contentRequested;
|
|
}
|
|
WebInspector.networkManager.requestContent(this, this._contentEncoded, onResourceContent.bind(this));
|
|
}
|
|
}
|
|
|
|
WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
|