2011-04-25 Pavel Feldman <pfeldman@google.com>
[WebKit-https.git] / Source / WebCore / inspector / front-end / NetworkManager.js
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
31 WebInspector.NetworkManager = function()
32 {
33     WebInspector.Object.call(this);
34     this._dispatcher = new WebInspector.NetworkDispatcher(this);
35     NetworkAgent.enable();
36 }
37
38 WebInspector.NetworkManager.EventTypes = {
39     ResourceStarted: "ResourceStarted",
40     ResourceUpdated: "ResourceUpdated",
41     ResourceFinished: "ResourceFinished"
42 }
43
44 WebInspector.NetworkManager.prototype = {
45     frontendReused: function()
46     {
47         NetworkAgent.enable();
48     },
49
50     requestContent: function(resource, base64Encode, callback)
51     {
52         function callbackWrapper(error, content)
53         {
54             callback(!error ? content : null);
55         }
56         PageAgent.getResourceContent(resource.frameId, resource.url, base64Encode, callbackWrapper);
57     },
58
59     inflightResourceForURL: function(url)
60     {
61         return this._dispatcher._inflightResourcesByURL[url];
62     }
63 }
64
65 WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype;
66
67 WebInspector.NetworkDispatcher = function(manager)
68 {
69     this._manager = manager;
70     this._inflightResourcesById = {};
71     this._inflightResourcesByURL = {};
72     this._lastIdentifierForCachedResource = 0;
73     InspectorBackend.registerDomainDispatcher("Network", this);
74 }
75
76 WebInspector.NetworkDispatcher.prototype = {
77     _updateResourceWithRequest: function(resource, request)
78     {
79         resource.requestMethod = request.method;
80         resource.requestHeaders = request.headers;
81         resource.requestFormData = request.postData;
82     },
83
84     _updateResourceWithResponse: function(resource, response)
85     {
86         if (!response)
87             return;
88
89         resource.mimeType = response.mimeType;
90         resource.statusCode = response.status;
91         resource.statusText = response.statusText;
92         resource.responseHeaders = response.headers;
93         if (response.headersText)
94             resource.responseHeadersText = response.headersText;
95         if (response.requestHeaders)
96             resource.requestHeaders = response.requestHeaders;
97         if (response.requestHeadersText)
98             resource.requestHeadersText = response.requestHeadersText;
99
100         resource.connectionReused = response.connectionReused;
101         resource.connectionID = response.connectionID;
102
103         if (response.fromDiskCache)
104             resource.cached = true;
105         else
106             resource.timing = response.timing;
107     },
108
109     _updateResourceWithCachedResource: function(resource, cachedResource)
110     {
111         resource.type = WebInspector.Resource.Type[cachedResource.type];
112         resource.resourceSize = cachedResource.bodySize;
113         this._updateResourceWithResponse(resource, cachedResource.response);
114     },
115
116     requestWillBeSent: function(identifier, frameId, loaderId, documentURL, request, time, stackTrace, redirectResponse)
117     {
118         var resource = this._inflightResourcesById[identifier];
119         if (resource) {
120             this.responseReceived(identifier, time, "Other", redirectResponse);
121             resource = this._appendRedirect(identifier, time, request.url);
122         } else
123             resource = this._createResource(identifier, frameId, loaderId, request.url, documentURL, stackTrace);
124         this._updateResourceWithRequest(resource, request);
125         resource.startTime = time;
126
127         this._startResource(resource);
128     },
129
130     resourceMarkedAsCached: function(identifier)
131     {
132         var resource = this._inflightResourcesById[identifier];
133         if (!resource)
134             return;
135
136         resource.cached = true;
137         this._updateResource(resource);
138     },
139
140     responseReceived: function(identifier, time, resourceType, response)
141     {
142         var resource = this._inflightResourcesById[identifier];
143         if (!resource)
144             return;
145
146         resource.responseReceivedTime = time;
147         resource.type = WebInspector.Resource.Type[resourceType];
148
149         this._updateResourceWithResponse(resource, response);
150
151         this._updateResource(resource);
152     },
153
154     dataReceived: function(identifier, time, dataLength, encodedDataLength)
155     {
156         var resource = this._inflightResourcesById[identifier];
157         if (!resource)
158             return;
159
160         resource.resourceSize += dataLength;
161         if (encodedDataLength != -1)
162             resource.increaseTransferSize(encodedDataLength);
163         resource.endTime = time;
164
165         this._updateResource(resource);
166     },
167
168     loadingFinished: function(identifier, finishTime)
169     {
170         var resource = this._inflightResourcesById[identifier];
171         if (!resource)
172             return;
173
174         this._finishResource(resource, finishTime);
175     },
176
177     loadingFailed: function(identifier, time, localizedDescription, canceled)
178     {
179         var resource = this._inflightResourcesById[identifier];
180         if (!resource)
181             return;
182
183         resource.failed = true;
184         resource.canceled = canceled;
185         resource.localizedFailDescription = localizedDescription;
186         this._finishResource(resource, time);
187     },
188
189     resourceLoadedFromMemoryCache: function(frameId, loaderId, documentURL, time, cachedResource)
190     {
191         var resource = this._createResource("cached:" + ++this._lastIdentifierForCachedResource, frameId, loaderId, cachedResource.url, documentURL);
192         this._updateResourceWithCachedResource(resource, cachedResource);
193         resource.cached = true;
194         resource.requestMethod = "GET";
195         this._startResource(resource);
196         resource.startTime = resource.responseReceivedTime = time;
197         this._finishResource(resource, time);
198     },
199
200     initialContentSet: function(identifier, sourceString, type)
201     {
202         var resource = WebInspector.networkResourceById(identifier);
203         if (!resource)
204             return;
205
206         resource.type = WebInspector.Resource.Type[type];
207         resource.setInitialContent(sourceString);
208         this._updateResource(resource);
209     },
210
211     webSocketCreated: function(identifier, requestURL)
212     {
213         var resource = this._createResource(identifier, null, null, requestURL);
214         resource.type = WebInspector.Resource.Type.WebSocket;
215         this._startResource(resource);
216     },
217
218     webSocketWillSendHandshakeRequest: function(identifier, time, request)
219     {
220         var resource = this._inflightResourcesById[identifier];
221         if (!resource)
222             return;
223
224         resource.requestMethod = "GET";
225         resource.requestHeaders = request.headers;
226         resource.webSocketRequestKey3 = request.requestKey3;
227         resource.startTime = time;
228
229         this._updateResource(resource);
230     },
231
232     webSocketHandshakeResponseReceived: function(identifier, time, response)
233     {
234         var resource = this._inflightResourcesById[identifier];
235         if (!resource)
236             return;
237
238         resource.statusCode = response.status;
239         resource.statusText = response.statusText;
240         resource.responseHeaders = response.headers;
241         resource.webSocketChallengeResponse = response.challengeResponse;
242         resource.responseReceivedTime = time;
243
244         this._updateResource(resource);
245     },
246
247     webSocketClosed: function(identifier, time)
248     {
249         var resource = this._inflightResourcesById[identifier];
250         if (!resource)
251             return;
252         this._finishResource(resource, time);
253     },
254
255     _appendRedirect: function(identifier, time, redirectURL)
256     {
257         var originalResource = this._inflightResourcesById[identifier];
258         var previousRedirects = originalResource.redirects || [];
259         originalResource.identifier = "redirected:" + identifier + "." + previousRedirects.length;
260         delete originalResource.redirects;
261         this._finishResource(originalResource, time);
262         var newResource = this._createResource(identifier, originalResource.frameId, originalResource.loaderId,
263              redirectURL, originalResource.documentURL, originalResource.stackTrace);
264         newResource.redirects = previousRedirects.concat(originalResource);
265         return newResource;
266     },
267
268     _startResource: function(resource)
269     {
270         this._inflightResourcesById[resource.identifier] = resource;
271         this._inflightResourcesByURL[resource.url] = resource;
272         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource);
273     },
274
275     _updateResource: function(resource)
276     {
277         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource);
278     },
279
280     _finishResource: function(resource, finishTime)
281     {
282         resource.endTime = finishTime;
283         resource.finished = true;
284         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource);
285         delete this._inflightResourcesById[resource.identifier];
286         delete this._inflightResourcesByURL[resource.url];
287     },
288
289     _dispatchEventToListeners: function(eventType, resource)
290     {
291         this._manager.dispatchEventToListeners(eventType, resource);
292     },
293
294     _createResource: function(identifier, frameId, loaderId, url, documentURL, stackTrace)
295     {
296         var resource = new WebInspector.Resource(identifier, url, loaderId);
297         resource.documentURL = documentURL;
298         resource.frameId = frameId;
299         resource.stackTrace = stackTrace;
300         return resource;
301     }
302 }