| /* |
| * Copyright (C) 2011 Google 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: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * 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. |
| * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT |
| * OWNER OR 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.NetworkManager = function(resourceTreeModel) |
| { |
| WebInspector.Object.call(this); |
| this._resourceTreeModel = resourceTreeModel; |
| this._dispatcher = new WebInspector.NetworkDispatcher(resourceTreeModel, this); |
| InspectorBackend.cachedResources(this._processCachedResources.bind(this)); |
| } |
| |
| WebInspector.NetworkManager.EventTypes = { |
| ResourceStarted: "ResourceStarted", |
| ResourceUpdated: "ResourceUpdated", |
| ResourceFinished: "ResourceFinished", |
| MainResourceCommitLoad: "MainResourceCommitLoad" |
| } |
| |
| WebInspector.NetworkManager.prototype = { |
| reset: function() |
| { |
| WebInspector.panels.network.clear(); |
| this._resourceTreeModel.reset(); |
| InspectorBackend.cachedResources(this._processCachedResources.bind(this)); |
| }, |
| |
| requestContent: function(resource, base64Encode, callback) |
| { |
| function callbackWrapper(success, content) |
| { |
| callback(success ? content : null); |
| } |
| InspectorBackend.resourceContent(resource.loader.frameId, resource.url, base64Encode, callbackWrapper); |
| }, |
| |
| _processCachedResources: function(mainFramePayload) |
| { |
| var mainResource = this._dispatcher._addFramesRecursively(mainFramePayload); |
| WebInspector.mainResource = mainResource; |
| mainResource.isMainResource = true; |
| }, |
| |
| inflightResourceForURL: function(url) |
| { |
| return this._dispatcher._inflightResourcesByURL[url]; |
| } |
| } |
| |
| WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype; |
| |
| WebInspector.NetworkDispatcher = function(resourceTreeModel, manager) |
| { |
| this._manager = manager; |
| this._inflightResourcesById = {}; |
| this._inflightResourcesByURL = {}; |
| this._resourceTreeModel = resourceTreeModel; |
| this._lastIdentifierForCachedResource = 0; |
| InspectorBackend.registerDomainDispatcher("Network", this); |
| } |
| |
| WebInspector.NetworkDispatcher.prototype = { |
| _updateResourceWithRequest: function(resource, request) |
| { |
| resource.requestMethod = request.httpMethod; |
| resource.requestHeaders = request.httpHeaderFields; |
| resource.requestFormData = request.requestFormData; |
| }, |
| |
| _updateResourceWithResponse: function(resource, response) |
| { |
| if (resource.isNull) |
| return; |
| |
| resource.mimeType = response.mimeType; |
| resource.expectedContentLength = response.expectedContentLength; |
| resource.textEncodingName = response.textEncodingName; |
| resource.suggestedFilename = response.suggestedFilename; |
| resource.statusCode = response.httpStatusCode; |
| resource.statusText = response.httpStatusText; |
| |
| resource.responseHeaders = response.httpHeaderFields; |
| resource.connectionReused = response.connectionReused; |
| resource.connectionID = response.connectionID; |
| |
| if (response.wasCached) |
| resource.cached = true; |
| else |
| resource.timing = response.timing; |
| |
| if (response.loadInfo) { |
| if (response.loadInfo.httpStatusCode) |
| resource.statusCode = response.loadInfo.httpStatusCode; |
| if (response.loadInfo.httpStatusText) |
| resource.statusText = response.loadInfo.httpStatusText; |
| resource.requestHeaders = response.loadInfo.requestHeaders; |
| resource.responseHeaders = response.loadInfo.responseHeaders; |
| } |
| }, |
| |
| _updateResourceWithCachedResource: function(resource, cachedResource) |
| { |
| resource.type = WebInspector.Resource.Type[cachedResource.type]; |
| resource.resourceSize = cachedResource.encodedSize; |
| this._updateResourceWithResponse(resource, cachedResource.response); |
| }, |
| |
| identifierForInitialRequest: function(identifier, url, loader, callStack) |
| { |
| this._startResource(this._createResource(identifier, url, loader, callStack)); |
| }, |
| |
| willSendRequest: function(identifier, time, request, redirectResponse) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| // Redirect may have empty URL and we'd like to not crash with invalid HashMap entry. |
| // See http/tests/misc/will-send-request-returns-null-on-redirect.html |
| var isRedirect = !redirectResponse.isNull && request.url.length; |
| if (isRedirect) { |
| this.didReceiveResponse(identifier, time, "Other", redirectResponse); |
| resource = this._appendRedirect(resource.identifier, time, request.url); |
| } |
| |
| this._updateResourceWithRequest(resource, request); |
| resource.startTime = time; |
| |
| if (isRedirect) |
| this._startResource(resource); |
| else |
| this._updateResource(resource); |
| }, |
| |
| markResourceAsCached: function(identifier) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| resource.cached = true; |
| this._updateResource(resource); |
| }, |
| |
| didReceiveResponse: function(identifier, time, resourceType, response) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| resource.responseReceivedTime = time; |
| resource.type = WebInspector.Resource.Type[resourceType]; |
| |
| this._updateResourceWithResponse(resource, response); |
| |
| this._updateResource(resource); |
| this._resourceTreeModel.addResourceToFrame(resource.loader.frameId, resource); |
| }, |
| |
| didReceiveContentLength: function(identifier, time, lengthReceived) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| resource.resourceSize += lengthReceived; |
| resource.endTime = time; |
| |
| this._updateResource(resource); |
| }, |
| |
| didFinishLoading: function(identifier, finishTime) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| this._finishResource(resource, finishTime); |
| }, |
| |
| didFailLoading: function(identifier, time, localizedDescription) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| resource.failed = true; |
| resource.localizedFailDescription = localizedDescription; |
| this._finishResource(resource, time); |
| }, |
| |
| didLoadResourceFromMemoryCache: function(time, cachedResource) |
| { |
| var resource = this._createResource("cached:" + ++this._lastIdentifierForCachedResource, cachedResource.url, cachedResource.loader); |
| this._updateResourceWithCachedResource(resource, cachedResource); |
| resource.cached = true; |
| resource.requestMethod = "GET"; |
| this._startResource(resource); |
| resource.startTime = resource.responseReceivedTime = time; |
| this._finishResource(resource, time); |
| this._resourceTreeModel.addResourceToFrame(resource.loader.frameId, resource); |
| }, |
| |
| frameDetachedFromParent: function(frameId) |
| { |
| this._resourceTreeModel.frameDetachedFromParent(frameId); |
| }, |
| |
| setInitialContent: function(identifier, sourceString, type) |
| { |
| var resource = WebInspector.networkResourceById(identifier); |
| if (!resource) |
| return; |
| |
| resource.type = WebInspector.Resource.Type[type]; |
| resource.setInitialContent(sourceString); |
| this._updateResource(resource); |
| }, |
| |
| didCommitLoadForFrame: function(frame, loader) |
| { |
| this._resourceTreeModel.didCommitLoadForFrame(frame, loader); |
| if (!frame.parentId) { |
| var mainResource = this._resourceTreeModel.resourceForURL(frame.url); |
| if (mainResource) { |
| WebInspector.mainResource = mainResource; |
| mainResource.isMainResource = true; |
| this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.MainResourceCommitLoad, mainResource); |
| } |
| } |
| }, |
| |
| didCreateWebSocket: function(identifier, requestURL) |
| { |
| var resource = this._createResource(identifier, requestURL); |
| resource.type = WebInspector.Resource.Type.WebSocket; |
| this._startResource(resource); |
| }, |
| |
| willSendWebSocketHandshakeRequest: function(identifier, time, request) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| resource.requestMethod = "GET"; |
| resource.requestHeaders = request.webSocketHeaderFields; |
| resource.webSocketRequestKey3 = request.webSocketRequestKey3; |
| resource.startTime = time; |
| |
| this._updateResource(resource); |
| }, |
| |
| didReceiveWebSocketHandshakeResponse: function(identifier, time, response) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| |
| resource.statusCode = response.statusCode; |
| resource.statusText = response.statusText; |
| resource.responseHeaders = response.webSocketHeaderFields; |
| resource.webSocketChallengeResponse = response.webSocketChallengeResponse; |
| resource.responseReceivedTime = time; |
| |
| this._updateResource(resource); |
| }, |
| |
| didCloseWebSocket: function(identifier, time) |
| { |
| var resource = this._inflightResourcesById[identifier]; |
| if (!resource) |
| return; |
| this._finishResource(resource, time); |
| }, |
| |
| _appendRedirect: function(identifier, time, redirectURL) |
| { |
| var originalResource = this._inflightResourcesById[identifier]; |
| var previousRedirects = originalResource.redirects || []; |
| originalResource.identifier = "redirected:" + identifier + "." + previousRedirects.length; |
| delete originalResource.redirects; |
| this._finishResource(originalResource, time); |
| var newResource = this._createResource(identifier, redirectURL, originalResource.loader, originalResource.stackTrace); |
| newResource.redirects = previousRedirects.concat(originalResource); |
| return newResource; |
| }, |
| |
| _startResource: function(resource) |
| { |
| this._inflightResourcesById[resource.identifier] = resource; |
| this._inflightResourcesByURL[resource.url] = resource; |
| this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource); |
| }, |
| |
| _updateResource: function(resource) |
| { |
| this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource); |
| }, |
| |
| _finishResource: function(resource, finishTime) |
| { |
| resource.endTime = finishTime; |
| resource.finished = true; |
| this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource); |
| delete this._inflightResourcesById[resource.identifier]; |
| delete this._inflightResourcesByURL[resource.url]; |
| }, |
| |
| _addFramesRecursively: function(framePayload) |
| { |
| var frameResource = this._createResource(null, framePayload.resource.url, framePayload.resource.loader); |
| this._updateResourceWithRequest(frameResource, framePayload.resource.request); |
| this._updateResourceWithResponse(frameResource, framePayload.resource.response); |
| frameResource.type = WebInspector.Resource.Type["Document"]; |
| frameResource.finished = true; |
| |
| this._resourceTreeModel.addOrUpdateFrame(framePayload); |
| this._resourceTreeModel.addResourceToFrame(framePayload.id, frameResource); |
| |
| for (var i = 0; framePayload.children && i < framePayload.children.length; ++i) |
| this._addFramesRecursively(framePayload.children[i]); |
| |
| if (!framePayload.subresources) |
| return; |
| |
| for (var i = 0; i < framePayload.subresources.length; ++i) { |
| var cachedResource = framePayload.subresources[i]; |
| var resource = this._createResource(null, cachedResource.url, cachedResource.loader); |
| this._updateResourceWithCachedResource(resource, cachedResource); |
| resource.finished = true; |
| this._resourceTreeModel.addResourceToFrame(framePayload.id, resource); |
| } |
| return frameResource; |
| }, |
| |
| _dispatchEventToListeners: function(eventType, resource) |
| { |
| this._manager.dispatchEventToListeners(eventType, resource); |
| }, |
| |
| _createResource: function(identifier, url, loader, stackTrace) |
| { |
| var resource = new WebInspector.Resource(identifier, url); |
| resource.loader = loader; |
| if (loader) |
| resource.documentURL = loader.url; |
| resource.stackTrace = stackTrace; |
| return resource; |
| } |
| } |