1/* 2 * Copyright (C) 2011 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31WebInspector.NetworkManager = function() 32{ 33 WebInspector.Object.call(this); 34 this._dispatcher = new WebInspector.NetworkDispatcher(this); 35 NetworkAgent.enable(); 36} 37 38WebInspector.NetworkManager.EventTypes = { 39 ResourceStarted: "ResourceStarted", 40 ResourceUpdated: "ResourceUpdated", 41 ResourceFinished: "ResourceFinished", 42 FrameCommittedLoad: "FrameCommittedLoad", 43 FrameDetached: "FrameDetached" 44} 45 46WebInspector.NetworkManager.prototype = { 47 frontendReused: function() 48 { 49 NetworkAgent.enable(); 50 }, 51 52 requestContent: function(resource, base64Encode, callback) 53 { 54 function callbackWrapper(error, content) 55 { 56 callback(!error ? content : null); 57 } 58 NetworkAgent.getResourceContent(resource.frameId, resource.url, base64Encode, callbackWrapper); 59 }, 60 61 inflightResourceForURL: function(url) 62 { 63 return this._dispatcher._inflightResourcesByURL[url]; 64 } 65} 66 67WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype; 68 69WebInspector.NetworkDispatcher = function(manager) 70{ 71 this._manager = manager; 72 this._inflightResourcesById = {}; 73 this._inflightResourcesByURL = {}; 74 this._lastIdentifierForCachedResource = 0; 75 InspectorBackend.registerDomainDispatcher("Network", this); 76} 77 78WebInspector.NetworkDispatcher.prototype = { 79 _updateResourceWithRequest: function(resource, request) 80 { 81 resource.requestMethod = request.method; 82 resource.requestHeaders = request.headers; 83 resource.requestFormData = request.postData; 84 }, 85 86 _updateResourceWithResponse: function(resource, response) 87 { 88 if (!response) 89 return; 90 91 resource.mimeType = response.mimeType; 92 resource.statusCode = response.status; 93 resource.statusText = response.statusText; 94 resource.responseHeaders = response.headers; 95 if (response.headersText) 96 resource.responseHeadersText = response.headersText; 97 if (response.requestHeaders) 98 resource.requestHeaders = response.requestHeaders; 99 if (response.requestHeadersText) 100 resource.requestHeadersText = response.requestHeadersText; 101 102 resource.connectionReused = response.connectionReused; 103 resource.connectionID = response.connectionID; 104 105 if (response.fromDiskCache) 106 resource.cached = true; 107 else 108 resource.timing = response.timing; 109 }, 110 111 _updateResourceWithCachedResource: function(resource, cachedResource) 112 { 113 resource.type = WebInspector.Resource.Type[cachedResource.type]; 114 resource.resourceSize = cachedResource.bodySize; 115 this._updateResourceWithResponse(resource, cachedResource.response); 116 }, 117 118 _isNull: function(response) 119 { 120 return response && !response.status && !response.mimeType && !Object.keys(response.headers).length; 121 }, 122 123 requestWillBeSent: function(identifier, frameId, loaderId, documentURL, request, time, stackTrace, redirectResponse) 124 { 125 var resource = this._inflightResourcesById[identifier]; 126 if (resource) { 127 // FIXME: move this check to the backend. 128 if (this._isNull(redirectResponse)) 129 return; 130 this.responseReceived(identifier, time, "Other", redirectResponse); 131 resource = this._appendRedirect(identifier, time, request.url); 132 } else 133 resource = this._createResource(identifier, frameId, loaderId, request.url, documentURL, stackTrace); 134 this._updateResourceWithRequest(resource, request); 135 resource.startTime = time; 136 137 this._startResource(resource); 138 }, 139 140 resourceMarkedAsCached: function(identifier) 141 { 142 var resource = this._inflightResourcesById[identifier]; 143 if (!resource) 144 return; 145 146 resource.cached = true; 147 this._updateResource(resource); 148 }, 149 150 responseReceived: function(identifier, time, resourceType, response) 151 { 152 // FIXME: move this check to the backend. 153 if (this._isNull(response)) 154 return; 155 156 var resource = this._inflightResourcesById[identifier]; 157 if (!resource) 158 return; 159 160 resource.responseReceivedTime = time; 161 resource.type = WebInspector.Resource.Type[resourceType]; 162 163 this._updateResourceWithResponse(resource, response); 164 165 this._updateResource(resource); 166 }, 167 168 domContentEventFired: function(time) 169 { 170 if (WebInspector.panels.network) 171 WebInspector.panels.network.mainResourceDOMContentTime = time; 172 }, 173 174 loadEventFired: function(time) 175 { 176 if (WebInspector.panels.network) 177 WebInspector.panels.network.mainResourceLoadTime = time; 178 }, 179 180 dataReceived: function(identifier, time, dataLength, encodedDataLength) 181 { 182 var resource = this._inflightResourcesById[identifier]; 183 if (!resource) 184 return; 185 186 resource.resourceSize += dataLength; 187 if (encodedDataLength != -1) 188 resource.increaseTransferSize(encodedDataLength); 189 resource.endTime = time; 190 191 this._updateResource(resource); 192 }, 193 194 loadingFinished: function(identifier, finishTime) 195 { 196 var resource = this._inflightResourcesById[identifier]; 197 if (!resource) 198 return; 199 200 this._finishResource(resource, finishTime); 201 }, 202 203 loadingFailed: function(identifier, time, localizedDescription, canceled) 204 { 205 var resource = this._inflightResourcesById[identifier]; 206 if (!resource) 207 return; 208 209 resource.failed = true; 210 resource.canceled = canceled; 211 resource.localizedFailDescription = localizedDescription; 212 this._finishResource(resource, time); 213 }, 214 215 resourceLoadedFromMemoryCache: function(frameId, loaderId, documentURL, time, cachedResource) 216 { 217 var resource = this._createResource("cached:" + ++this._lastIdentifierForCachedResource, frameId, loaderId, cachedResource.url, documentURL); 218 this._updateResourceWithCachedResource(resource, cachedResource); 219 resource.cached = true; 220 resource.requestMethod = "GET"; 221 this._startResource(resource); 222 resource.startTime = resource.responseReceivedTime = time; 223 this._finishResource(resource, time); 224 }, 225 226 frameDetached: function(frameId) 227 { 228 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.FrameDetached, frameId); 229 }, 230 231 initialContentSet: function(identifier, sourceString, type) 232 { 233 var resource = WebInspector.networkResourceById(identifier); 234 if (!resource) 235 return; 236 237 resource.type = WebInspector.Resource.Type[type]; 238 resource.setInitialContent(sourceString); 239 this._updateResource(resource); 240 }, 241 242 frameNavigated: function(frame, loaderId) 243 { 244 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.FrameCommittedLoad, { frame: frame, loaderId: loaderId }); 245 }, 246 247 webSocketCreated: function(identifier, requestURL) 248 { 249 var resource = this._createResource(identifier, null, null, requestURL); 250 resource.type = WebInspector.Resource.Type.WebSocket; 251 this._startResource(resource); 252 }, 253 254 webSocketWillSendHandshakeRequest: function(identifier, time, request) 255 { 256 var resource = this._inflightResourcesById[identifier]; 257 if (!resource) 258 return; 259 260 resource.requestMethod = "GET"; 261 resource.requestHeaders = request.headers; 262 resource.webSocketRequestKey3 = request.requestKey3; 263 resource.startTime = time; 264 265 this._updateResource(resource); 266 }, 267 268 webSocketHandshakeResponseReceived: function(identifier, time, response) 269 { 270 var resource = this._inflightResourcesById[identifier]; 271 if (!resource) 272 return; 273 274 resource.statusCode = response.status; 275 resource.statusText = response.statusText; 276 resource.responseHeaders = response.headers; 277 resource.webSocketChallengeResponse = response.challengeResponse; 278 resource.responseReceivedTime = time; 279 280 this._updateResource(resource); 281 }, 282 283 webSocketClosed: function(identifier, time) 284 { 285 var resource = this._inflightResourcesById[identifier]; 286 if (!resource) 287 return; 288 this._finishResource(resource, time); 289 }, 290 291 _appendRedirect: function(identifier, time, redirectURL) 292 { 293 var originalResource = this._inflightResourcesById[identifier]; 294 var previousRedirects = originalResource.redirects || []; 295 originalResource.identifier = "redirected:" + identifier + "." + previousRedirects.length; 296 delete originalResource.redirects; 297 this._finishResource(originalResource, time); 298 var newResource = this._createResource(identifier, originalResource.frameId, originalResource.loaderId, 299 redirectURL, originalResource.documentURL, originalResource.stackTrace); 300 newResource.redirects = previousRedirects.concat(originalResource); 301 return newResource; 302 }, 303 304 _startResource: function(resource) 305 { 306 this._inflightResourcesById[resource.identifier] = resource; 307 this._inflightResourcesByURL[resource.url] = resource; 308 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource); 309 }, 310 311 _updateResource: function(resource) 312 { 313 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource); 314 }, 315 316 _finishResource: function(resource, finishTime) 317 { 318 resource.endTime = finishTime; 319 resource.finished = true; 320 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource); 321 delete this._inflightResourcesById[resource.identifier]; 322 delete this._inflightResourcesByURL[resource.url]; 323 }, 324 325 _dispatchEventToListeners: function(eventType, resource) 326 { 327 this._manager.dispatchEventToListeners(eventType, resource); 328 }, 329 330 _createResource: function(identifier, frameId, loaderId, url, documentURL, stackTrace) 331 { 332 var resource = new WebInspector.Resource(identifier, url); 333 resource.documentURL = documentURL; 334 resource.frameId = frameId; 335 resource.loaderId = loaderId; 336 resource.stackTrace = stackTrace; 337 return resource; 338 } 339} 340