• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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