blob: 241b415e7a2b50a5a0977a37730e87c1c8115c8a [file] [log] [blame]
/*
* 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.
*/
/**
* @constructor
* @extends {WebInspector.Object}
* @implements {WebInspector.ContentProvider}
* @param {?WebInspector.NetworkRequest} request
* @param {string} url
* @param {string} documentURL
* @param {NetworkAgent.FrameId} frameId
* @param {NetworkAgent.LoaderId} loaderId
* @param {WebInspector.ResourceType} type
* @param {string} mimeType
* @param {boolean=} isHidden
*/
WebInspector.Resource = function(request, url, documentURL, frameId, loaderId, type, mimeType, isHidden)
{
this._request = request;
this.url = url;
this._documentURL = documentURL;
this._frameId = frameId;
this._loaderId = loaderId;
this._type = type || WebInspector.resourceTypes.Other;
this._mimeType = mimeType;
this.history = [];
this._isHidden = isHidden;
/** @type {?string} */ this._content;
/** @type {boolean} */ this._contentEncoded;
this._pendingContentCallbacks = [];
if (this._request && !this._request.finished)
this._request.addEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this);
}
WebInspector.Resource._resourceRevisionRegistry = function()
{
if (!WebInspector.Resource._resourceRevisionRegistryObject) {
if (window.localStorage) {
var resourceHistory = window.localStorage["resource-history"];
try {
WebInspector.Resource._resourceRevisionRegistryObject = resourceHistory ? JSON.parse(resourceHistory) : {};
} catch (e) {
WebInspector.Resource._resourceRevisionRegistryObject = {};
}
} else
WebInspector.Resource._resourceRevisionRegistryObject = {};
}
return WebInspector.Resource._resourceRevisionRegistryObject;
}
WebInspector.Resource.restoreRevisions = function()
{
var registry = WebInspector.Resource._resourceRevisionRegistry();
var filteredRegistry = {};
for (var url in registry) {
var historyItems = registry[url];
var resource = WebInspector.resourceForURL(url);
var filteredHistoryItems = [];
for (var i = 0; historyItems && i < historyItems.length; ++i) {
var historyItem = historyItems[i];
if (resource && historyItem.loaderId === resource.loaderId) {
resource.addRevision(window.localStorage[historyItem.key], new Date(historyItem.timestamp), true);
filteredHistoryItems.push(historyItem);
filteredRegistry[url] = filteredHistoryItems;
} else
delete window.localStorage[historyItem.key];
}
}
WebInspector.Resource._resourceRevisionRegistryObject = filteredRegistry;
function persist()
{
window.localStorage["resource-history"] = JSON.stringify(filteredRegistry);
}
// Schedule async storage.
setTimeout(persist, 0);
}
/**
* @param {WebInspector.ResourceRevision} revision
*/
WebInspector.Resource.persistRevision = function(revision)
{
if (!window.localStorage)
return;
if (revision.resource.url.startsWith("inspector://"))
return;
var resource = revision.resource;
var url = resource.url;
var loaderId = resource.loaderId;
var timestamp = revision.timestamp.getTime();
var key = "resource-history|" + url + "|" + loaderId + "|" + timestamp;
var content = revision._content;
var registry = WebInspector.Resource._resourceRevisionRegistry();
var historyItems = registry[resource.url];
if (!historyItems) {
historyItems = [];
registry[resource.url] = historyItems;
}
historyItems.push({url: url, loaderId: loaderId, timestamp: timestamp, key: key});
function persist()
{
window.localStorage[key] = content;
window.localStorage["resource-history"] = JSON.stringify(registry);
}
// Schedule async storage.
setTimeout(persist, 0);
}
/**
* @param {WebInspector.Resource} resource
*/
WebInspector.Resource._clearResourceHistory = function(resource)
{
if (!window.localStorage)
return;
if (resource.url.startsWith("inspector://"))
return;
var registry = WebInspector.Resource._resourceRevisionRegistry();
var historyItems = registry[resource.url];
for (var i = 0; historyItems && i < historyItems.length; ++i)
delete window.localStorage[historyItems[i].key];
delete registry[resource.url];
window.localStorage["resource-history"] = JSON.stringify(registry);
}
WebInspector.Resource.Events = {
RevisionAdded: "revision-added",
MessageAdded: "message-added",
MessagesCleared: "messages-cleared",
}
WebInspector.Resource.prototype = {
/**
* @return {?WebInspector.NetworkRequest}
*/
get request()
{
return this._request;
},
/**
* @return {string}
*/
get url()
{
return this._url;
},
set url(x)
{
this._url = x;
this._parsedURL = new WebInspector.ParsedURL(x);
},
get parsedURL()
{
return this._parsedURL;
},
/**
* @return {string}
*/
get documentURL()
{
return this._documentURL;
},
/**
* @return {NetworkAgent.FrameId}
*/
get frameId()
{
return this._frameId;
},
/**
* @return {NetworkAgent.LoaderId}
*/
get loaderId()
{
return this._loaderId;
},
/**
* @return {string}
*/
get displayName()
{
return this._parsedURL.displayName;
},
/**
* @return {WebInspector.ResourceType}
*/
get type()
{
return this._request ? this._request.type : this._type;
},
/**
* @return {string}
*/
get mimeType()
{
return this._request ? this._request.mimeType : this._mimeType;
},
/**
* @return {Array.<WebInspector.ConsoleMessage>}
*/
get messages()
{
return this._messages || [];
},
/**
* @param {WebInspector.ConsoleMessage} msg
*/
addMessage: function(msg)
{
if (!msg.isErrorOrWarning() || !msg.message)
return;
if (!this._messages)
this._messages = [];
this._messages.push(msg);
this.dispatchEventToListeners(WebInspector.Resource.Events.MessageAdded, msg);
},
/**
* @return {number}
*/
get errors()
{
return this._errors || 0;
},
set errors(x)
{
this._errors = x;
},
/**
* @return {number}
*/
get warnings()
{
return this._warnings || 0;
},
set warnings(x)
{
this._warnings = x;
},
clearErrorsAndWarnings: function()
{
this._messages = [];
this._warnings = 0;
this._errors = 0;
this.dispatchEventToListeners(WebInspector.Resource.Events.MessagesCleared);
},
/**
* @return {?string}
*/
get content()
{
return this._content;
},
/**
* @return {boolean}
*/
get contentEncoded()
{
return this._contentEncoded;
},
/**
* @param {string} newContent
* @param {function(String)=} callback
*/
_setContent: function(newContent, callback)
{
var uiSourceCode = this._uiSourceCode;
if (!this._uiSourceCode || !this._uiSourceCode.isEditable())
return;
this._uiSourceCode.setWorkingCopy(newContent);
this._uiSourceCode.commitWorkingCopy(callback);
},
/**
* @param {string} content
* @param {Date=} timestamp
* @param {boolean=} restoringHistory
*/
addRevision: function(content, timestamp, restoringHistory)
{
if (this.history.length) {
var lastRevision = this.history[this.history.length - 1];
if (lastRevision._content === content)
return;
}
var revision = new WebInspector.ResourceRevision(this, content, timestamp || new Date());
this.history.push(revision);
this.dispatchEventToListeners(WebInspector.Resource.Events.RevisionAdded, revision);
if (!restoringHistory)
revision._persistRevision();
WebInspector.resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceContentCommitted, { resource: this, content: content });
},
/**
* @return {?string}
*/
contentURL: function()
{
return this._url;
},
/**
* @return {WebInspector.ResourceType}
*/
contentType: function()
{
return this.type;
},
/**
* @param {function(?string, boolean, string)} callback
*/
requestContent: function(callback)
{
if (typeof this._content !== "undefined") {
callback(this._content, !!this._contentEncoded, this.canonicalMimeType());
return;
}
this._pendingContentCallbacks.push(callback);
if (!this._request || this._request.finished)
this._innerRequestContent();
},
canonicalMimeType: function()
{
return this.type.canonicalMimeType() || this.mimeType;
},
/**
* @param {string} query
* @param {boolean} caseSensitive
* @param {boolean} isRegex
* @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback
*/
searchInContent: function(query, caseSensitive, isRegex, callback)
{
/**
* @param {?Protocol.Error} error
* @param {Array.<PageAgent.SearchMatch>} searchMatches
*/
function callbackWrapper(error, searchMatches)
{
callback(searchMatches || []);
}
if (this.frameId)
PageAgent.searchInResource(this.frameId, this.url, query, caseSensitive, isRegex, callbackWrapper);
else
callback([]);
},
/**
* @param {Element} image
*/
populateImageSource: function(image)
{
function onResourceContent()
{
image.src = this._contentURL();
}
this.requestContent(onResourceContent.bind(this));
},
/**
* @return {string}
*/
_contentURL: function()
{
const 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;
},
_requestFinished: function()
{
this._request.removeEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this);
if (this._pendingContentCallbacks.length)
this._innerRequestContent();
},
_innerRequestContent: function()
{
if (this._contentRequested)
return;
this._contentRequested = true;
/**
* @param {?Protocol.Error} error
* @param {string} content
* @param {boolean} contentEncoded
*/
function callback(error, content, contentEncoded)
{
this._content = error ? null : content;
this._contentEncoded = contentEncoded;
var callbacks = this._pendingContentCallbacks.slice();
for (var i = 0; i < callbacks.length; ++i)
callbacks[i](this._content, this._contentEncoded, this.canonicalMimeType());
this._pendingContentCallbacks.length = 0;
delete this._contentRequested;
}
PageAgent.getResourceContent(this.frameId, this.url, callback.bind(this));
},
revertToOriginal: function()
{
function revert(content)
{
this._setContent(content, function() {});
}
this.requestContent(revert.bind(this));
},
revertAndClearHistory: function(callback)
{
function revert(content)
{
this._setContent(content, clearHistory.bind(this));
}
function clearHistory()
{
WebInspector.Resource._clearResourceHistory(this);
this.history = [];
callback();
}
this.requestContent(revert.bind(this));
},
/**
* @return {boolean}
*/
isHidden: function()
{
return !!this._isHidden;
},
/**
* @return {WebInspector.UISourceCode}
*/
uiSourceCode: function()
{
return this._uiSourceCode;
},
/**
* @param {WebInspector.UISourceCode} uiSourceCode
*/
setUISourceCode: function(uiSourceCode)
{
this._uiSourceCode = uiSourceCode;
}
}
WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
/**
* @constructor
* @implements {WebInspector.ContentProvider}
* @param {WebInspector.Resource} resource
* @param {?string|undefined} content
* @param {Date} timestamp
*/
WebInspector.ResourceRevision = function(resource, content, timestamp)
{
this._resource = resource;
this._content = content;
this._timestamp = timestamp;
}
WebInspector.ResourceRevision.prototype = {
/**
* @return {WebInspector.Resource}
*/
get resource()
{
return this._resource;
},
/**
* @return {Date}
*/
get timestamp()
{
return this._timestamp;
},
/**
* @return {?string}
*/
get content()
{
return this._content || null;
},
revertToThis: function()
{
function revert(content)
{
if (this._resource._content !== content)
this._resource._setContent(content, function() {});
}
this.requestContent(revert.bind(this));
},
/**
* @return {?string}
*/
contentURL: function()
{
return this._resource.url;
},
/**
* @return {WebInspector.ResourceType}
*/
contentType: function()
{
return this._resource.contentType();
},
/**
* @param {function(?string, boolean, string)} callback
*/
requestContent: function(callback)
{
callback(this._content || "", false, this.resource.mimeType);
},
/**
* @param {string} query
* @param {boolean} caseSensitive
* @param {boolean} isRegex
* @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback
*/
searchInContent: function(query, caseSensitive, isRegex, callback)
{
callback([]);
},
_persistRevision: function()
{
WebInspector.Resource.persistRevision(this);
}
}