Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / 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 /**
32  * @constructor
33  * @extends {WebInspector.Object}
34  */
35 WebInspector.NetworkManager = function()
36 {
37     WebInspector.Object.call(this);
38     this._dispatcher = new WebInspector.NetworkDispatcher(this);
39     if (WebInspector.settings.cacheDisabled.get())
40         NetworkAgent.setCacheDisabled(true);
41
42     NetworkAgent.enable();
43
44     WebInspector.settings.cacheDisabled.addChangeListener(this._cacheDisabledSettingChanged, this);
45 }
46
47 WebInspector.NetworkManager.EventTypes = {
48     RequestStarted: "RequestStarted",
49     RequestUpdated: "RequestUpdated",
50     RequestFinished: "RequestFinished",
51     RequestUpdateDropped: "RequestUpdateDropped"
52 }
53
54 WebInspector.NetworkManager._MIMETypes = {
55     "text/html":                   {"document": true},
56     "text/xml":                    {"document": true},
57     "text/plain":                  {"document": true},
58     "application/xhtml+xml":       {"document": true},
59     "text/css":                    {"stylesheet": true},
60     "text/xsl":                    {"stylesheet": true},
61     "image/jpg":                   {"image": true},
62     "image/jpeg":                  {"image": true},
63     "image/pjpeg":                 {"image": true},
64     "image/png":                   {"image": true},
65     "image/gif":                   {"image": true},
66     "image/bmp":                   {"image": true},
67     "image/svg+xml":               {"image": true, "font": true, "document": true},
68     "image/vnd.microsoft.icon":    {"image": true},
69     "image/webp":                  {"image": true},
70     "image/x-icon":                {"image": true},
71     "image/x-xbitmap":             {"image": true},
72     "font/ttf":                    {"font": true},
73     "font/otf":                    {"font": true},
74     "font/woff":                   {"font": true},
75     "font/woff2":                  {"font": true},
76     "font/truetype":               {"font": true},
77     "font/opentype":               {"font": true},
78     "application/octet-stream":    {"font": true, "image": true},
79     "application/font-woff":       {"font": true},
80     "application/x-font-woff":     {"font": true},
81     "application/x-font-type1":    {"font": true},
82     "application/x-font-ttf":      {"font": true},
83     "application/x-truetype-font": {"font": true},
84     "text/javascript":             {"script": true},
85     "text/ecmascript":             {"script": true},
86     "application/javascript":      {"script": true},
87     "application/ecmascript":      {"script": true},
88     "application/x-javascript":    {"script": true},
89     "application/json":            {"script": true},
90     "text/javascript1.1":          {"script": true},
91     "text/javascript1.2":          {"script": true},
92     "text/javascript1.3":          {"script": true},
93     "text/jscript":                {"script": true},
94     "text/livescript":             {"script": true},
95 }
96
97 WebInspector.NetworkManager.prototype = {
98     /**
99      * @param {string} url
100      * @return {!WebInspector.NetworkRequest}
101      */
102     inflightRequestForURL: function(url)
103     {
104         return this._dispatcher._inflightRequestsByURL[url];
105     },
106
107     /**
108      * @param {!WebInspector.Event} event
109      */
110     _cacheDisabledSettingChanged: function(event)
111     {
112         var enabled = /** @type {boolean} */ (event.data);
113         NetworkAgent.setCacheDisabled(enabled);
114     },
115
116     __proto__: WebInspector.Object.prototype
117 }
118
119 /**
120  * @constructor
121  * @implements {NetworkAgent.Dispatcher}
122  */
123 WebInspector.NetworkDispatcher = function(manager)
124 {
125     this._manager = manager;
126     this._inflightRequestsById = {};
127     this._inflightRequestsByURL = {};
128     InspectorBackend.registerNetworkDispatcher(this);
129 }
130
131 WebInspector.NetworkDispatcher.prototype = {
132     /**
133      * @param {!NetworkAgent.Headers} headersMap
134      * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
135      */
136     _headersMapToHeadersArray: function(headersMap)
137     {
138         var result = [];
139         for (var name in headersMap) {
140             var values = headersMap[name].split("\n");
141             for (var i = 0; i < values.length; ++i)
142                 result.push({name: name, value: values[i]});
143         }
144         return result;
145     },
146
147     /**
148      * @param {!WebInspector.NetworkRequest} networkRequest
149      * @param {!NetworkAgent.Request} request
150      */
151     _updateNetworkRequestWithRequest: function(networkRequest, request)
152     {
153         networkRequest.requestMethod = request.method;
154         networkRequest.setRequestHeaders(this._headersMapToHeadersArray(request.headers));
155         networkRequest.requestFormData = request.postData;
156     },
157
158     /**
159      * @param {!WebInspector.NetworkRequest} networkRequest
160      * @param {!NetworkAgent.Response=} response
161      */
162     _updateNetworkRequestWithResponse: function(networkRequest, response)
163     {
164         if (!response)
165             return;
166
167         if (response.url && networkRequest.url !== response.url)
168             networkRequest.url = response.url;
169         networkRequest.mimeType = response.mimeType;
170         networkRequest.statusCode = response.status;
171         networkRequest.statusText = response.statusText;
172         networkRequest.responseHeaders = this._headersMapToHeadersArray(response.headers);
173         if (response.headersText)
174             networkRequest.responseHeadersText = response.headersText;
175         if (response.requestHeaders) {
176             networkRequest.setRequestHeaders(this._headersMapToHeadersArray(response.requestHeaders));
177             networkRequest.setRequestHeadersText(response.requestHeadersText || "");
178         }
179
180         networkRequest.connectionReused = response.connectionReused;
181         networkRequest.connectionId = response.connectionId;
182
183         if (response.fromDiskCache)
184             networkRequest.cached = true;
185         else
186             networkRequest.timing = response.timing;
187
188         if (!this._mimeTypeIsConsistentWithType(networkRequest)) {
189             WebInspector.console.addMessage(WebInspector.ConsoleMessage.create(WebInspector.ConsoleMessage.MessageSource.Network,
190                 WebInspector.ConsoleMessage.MessageLevel.Log,
191                 WebInspector.UIString("Resource interpreted as %s but transferred with MIME type %s: \"%s\".", networkRequest.type.title(), networkRequest.mimeType, networkRequest.url),
192                 WebInspector.ConsoleMessage.MessageType.Log,
193                 "",
194                 0,
195                 0,
196                 1,
197                 [],
198                 undefined,
199                 networkRequest.requestId));
200         }
201     },
202
203     /**
204      * @param {!WebInspector.NetworkRequest} networkRequest
205      * @return {boolean}
206      */
207     _mimeTypeIsConsistentWithType: function(networkRequest)
208     {
209         // If status is an error, content is likely to be of an inconsistent type,
210         // as it's going to be an error message. We do not want to emit a warning
211         // for this, though, as this will already be reported as resource loading failure.
212         // Also, if a URL like http://localhost/wiki/load.php?debug=true&lang=en produces text/css and gets reloaded,
213         // it is 304 Not Modified and its guessed mime-type is text/php, which is wrong.
214         // Don't check for mime-types in 304-resources.
215         if (networkRequest.hasErrorStatusCode() || networkRequest.statusCode === 304 || networkRequest.statusCode === 204)
216             return true;
217
218         if (typeof networkRequest.type === "undefined"
219             || networkRequest.type === WebInspector.resourceTypes.Other
220             || networkRequest.type === WebInspector.resourceTypes.XHR
221             || networkRequest.type === WebInspector.resourceTypes.WebSocket)
222             return true;
223
224         if (!networkRequest.mimeType)
225             return true; // Might be not known for cached resources with null responses.
226
227         if (networkRequest.mimeType in WebInspector.NetworkManager._MIMETypes)
228             return networkRequest.type.name() in WebInspector.NetworkManager._MIMETypes[networkRequest.mimeType];
229
230         return false;
231     },
232
233     /**
234      * @param {!NetworkAgent.Response} response
235      * @return {boolean}
236      */
237     _isNull: function(response)
238     {
239         if (!response)
240             return true;
241         return !response.status && !response.mimeType && (!response.headers || !Object.keys(response.headers).length);
242     },
243
244     /**
245      * @param {!NetworkAgent.RequestId} requestId
246      * @param {!PageAgent.FrameId} frameId
247      * @param {!NetworkAgent.LoaderId} loaderId
248      * @param {string} documentURL
249      * @param {!NetworkAgent.Request} request
250      * @param {!NetworkAgent.Timestamp} time
251      * @param {!NetworkAgent.Initiator} initiator
252      * @param {!NetworkAgent.Response=} redirectResponse
253      */
254     requestWillBeSent: function(requestId, frameId, loaderId, documentURL, request, time, initiator, redirectResponse)
255     {
256         var networkRequest = this._inflightRequestsById[requestId];
257         if (networkRequest) {
258             // FIXME: move this check to the backend.
259             if (!redirectResponse)
260                 return;
261             this.responseReceived(requestId, frameId, loaderId, time, PageAgent.ResourceType.Other, redirectResponse);
262             networkRequest = this._appendRedirect(requestId, time, request.url);
263         } else
264             networkRequest = this._createNetworkRequest(requestId, frameId, loaderId, request.url, documentURL, initiator);
265         networkRequest.hasNetworkData = true;
266         this._updateNetworkRequestWithRequest(networkRequest, request);
267         networkRequest.startTime = time;
268
269         this._startNetworkRequest(networkRequest);
270     },
271
272     /**
273      * @param {!NetworkAgent.RequestId} requestId
274      */
275     requestServedFromCache: function(requestId)
276     {
277         var networkRequest = this._inflightRequestsById[requestId];
278         if (!networkRequest)
279             return;
280
281         networkRequest.cached = true;
282     },
283
284     /**
285      * @param {!NetworkAgent.RequestId} requestId
286      * @param {!PageAgent.FrameId} frameId
287      * @param {!NetworkAgent.LoaderId} loaderId
288      * @param {!NetworkAgent.Timestamp} time
289      * @param {!PageAgent.ResourceType} resourceType
290      * @param {!NetworkAgent.Response} response
291      */
292     responseReceived: function(requestId, frameId, loaderId, time, resourceType, response)
293     {
294         // FIXME: move this check to the backend.
295         if (this._isNull(response))
296             return;
297
298         var networkRequest = this._inflightRequestsById[requestId];
299         if (!networkRequest) {
300             // We missed the requestWillBeSent.
301             var eventData = {};
302             eventData.url = response.url;
303             eventData.frameId = frameId;
304             eventData.loaderId = loaderId;
305             eventData.resourceType = resourceType;
306             eventData.mimeType = response.mimeType;
307             this._manager.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, eventData);
308             return;
309         }
310
311         networkRequest.responseReceivedTime = time;
312         networkRequest.type = WebInspector.resourceTypes[resourceType];
313
314         this._updateNetworkRequestWithResponse(networkRequest, response);
315
316         this._updateNetworkRequest(networkRequest);
317     },
318
319     /**
320      * @param {!NetworkAgent.RequestId} requestId
321      * @param {!NetworkAgent.Timestamp} time
322      * @param {number} dataLength
323      * @param {number} encodedDataLength
324      */
325     dataReceived: function(requestId, time, dataLength, encodedDataLength)
326     {
327         var networkRequest = this._inflightRequestsById[requestId];
328         if (!networkRequest)
329             return;
330
331         networkRequest.resourceSize += dataLength;
332         if (encodedDataLength != -1)
333             networkRequest.increaseTransferSize(encodedDataLength);
334         networkRequest.endTime = time;
335
336         this._updateNetworkRequest(networkRequest);
337     },
338
339     /**
340      * @param {!NetworkAgent.RequestId} requestId
341      * @param {!NetworkAgent.Timestamp} finishTime
342      */
343     loadingFinished: function(requestId, finishTime)
344     {
345         var networkRequest = this._inflightRequestsById[requestId];
346         if (!networkRequest)
347             return;
348         this._finishNetworkRequest(networkRequest, finishTime);
349     },
350
351     /**
352      * @param {!NetworkAgent.RequestId} requestId
353      * @param {!NetworkAgent.Timestamp} time
354      * @param {string} localizedDescription
355      * @param {boolean=} canceled
356      */
357     loadingFailed: function(requestId, time, localizedDescription, canceled)
358     {
359         var networkRequest = this._inflightRequestsById[requestId];
360         if (!networkRequest)
361             return;
362
363         networkRequest.failed = true;
364         networkRequest.canceled = canceled;
365         networkRequest.localizedFailDescription = localizedDescription;
366         this._finishNetworkRequest(networkRequest, time);
367     },
368
369     /**
370      * @param {!NetworkAgent.RequestId} requestId
371      * @param {string} requestURL
372      */
373     webSocketCreated: function(requestId, requestURL)
374     {
375         var networkRequest = new WebInspector.NetworkRequest(requestId, requestURL, "", "", "");
376         networkRequest.type = WebInspector.resourceTypes.WebSocket;
377         this._startNetworkRequest(networkRequest);
378     },
379
380     /**
381      * @param {!NetworkAgent.RequestId} requestId
382      * @param {!NetworkAgent.Timestamp} time
383      * @param {!NetworkAgent.WebSocketRequest} request
384      */
385     webSocketWillSendHandshakeRequest: function(requestId, time, request)
386     {
387         var networkRequest = this._inflightRequestsById[requestId];
388         if (!networkRequest)
389             return;
390
391         networkRequest.requestMethod = "GET";
392         networkRequest.setRequestHeaders(this._headersMapToHeadersArray(request.headers));
393         networkRequest.startTime = time;
394
395         this._updateNetworkRequest(networkRequest);
396     },
397
398     /**
399      * @param {!NetworkAgent.RequestId} requestId
400      * @param {!NetworkAgent.Timestamp} time
401      * @param {!NetworkAgent.WebSocketResponse} response
402      */
403     webSocketHandshakeResponseReceived: function(requestId, time, response)
404     {
405         var networkRequest = this._inflightRequestsById[requestId];
406         if (!networkRequest)
407             return;
408
409         networkRequest.statusCode = response.status;
410         networkRequest.statusText = response.statusText;
411         networkRequest.responseHeaders = this._headersMapToHeadersArray(response.headers);
412         networkRequest.responseReceivedTime = time;
413
414         this._updateNetworkRequest(networkRequest);
415     },
416
417     /**
418      * @param {!NetworkAgent.RequestId} requestId
419      * @param {!NetworkAgent.Timestamp} time
420      * @param {!NetworkAgent.WebSocketFrame} response
421      */
422     webSocketFrameReceived: function(requestId, time, response)
423     {
424         var networkRequest = this._inflightRequestsById[requestId];
425         if (!networkRequest)
426             return;
427
428         networkRequest.addFrame(response, time);
429         networkRequest.responseReceivedTime = time;
430
431         this._updateNetworkRequest(networkRequest);
432     },
433
434     /**
435      * @param {!NetworkAgent.RequestId} requestId
436      * @param {!NetworkAgent.Timestamp} time
437      * @param {!NetworkAgent.WebSocketFrame} response
438      */
439     webSocketFrameSent: function(requestId, time, response)
440     {
441         var networkRequest = this._inflightRequestsById[requestId];
442         if (!networkRequest)
443             return;
444
445         networkRequest.addFrame(response, time, true);
446         networkRequest.responseReceivedTime = time;
447
448         this._updateNetworkRequest(networkRequest);
449     },
450
451     /**
452      * @param {!NetworkAgent.RequestId} requestId
453      * @param {!NetworkAgent.Timestamp} time
454      * @param {string} errorMessage
455      */
456     webSocketFrameError: function(requestId, time, errorMessage)
457     {
458         var networkRequest = this._inflightRequestsById[requestId];
459         if (!networkRequest)
460             return;
461
462         networkRequest.addFrameError(errorMessage, time);
463         networkRequest.responseReceivedTime = time;
464
465         this._updateNetworkRequest(networkRequest);
466     },
467
468     /**
469      * @param {!NetworkAgent.RequestId} requestId
470      * @param {!NetworkAgent.Timestamp} time
471      */
472     webSocketClosed: function(requestId, time)
473     {
474         var networkRequest = this._inflightRequestsById[requestId];
475         if (!networkRequest)
476             return;
477         this._finishNetworkRequest(networkRequest, time);
478     },
479
480     /**
481      * @param {!NetworkAgent.RequestId} requestId
482      * @param {!NetworkAgent.Timestamp} time
483      * @param {string} redirectURL
484      * @return {!WebInspector.NetworkRequest}
485      */
486     _appendRedirect: function(requestId, time, redirectURL)
487     {
488         var originalNetworkRequest = this._inflightRequestsById[requestId];
489         var previousRedirects = originalNetworkRequest.redirects || [];
490         originalNetworkRequest.requestId = "redirected:" + requestId + "." + previousRedirects.length;
491         delete originalNetworkRequest.redirects;
492         if (previousRedirects.length > 0)
493             originalNetworkRequest.redirectSource = previousRedirects[previousRedirects.length - 1];
494         this._finishNetworkRequest(originalNetworkRequest, time);
495         var newNetworkRequest = this._createNetworkRequest(requestId, originalNetworkRequest.frameId, originalNetworkRequest.loaderId,
496              redirectURL, originalNetworkRequest.documentURL, originalNetworkRequest.initiator);
497         newNetworkRequest.redirects = previousRedirects.concat(originalNetworkRequest);
498         return newNetworkRequest;
499     },
500
501     /**
502      * @param {!WebInspector.NetworkRequest} networkRequest
503      */
504     _startNetworkRequest: function(networkRequest)
505     {
506         this._inflightRequestsById[networkRequest.requestId] = networkRequest;
507         this._inflightRequestsByURL[networkRequest.url] = networkRequest;
508         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestStarted, networkRequest);
509     },
510
511     /**
512      * @param {!WebInspector.NetworkRequest} networkRequest
513      */
514     _updateNetworkRequest: function(networkRequest)
515     {
516         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdated, networkRequest);
517     },
518
519     /**
520      * @param {!WebInspector.NetworkRequest} networkRequest
521      * @param {!NetworkAgent.Timestamp} finishTime
522      */
523     _finishNetworkRequest: function(networkRequest, finishTime)
524     {
525         networkRequest.endTime = finishTime;
526         networkRequest.finished = true;
527         this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestFinished, networkRequest);
528         delete this._inflightRequestsById[networkRequest.requestId];
529         delete this._inflightRequestsByURL[networkRequest.url];
530     },
531
532     /**
533      * @param {string} eventType
534      * @param {!WebInspector.NetworkRequest} networkRequest
535      */
536     _dispatchEventToListeners: function(eventType, networkRequest)
537     {
538         this._manager.dispatchEventToListeners(eventType, networkRequest);
539     },
540
541     /**
542      * @param {!NetworkAgent.RequestId} requestId
543      * @param {string} frameId
544      * @param {!NetworkAgent.LoaderId} loaderId
545      * @param {string} url
546      * @param {string} documentURL
547      * @param {!NetworkAgent.Initiator} initiator
548      */
549     _createNetworkRequest: function(requestId, frameId, loaderId, url, documentURL, initiator)
550     {
551         var networkRequest = new WebInspector.NetworkRequest(requestId, url, documentURL, frameId, loaderId);
552         networkRequest.initiator = initiator;
553         return networkRequest;
554     }
555 }
556
557 /**
558  * @type {!WebInspector.NetworkManager}
559  */
560 WebInspector.networkManager;