399f110406adf884fa1f27f50d51c62d8346898f
[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     FrameCommittedLoad: "FrameCommittedLoad",
43     FrameDetached: "FrameDetached"
44 }
45
46 WebInspector.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
67 WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype;
68
69 WebInspector.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
78 WebInspector.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     requestWillBeSent: function(identifier, frameId, loaderId, documentURL, request, time, stackTrace, redirectResponse)
119     {
120         var resource = this._inflightResourcesById[identifier];
121         if (resource) {
122             this.responseReceived(identifier, time, "Other", redirectResponse);
123             resource = this._appendRedirect(identifier, time, request.url);
124         } else
125             resource = this._createResource(identifier, frameId, loaderId, request.url, documentURL, stackTrace);
126         this._updateResourceWithRequest(resource, request);
127         resource.startTime = time;
128
129         this._startResource(resource);
130     },
131
132     resourceMarkedAsCached: function(identifier)
133     {
134         var resource = this._inflightResourcesById[identifier];
135         if (!resource)
136             return;
137
138         resource.cached = true;
139         this._updateResource(resource);
140     },
141
142     responseReceived: function(identifier, time, resourceType, response)
143     {
144         var resource = this._inflightResourcesById[identifier];
145         if (!resource)
146             return;
147
148         resource.responseReceivedTime = time;
149         resource.type = WebInspector.Resource.Type[resourceType];
150
151         this._updateResourceWithResponse(resource, response);
152
153         this._updateResource(resource);
154     },
155
156     domContentEventFired: function(time)
157     {
158         if (WebInspector.panels.network)
159             WebInspector.panels.network.mainResourceDOMContentTime = time;
160     },
161
162     loadEventFired: function(time)
163     {
164         if (WebInspector.panels.network)
165             WebInspector.panels.network.mainResourceLoadTime = time;
166     },
167
168     dataReceived: function(identifier, time, dataLength, encodedDataLength)
169     {
170         var resource = this._inflightResourcesById[identifier];
171         if (!resource)
172             return;
173
174         resource.resourceSize += dataLength;
175         if (encodedDataLength != -1)
176             resource.increaseTransferSize(encodedDataLength);
177         resource.endTime = time;
178
179         this._updateResource(resource);
180     },
181
182     loadingFinished: function(identifier, finishTime)
183     {
184         var resource = this._inflightResourcesById[identifier];
185         if (!resource)
186             return;
187
188         this._finishResource(resource, finishTime);
189     },
190
191     loadingFailed: function(identifier, time, localizedDescription, canceled)
192     {
193         var resource = this._inflightResourcesById[identifier];
194         if (!resource)
195             return;
196
197         resource.failed = true;
198         resource.canceled = canceled;
199         resource.localizedFailDescription = localizedDescription;
200         this._finishResource(resource, time);
201     },
202
203     resourceLoadedFromMemoryCache: function(frameId, loaderId, documentURL, time, cachedResource)
204     {
205         var resource = this._createResource("cached:" + ++this._lastIdentifierForCachedResource, frameId, loaderId, cachedResource.url, documentURL);
206         this._updateResourceWithCachedResource(resource, cachedResource);
207         resource.cached = true;
208         resource.requestMethod = "GET";
209         this._startResource(resource);
210         resource.startTime = resource.responseReceivedTime = time;
211         this._finishResource(resource, time);
212     },
213
214     frameDetached: function(frameId)
215     {
216         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.FrameDetached, frameId);
217     },
218
219     initialContentSet: function(identifier, sourceString, type)
220     {
221         var resource = WebInspector.networkResourceById(identifier);
222         if (!resource)
223             return;
224
225         resource.type = WebInspector.Resource.Type[type];
226         resource.setInitialContent(sourceString);
227         this._updateResource(resource);
228     },
229
230     frameNavigated: function(frame, loaderId)
231     {
232         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.FrameCommittedLoad, { frame: frame, loaderId: loaderId });
233     },
234
235     webSocketCreated: function(identifier, requestURL)
236     {
237         var resource = this._createResource(identifier, null, null, requestURL);
238         resource.type = WebInspector.Resource.Type.WebSocket;
239         this._startResource(resource);
240     },
241
242     webSocketWillSendHandshakeRequest: function(identifier, time, request)
243     {
244         var resource = this._inflightResourcesById[identifier];
245         if (!resource)
246             return;
247
248         resource.requestMethod = "GET";
249         resource.requestHeaders = request.headers;
250         resource.webSocketRequestKey3 = request.requestKey3;
251         resource.startTime = time;
252
253         this._updateResource(resource);
254     },
255
256     webSocketHandshakeResponseReceived: function(identifier, time, response)
257     {
258         var resource = this._inflightResourcesById[identifier];
259         if (!resource)
260             return;
261
262         resource.statusCode = response.status;
263         resource.statusText = response.statusText;
264         resource.responseHeaders = response.headers;
265         resource.webSocketChallengeResponse = response.challengeResponse;
266         resource.responseReceivedTime = time;
267
268         this._updateResource(resource);
269     },
270
271     webSocketClosed: function(identifier, time)
272     {
273         var resource = this._inflightResourcesById[identifier];
274         if (!resource)
275             return;
276         this._finishResource(resource, time);
277     },
278
279     _appendRedirect: function(identifier, time, redirectURL)
280     {
281         var originalResource = this._inflightResourcesById[identifier];
282         var previousRedirects = originalResource.redirects || [];
283         originalResource.identifier = "redirected:" + identifier + "." + previousRedirects.length;
284         delete originalResource.redirects;
285         this._finishResource(originalResource, time);
286         var newResource = this._createResource(identifier, originalResource.frameId, originalResource.loaderId,
287              redirectURL, originalResource.documentURL, originalResource.stackTrace);
288         newResource.redirects = previousRedirects.concat(originalResource);
289         return newResource;
290     },
291
292     _startResource: function(resource)
293     {
294         this._inflightResourcesById[resource.identifier] = resource;
295         this._inflightResourcesByURL[resource.url] = resource;
296         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource);
297     },
298
299     _updateResource: function(resource)
300     {
301         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource);
302     },
303
304     _finishResource: function(resource, finishTime)
305     {
306         resource.endTime = finishTime;
307         resource.finished = true;
308         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource);
309         delete this._inflightResourcesById[resource.identifier];
310         delete this._inflightResourcesByURL[resource.url];
311     },
312
313     _dispatchEventToListeners: function(eventType, resource)
314     {
315         this._manager.dispatchEventToListeners(eventType, resource);
316     },
317
318     _createResource: function(identifier, frameId, loaderId, url, documentURL, stackTrace)
319     {
320         var resource = new WebInspector.Resource(identifier, url, loaderId);
321         resource.documentURL = documentURL;
322         resource.frameId = frameId;
323         resource.stackTrace = stackTrace;
324         return resource;
325     }
326 }