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