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.
31 // See http://groups.google.com/group/http-archive-specification/web/har-1-2-spec
32 // for HAR specification.
34 // FIXME: Some fields are not yet supported due to back-end limitations.
35 // See https://bugs.webkit.org/show_bug.cgi?id=58127 for details.
40 WebInspector.HAREntry = function(resource)
42 this._resource = resource;
45 WebInspector.HAREntry.prototype = {
49 pageref: this._resource.documentURL,
50 startedDateTime: new Date(this._resource.startTime * 1000),
51 time: WebInspector.HAREntry._toMilliseconds(this._resource.duration),
52 request: this._buildRequest(),
53 response: this._buildResponse(),
54 cache: { }, // Not supported yet.
55 timings: this._buildTimings()
59 _buildRequest: function()
62 method: this._resource.requestMethod,
63 url: this._buildRequestURL(this._resource.url),
64 httpVersion: this._resource.requestHttpVersion,
65 headers: this._buildHeaders(this._resource.requestHeaders),
66 queryString: this._buildParameters(this._resource.queryParameters || []),
67 cookies: this._buildCookies(this._resource.requestCookies || []),
68 headersSize: this._resource.requestHeadersSize,
69 bodySize: this.requestBodySize
71 if (this._resource.requestFormData)
72 res.postData = this._buildPostData();
77 _buildResponse: function()
80 status: this._resource.statusCode,
81 statusText: this._resource.statusText,
82 httpVersion: this._resource.responseHttpVersion,
83 headers: this._buildHeaders(this._resource.responseHeaders),
84 cookies: this._buildCookies(this._resource.responseCookies || []),
85 content: this._buildContent(),
86 redirectURL: this._resource.responseHeaderValue("Location") || "",
87 headersSize: this._resource.responseHeadersSize,
88 bodySize: this.responseBodySize
92 _buildContent: function()
95 size: this._resource.resourceSize,
96 compression: this.responseCompression,
97 mimeType: this._resource.mimeType,
98 // text: this._resource.content // TODO: pull out into a boolean flag, as content can be huge (and needs to be requested with an async call)
102 _buildTimings: function()
104 var waitForConnection = this._interval("connectStart", "connectEnd");
107 var dns = this._interval("dnsStart", "dnsEnd");
108 var send = this._interval("sendStart", "sendEnd");
109 var ssl = this._interval("sslStart", "sslEnd");
111 if (ssl !== -1 && send !== -1)
114 if (this._resource.connectionReused) {
116 blocked = waitForConnection;
119 connect = waitForConnection;
129 wait: this._interval("sendEnd", "receiveHeadersEnd"),
130 receive: WebInspector.HAREntry._toMilliseconds(this._resource.receiveDuration),
135 _buildHeaders: function(headers)
138 for (var name in headers)
139 result.push({ name: name, value: headers[name] });
143 _buildPostData: function()
146 mimeType: this._resource.requestHeaderValue("Content-Type"),
147 text: this._resource.requestFormData
149 if (this._resource.formParameters)
150 res.params = this._buildParameters(this._resource.formParameters);
154 _buildParameters: function(parameters)
156 return parameters.slice();
159 _buildRequestURL: function(url)
161 return url.split("#", 2)[0];
164 _buildCookies: function(cookies)
166 return cookies.map(this._buildCookie.bind(this));
169 _buildCookie: function(cookie)
175 domain: cookie.domain,
176 expires: cookie.expires(new Date(this._resource.startTime * 1000)),
177 httpOnly: cookie.httpOnly,
178 secure: cookie.secure
182 _interval: function(start, end)
184 var timing = this._resource.timing;
187 var startTime = timing[start];
188 return typeof startTime !== "number" || startTime === -1 ? -1 : Math.round(timing[end] - startTime);
191 get requestBodySize()
193 return !this._resource.requestFormData ? 0 : this._resource.requestFormData.length;
196 get responseBodySize()
198 return this._resource.transferSize - this._resource.responseHeadersSize
201 get responseCompression()
203 return this._resource.resourceSize - (this._resource.transferSize - this._resource.responseHeadersSize);
207 WebInspector.HAREntry._toMilliseconds = function(time)
209 return time === -1 ? -1 : Math.round(time * 1000);
215 WebInspector.HARLog = function(resources)
217 this._resources = resources;
220 WebInspector.HARLog.prototype = {
223 var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
228 name: "WebInspector",
229 version: webKitVersion ? webKitVersion[1] : "n/a"
231 pages: this._buildPages(),
232 entries: this._resources.map(this._convertResource.bind(this))
236 _buildPages: function()
240 startedDateTime: new Date(WebInspector.mainResourceStartTime * 1000),
241 id: WebInspector.inspectedPageURL,
243 pageTimings: this.buildMainResourceTimings()
248 buildMainResourceTimings: function()
251 onContentLoad: this._pageEventTime(WebInspector.mainResourceDOMContentTime),
252 onLoad: this._pageEventTime(WebInspector.mainResourceLoadTime),
256 _convertResource: function(resource)
258 return (new WebInspector.HAREntry(resource)).build();
261 _pageEventTime: function(time)
263 var startTime = WebInspector.mainResourceStartTime;
264 if (time === -1 || startTime === -1)
266 return WebInspector.HAREntry._toMilliseconds(time - startTime);