tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / inspector / front-end / HAREntry.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 // See http://groups.google.com/group/http-archive-specification/web/har-1-2-spec
32 // for HAR specification.
33
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.
36
37 /**
38  * @constructor
39  */
40 WebInspector.HAREntry = function(resource)
41 {
42     this._resource = resource;
43 }
44
45 WebInspector.HAREntry.prototype = {
46     build: function()
47     {
48         return {
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()
56         };
57     },
58
59     _buildRequest: function()
60     {
61         var res = {
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
70         };
71         if (this._resource.requestFormData)
72             res.postData = this._buildPostData();
73
74         return res;
75     },
76
77     _buildResponse: function()
78     {
79         return {
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
89         };
90     },
91
92     _buildContent: function()
93     {
94         return {
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)
99         };
100     },
101
102     _buildTimings: function()
103     {
104         var waitForConnection = this._interval("connectStart", "connectEnd");
105         var blocked;
106         var connect;
107         var dns = this._interval("dnsStart", "dnsEnd");
108         var send = this._interval("sendStart", "sendEnd");
109         var ssl = this._interval("sslStart", "sslEnd");
110
111         if (ssl !== -1 && send !== -1)
112             send -= ssl;
113
114         if (this._resource.connectionReused) {
115             connect = -1;
116             blocked = waitForConnection;
117         } else {
118             blocked = 0;
119             connect = waitForConnection;
120             if (dns !== -1)
121                 connect -= dns;
122         }
123
124         return {
125             blocked: blocked,
126             dns: dns,
127             connect: connect,
128             send: send,
129             wait: this._interval("sendEnd", "receiveHeadersEnd"),
130             receive: WebInspector.HAREntry._toMilliseconds(this._resource.receiveDuration),
131             ssl: ssl
132         };
133     },
134
135     _buildHeaders: function(headers)
136     {
137         var result = [];
138         for (var name in headers)
139             result.push({ name: name, value: headers[name] });
140         return result;
141     },
142
143     _buildPostData: function()
144     {
145         var res = {
146             mimeType: this._resource.requestHeaderValue("Content-Type"),
147             text: this._resource.requestFormData
148         };
149         if (this._resource.formParameters)
150            res.params = this._buildParameters(this._resource.formParameters);
151         return res;
152     },
153
154     _buildParameters: function(parameters)
155     {
156         return parameters.slice();
157     },
158
159     _buildRequestURL: function(url)
160     {
161         return url.split("#", 2)[0];
162     },
163
164     _buildCookies: function(cookies)
165     {
166         return cookies.map(this._buildCookie.bind(this));
167     },
168
169     _buildCookie: function(cookie)
170     {
171         return {
172             name: cookie.name,
173             value: cookie.value,
174             path: cookie.path,
175             domain: cookie.domain,
176             expires: cookie.expires(new Date(this._resource.startTime * 1000)),
177             httpOnly: cookie.httpOnly,
178             secure: cookie.secure
179         };
180     },
181
182     _interval: function(start, end)
183     {
184         var timing = this._resource.timing;
185         if (!timing)
186             return -1;
187         var startTime = timing[start];
188         return typeof startTime !== "number" || startTime === -1 ? -1 : Math.round(timing[end] - startTime);
189     },
190
191     get requestBodySize()
192     {
193         return !this._resource.requestFormData ? 0 : this._resource.requestFormData.length;
194     },
195
196     get responseBodySize()
197     {
198         return this._resource.transferSize - this._resource.responseHeadersSize
199     },
200
201     get responseCompression()
202     {
203         return this._resource.resourceSize - (this._resource.transferSize - this._resource.responseHeadersSize);
204     }
205 }
206
207 WebInspector.HAREntry._toMilliseconds = function(time)
208 {
209     return time === -1 ? -1 : Math.round(time * 1000);
210 }
211
212 /**
213  * @constructor
214  */
215 WebInspector.HARLog = function(resources)
216 {
217     this._resources = resources;
218 }
219
220 WebInspector.HARLog.prototype = {
221     build: function()
222     {
223         var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
224
225         return {
226             version: "1.2",
227             creator: {
228                 name: "WebInspector",
229                 version: webKitVersion ? webKitVersion[1] : "n/a"
230             },
231             pages: this._buildPages(),
232             entries: this._resources.map(this._convertResource.bind(this))
233         }
234     },
235
236     _buildPages: function()
237     {
238         return [
239             {
240                 startedDateTime: new Date(WebInspector.mainResourceStartTime * 1000),
241                 id: WebInspector.inspectedPageURL,
242                 title: "",
243                 pageTimings: this.buildMainResourceTimings()
244             }
245         ];
246     },
247
248     buildMainResourceTimings: function()
249     {
250         return {
251              onContentLoad: this._pageEventTime(WebInspector.mainResourceDOMContentTime),
252              onLoad: this._pageEventTime(WebInspector.mainResourceLoadTime),
253         }
254     },
255
256     _convertResource: function(resource)
257     {
258         return (new WebInspector.HAREntry(resource)).build();
259     },
260
261     _pageEventTime: function(time)
262     {
263         var startTime = WebInspector.mainResourceStartTime;
264         if (time === -1 || startTime === -1)
265             return -1;
266         return WebInspector.HAREntry._toMilliseconds(time - startTime);
267     }
268 }