2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @extends {WebInspector.TargetAwareObject}
34 * @param {!WebInspector.Target} target
36 WebInspector.NetworkManager = function(target)
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);
46 this._networkAgent.enable();
48 WebInspector.settings.cacheDisabled.addChangeListener(this._cacheDisabledSettingChanged, this);
51 WebInspector.NetworkManager.EventTypes = {
52 RequestStarted: "RequestStarted",
53 RequestUpdated: "RequestUpdated",
54 RequestFinished: "RequestFinished",
55 RequestUpdateDropped: "RequestUpdateDropped"
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},
102 WebInspector.NetworkManager.prototype = {
104 * @param {string} url
105 * @return {!WebInspector.NetworkRequest}
107 inflightRequestForURL: function(url)
109 return this._dispatcher._inflightRequestsByURL[url];
113 * @param {!WebInspector.Event} event
115 _cacheDisabledSettingChanged: function(event)
117 var enabled = /** @type {boolean} */ (event.data);
118 this._networkAgent.setCacheDisabled(enabled);
121 __proto__: WebInspector.TargetAwareObject.prototype
126 * @implements {NetworkAgent.Dispatcher}
128 WebInspector.NetworkDispatcher = function(manager)
130 this._manager = manager;
131 this._inflightRequestsById = {};
132 this._inflightRequestsByURL = {};
135 WebInspector.NetworkDispatcher.prototype = {
137 * @param {!NetworkAgent.Headers} headersMap
138 * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
140 _headersMapToHeadersArray: function(headersMap)
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]});
152 * @param {!WebInspector.NetworkRequest} networkRequest
153 * @param {!NetworkAgent.Request} request
155 _updateNetworkRequestWithRequest: function(networkRequest, request)
157 networkRequest.requestMethod = request.method;
158 networkRequest.setRequestHeaders(this._headersMapToHeadersArray(request.headers));
159 networkRequest.requestFormData = request.postData;
163 * @param {!WebInspector.NetworkRequest} networkRequest
164 * @param {!NetworkAgent.Response=} response
166 _updateNetworkRequestWithResponse: function(networkRequest, response)
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 || "");
183 networkRequest.connectionReused = response.connectionReused;
184 networkRequest.connectionId = response.connectionId;
185 if (response.remoteIPAddress)
186 networkRequest.setRemoteAddress(response.remoteIPAddress, response.remotePort || -1);
188 if (response.fromDiskCache)
189 networkRequest.cached = true;
191 networkRequest.timing = response.timing;
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,
202 networkRequest.requestId));
207 * @param {!WebInspector.NetworkRequest} networkRequest
210 _mimeTypeIsConsistentWithType: function(networkRequest)
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)
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)
228 if (!networkRequest.mimeType)
229 return true; // Might be not known for cached resources with null responses.
231 if (networkRequest.mimeType in WebInspector.NetworkManager._MIMETypes)
232 return networkRequest.type.name() in WebInspector.NetworkManager._MIMETypes[networkRequest.mimeType];
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
247 requestWillBeSent: function(requestId, frameId, loaderId, documentURL, request, time, initiator, redirectResponse)
249 var networkRequest = this._inflightRequestsById[requestId];
250 if (networkRequest) {
251 // FIXME: move this check to the backend.
252 if (!redirectResponse)
254 this.responseReceived(requestId, frameId, loaderId, time, PageAgent.ResourceType.Other, redirectResponse);
255 networkRequest = this._appendRedirect(requestId, time, request.url);
257 networkRequest = this._createNetworkRequest(requestId, frameId, loaderId, request.url, documentURL, initiator);
258 networkRequest.hasNetworkData = true;
259 this._updateNetworkRequestWithRequest(networkRequest, request);
260 networkRequest.startTime = time;
262 this._startNetworkRequest(networkRequest);
266 * @param {!NetworkAgent.RequestId} requestId
268 requestServedFromCache: function(requestId)
270 var networkRequest = this._inflightRequestsById[requestId];
274 networkRequest.cached = true;
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
285 responseReceived: function(requestId, frameId, loaderId, time, resourceType, response)
287 var networkRequest = this._inflightRequestsById[requestId];
288 if (!networkRequest) {
289 // We missed the requestWillBeSent.
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);
300 networkRequest.responseReceivedTime = time;
301 networkRequest.type = WebInspector.resourceTypes[resourceType];
303 this._updateNetworkRequestWithResponse(networkRequest, response);
305 this._updateNetworkRequest(networkRequest);
309 * @param {!NetworkAgent.RequestId} requestId
310 * @param {!NetworkAgent.Timestamp} time
311 * @param {number} dataLength
312 * @param {number} encodedDataLength
314 dataReceived: function(requestId, time, dataLength, encodedDataLength)
316 var networkRequest = this._inflightRequestsById[requestId];
320 networkRequest.resourceSize += dataLength;
321 if (encodedDataLength != -1)
322 networkRequest.increaseTransferSize(encodedDataLength);
323 networkRequest.endTime = time;
325 this._updateNetworkRequest(networkRequest);
329 * @param {!NetworkAgent.RequestId} requestId
330 * @param {!NetworkAgent.Timestamp} finishTime
331 * @param {number} encodedDataLength
333 loadingFinished: function(requestId, finishTime, encodedDataLength)
335 var networkRequest = this._inflightRequestsById[requestId];
338 this._finishNetworkRequest(networkRequest, finishTime, encodedDataLength);
342 * @param {!NetworkAgent.RequestId} requestId
343 * @param {!NetworkAgent.Timestamp} time
344 * @param {string} localizedDescription
345 * @param {boolean=} canceled
347 loadingFailed: function(requestId, time, localizedDescription, canceled)
349 var networkRequest = this._inflightRequestsById[requestId];
353 networkRequest.failed = true;
354 networkRequest.canceled = canceled;
355 networkRequest.localizedFailDescription = localizedDescription;
356 this._finishNetworkRequest(networkRequest, time, -1);
360 * @param {!NetworkAgent.RequestId} requestId
361 * @param {string} requestURL
363 webSocketCreated: function(requestId, requestURL)
365 var networkRequest = new WebInspector.NetworkRequest(this._manager._target, requestId, requestURL, "", "", "");
366 networkRequest.type = WebInspector.resourceTypes.WebSocket;
367 this._startNetworkRequest(networkRequest);
371 * @param {!NetworkAgent.RequestId} requestId
372 * @param {!NetworkAgent.Timestamp} time
373 * @param {!NetworkAgent.WebSocketRequest} request
375 webSocketWillSendHandshakeRequest: function(requestId, time, request)
377 var networkRequest = this._inflightRequestsById[requestId];
381 networkRequest.requestMethod = "GET";
382 networkRequest.setRequestHeaders(this._headersMapToHeadersArray(request.headers));
383 networkRequest.startTime = time;
385 this._updateNetworkRequest(networkRequest);
389 * @param {!NetworkAgent.RequestId} requestId
390 * @param {!NetworkAgent.Timestamp} time
391 * @param {!NetworkAgent.WebSocketResponse} response
393 webSocketHandshakeResponseReceived: function(requestId, time, response)
395 var networkRequest = this._inflightRequestsById[requestId];
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;
409 this._updateNetworkRequest(networkRequest);
413 * @param {!NetworkAgent.RequestId} requestId
414 * @param {!NetworkAgent.Timestamp} time
415 * @param {!NetworkAgent.WebSocketFrame} response
417 webSocketFrameReceived: function(requestId, time, response)
419 var networkRequest = this._inflightRequestsById[requestId];
423 networkRequest.addFrame(response, time);
424 networkRequest.responseReceivedTime = time;
426 this._updateNetworkRequest(networkRequest);
430 * @param {!NetworkAgent.RequestId} requestId
431 * @param {!NetworkAgent.Timestamp} time
432 * @param {!NetworkAgent.WebSocketFrame} response
434 webSocketFrameSent: function(requestId, time, response)
436 var networkRequest = this._inflightRequestsById[requestId];
440 networkRequest.addFrame(response, time, true);
441 networkRequest.responseReceivedTime = time;
443 this._updateNetworkRequest(networkRequest);
447 * @param {!NetworkAgent.RequestId} requestId
448 * @param {!NetworkAgent.Timestamp} time
449 * @param {string} errorMessage
451 webSocketFrameError: function(requestId, time, errorMessage)
453 var networkRequest = this._inflightRequestsById[requestId];
457 networkRequest.addFrameError(errorMessage, time);
458 networkRequest.responseReceivedTime = time;
460 this._updateNetworkRequest(networkRequest);
464 * @param {!NetworkAgent.RequestId} requestId
465 * @param {!NetworkAgent.Timestamp} time
467 webSocketClosed: function(requestId, time)
469 var networkRequest = this._inflightRequestsById[requestId];
472 this._finishNetworkRequest(networkRequest, time, -1);
476 * @param {!NetworkAgent.RequestId} requestId
477 * @param {!NetworkAgent.Timestamp} time
478 * @param {string} redirectURL
479 * @return {!WebInspector.NetworkRequest}
481 _appendRedirect: function(requestId, time, redirectURL)
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;
497 * @param {!WebInspector.NetworkRequest} networkRequest
499 _startNetworkRequest: function(networkRequest)
501 this._inflightRequestsById[networkRequest.requestId] = networkRequest;
502 this._inflightRequestsByURL[networkRequest.url] = networkRequest;
503 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestStarted, networkRequest);
507 * @param {!WebInspector.NetworkRequest} networkRequest
509 _updateNetworkRequest: function(networkRequest)
511 this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdated, networkRequest);
515 * @param {!WebInspector.NetworkRequest} networkRequest
516 * @param {!NetworkAgent.Timestamp} finishTime
517 * @param {number} encodedDataLength
519 _finishNetworkRequest: function(networkRequest, finishTime, encodedDataLength)
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];
531 * @param {string} eventType
532 * @param {!WebInspector.NetworkRequest} networkRequest
534 _dispatchEventToListeners: function(eventType, networkRequest)
536 this._manager.dispatchEventToListeners(eventType, networkRequest);
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
547 _createNetworkRequest: function(requestId, frameId, loaderId, url, documentURL, initiator)
549 var networkRequest = new WebInspector.NetworkRequest(this._manager._target, requestId, url, documentURL, frameId, loaderId);
550 networkRequest.initiator = initiator;
551 return networkRequest;
556 * @type {!WebInspector.NetworkManager}
558 WebInspector.networkManager;