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.
37 WebInspector.HAREntry = function(resource)
39 this._resource = resource;
42 WebInspector.HAREntry.prototype = {
46 pageref: this._resource.documentURL,
47 startedDateTime: new Date(this._resource.startTime * 1000),
48 time: WebInspector.HAREntry._toMilliseconds(this._resource.duration),
49 request: this._buildRequest(),
50 response: this._buildResponse(),
51 cache: { }, // Not supported yet.
52 timings: this._buildTimings()
56 _buildRequest: function()
59 method: this._resource.requestMethod,
60 url: this._buildRequestURL(this._resource.url),
61 httpVersion: this._resource.requestHttpVersion,
62 headers: this._buildHeaders(this._resource.requestHeaders),
63 queryString: this._buildParameters(this._resource.queryParameters || []),
64 cookies: this._buildCookies(this._resource.requestCookies || []),
65 headersSize: this._resource.requestHeadersSize,
66 bodySize: this.requestBodySize
68 if (this._resource.requestFormData)
69 res.postData = this._buildPostData();
74 _buildResponse: function()
77 status: this._resource.statusCode,
78 statusText: this._resource.statusText,
79 httpVersion: this._resource.responseHttpVersion,
80 headers: this._buildHeaders(this._resource.responseHeaders),
81 cookies: this._buildCookies(this._resource.responseCookies || []),
82 content: this._buildContent(),
83 redirectURL: this._resource.responseHeaderValue("Location") || "",
84 headersSize: this._resource.responseHeadersSize,
85 bodySize: this.responseBodySize
89 _buildContent: function()
92 size: this._resource.resourceSize,
93 compression: this.responseCompression,
94 mimeType: this._resource.mimeType,
95 // 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)
99 _buildTimings: function()
101 var waitForConnection = this._interval("connectStart", "connectEnd");
104 var dns = this._interval("dnsStart", "dnsEnd");
105 var send = this._interval("sendStart", "sendEnd");
106 var ssl = this._interval("sslStart", "sslEnd");
108 if (ssl !== -1 && send !== -1)
111 if (this._resource.connectionReused) {
113 blocked = waitForConnection;
116 connect = waitForConnection;
126 wait: this._interval("sendEnd", "receiveHeadersEnd"),
127 receive: WebInspector.HAREntry._toMilliseconds(this._resource.receiveDuration),
132 _buildHeaders: function(headers)
135 for (var name in headers)
136 result.push({ name: name, value: headers[name] });
140 _buildPostData: function()
143 mimeType: this._resource.requestHeaderValue("Content-Type"),
144 text: this._resource.requestFormData
146 if (this._resource.formParameters)
147 res.params = this._buildParameters(this._resource.formParameters);
151 _buildParameters: function(parameters)
153 return parameters.slice();
156 _buildRequestURL: function(url)
158 return url.split("#", 2)[0];
161 _buildCookies: function(cookies)
163 return cookies.map(this._buildCookie.bind(this));
166 _buildCookie: function(cookie)
172 domain: cookie.domain,
173 expires: cookie.expires(new Date(this._resource.startTime * 1000)),
174 httpOnly: cookie.httpOnly,
175 secure: cookie.secure
179 _interval: function(start, end)
181 var timing = this._resource.timing;
184 var startTime = timing[start];
185 return typeof startTime !== "number" || startTime === -1 ? -1 : Math.round(timing[end] - startTime);
188 get requestBodySize()
190 return !this._resource.requestFormData ? 0 : this._resource.requestFormData.length;
193 get responseBodySize()
195 return this._resource.transferSize - this._resource.responseHeadersSize
198 get responseCompression()
200 return this._resource.resourceSize - (this._resource.transferSize - this._resource.responseHeadersSize);
204 WebInspector.HAREntry._toMilliseconds = function(time)
206 return time === -1 ? -1 : Math.round(time * 1000);
209 WebInspector.HARLog = function(resources)
211 this._resources = resources;
214 WebInspector.HARLog.prototype = {
217 var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
222 name: "WebInspector",
223 version: webKitVersion ? webKitVersion[1] : "n/a"
225 pages: this._buildPages(),
226 entries: this._resources.map(this._convertResource.bind(this))
230 _buildPages: function()
234 startedDateTime: new Date(WebInspector.mainResource.startTime * 1000),
235 id: WebInspector.mainResource.documentURL,
237 pageTimings: this.buildMainResourceTimings()
242 buildMainResourceTimings: function()
245 onContentLoad: this._pageEventTime(WebInspector.mainResourceDOMContentTime),
246 onLoad: this._pageEventTime(WebInspector.mainResourceLoadTime),
250 _convertResource: function(resource)
252 return (new WebInspector.HAREntry(resource)).build();
255 _pageEventTime: function(time)
257 var startTime = WebInspector.mainResource.startTime;
258 if (time === -1 || startTime === -1)
260 return WebInspector.HAREntry._toMilliseconds(time - startTime);