15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)// See http://www.softwareishard.com/blog/har-12-spec/
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// for HAR specification.
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// FIXME: Some fields are not yet supported due to back-end limitations.
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// See https://bugs.webkit.org/show_bug.cgi?id=58127 for details.
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
39a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!WebInspector.NetworkRequest} request
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HAREntry = function(request)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._request = request;
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HAREntry.prototype = {
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
48a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    build: function()
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
529bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var entry = {
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            startedDateTime: new Date(this._request.startTime * 1000),
549bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            time: this._request.timing ? WebInspector.HAREntry._toMilliseconds(this._request.duration) : 0,
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            request: this._buildRequest(),
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            response: this._buildResponse(),
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cache: { }, // Not supported yet.
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            timings: this._buildTimings()
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
609bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        if (this._request.connectionId !== "0")
627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci            entry.connection = this._request.connectionId;
63a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        var page = this._request.target().networkLog.pageLoadForRequest(this._request);
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (page)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entry.pageref = "page_" + page.id;
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return entry;
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
70a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildRequest: function()
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
74f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)        var headersText = this._request.requestHeadersText();
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var res = {
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            method: this._request.requestMethod,
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            url: this._buildRequestURL(this._request.url),
78f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)            httpVersion: this._request.requestHttpVersion(),
79f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)            headers: this._request.requestHeaders(),
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            queryString: this._buildParameters(this._request.queryParameters || []),
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cookies: this._buildCookies(this._request.requestCookies || []),
82f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)            headersSize: headersText ? headersText.length : -1,
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            bodySize: this.requestBodySize
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this._request.requestFormData)
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            res.postData = this._buildPostData();
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return res;
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
92a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildResponse: function()
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
96d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        var headersText = this._request.responseHeadersText;
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return {
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            status: this._request.statusCode,
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            statusText: this._request.statusText,
100197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            httpVersion: this._request.responseHttpVersion(),
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            headers: this._request.responseHeaders,
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            cookies: this._buildCookies(this._request.responseCookies || []),
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            content: this._buildContent(),
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            redirectURL: this._request.responseHeaderValue("Location") || "",
105d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            headersSize: headersText ? headersText.length : -1,
106d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            bodySize: this.responseBodySize,
107d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            _error: this._request.localizedFailDescription
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
112a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildContent: function()
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var content = {
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            size: this._request.resourceSize,
118d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            mimeType: this._request.mimeType || "x-unknown",
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // text: this._request.content // TODO: pull out into a boolean flag, as content can be huge (and needs to be requested with an async call)
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var compression = this.responseCompression;
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (typeof compression === "number")
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            content.compression = compression;
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return content;
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
128a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildTimings: function()
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1329bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        // Order of events: request_start = 0, [proxy], [dns], [connect [ssl]], [send], receive_headers_end
1339bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        // HAR 'blocked' time is time before first network activity.
1349bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
1359bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var timing = this._request.timing;
1369bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        if (!timing)
1379bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            return {blocked: -1, dns: -1, connect: -1, send: 0, wait: 0, receive: 0, ssl: -1};
1389bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
1399bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        function firstNonNegative(values)
1409bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        {
1419bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            for (var i = 0; i < values.length; ++i) {
1429bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)                if (values[i] >= 0)
1439bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)                    return values[i];
1449bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            }
1459bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            console.assert(false, "Incomplete requet timing information.");
1469bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        }
1479bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
1489bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var blocked = firstNonNegative([timing.dnsStart, timing.connectStart, timing.sendStart]);
1499bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
1509bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var dns = -1;
1519bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        if (timing.dnsStart >= 0)
1529bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            dns = firstNonNegative([timing.connectStart, timing.sendStart]) - timing.dnsStart;
1539bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
15493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        var connect = -1;
1559bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        if (timing.connectStart >= 0)
1569bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            connect = timing.sendStart - timing.connectStart;
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1589bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var send = timing.sendEnd - timing.sendStart;
1599bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var wait = timing.receiveHeadersEnd - timing.sendEnd;
1609bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var receive = WebInspector.HAREntry._toMilliseconds(this._request.duration) - timing.receiveHeadersEnd;
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1629bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        var ssl = -1;
1639bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        if (timing.sslStart >= 0 && timing.sslEnd >= 0)
1649bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)            ssl = timing.sslEnd - timing.sslStart;
1659bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)
1669bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)        return {blocked: blocked, dns: dns, connect: connect, send: send, wait: wait, receive: receive, ssl: ssl};
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
170a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildPostData: function()
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var res = {
175f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)            mimeType: this._request.requestContentType(),
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            text: this._request.requestFormData
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this._request.formParameters)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            res.params = this._buildParameters(this._request.formParameters);
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return res;
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
184a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!Array.<!Object>} parameters
185a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<!Object>}
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildParameters: function(parameters)
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return parameters.slice();
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {string} url
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @return {string}
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildRequestURL: function(url)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return url.split("#", 2)[0];
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
202a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!Array.<!WebInspector.Cookie>} cookies
203a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<!Object>}
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildCookies: function(cookies)
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return cookies.map(this._buildCookie.bind(this));
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
211a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.Cookie} cookie
212a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildCookie: function(cookie)
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return {
217926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            name: cookie.name(),
218926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            value: cookie.value(),
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            path: cookie.path(),
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            domain: cookie.domain(),
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            expires: cookie.expiresDate(new Date(this._request.startTime * 1000)),
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            httpOnly: cookie.httpOnly(),
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            secure: cookie.secure()
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @return {number}
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    get requestBodySize()
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return !this._request.requestFormData ? 0 : this._request.requestFormData.length;
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @return {number}
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    get responseBodySize()
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this._request.cached || this._request.statusCode === 304)
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return 0;
242d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (!this._request.responseHeadersText)
243d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return -1;
244d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return this._request.transferSize - this._request.responseHeadersText.length;
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @return {number|undefined}
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    get responseCompression()
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2525267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        if (this._request.cached || this._request.statusCode === 304 || this._request.statusCode === 206)
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
254d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (!this._request.responseHeadersText)
255d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return;
2565267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        return this._request.resourceSize - this.responseBodySize;
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @param {number} time
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @return {number}
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HAREntry._toMilliseconds = function(time)
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2669bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles)    return time === -1 ? -1 : time * 1000;
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
271a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) * @param {!Array.<!WebInspector.NetworkRequest>} requests
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HARLog = function(requests)
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    this._requests = requests;
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HARLog.prototype = {
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
280a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    build: function()
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return {
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            version: "1.2",
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            creator: this._creator(),
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            pages: this._buildPages(),
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entries: this._requests.map(this._convertResource.bind(this))
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _creator: function()
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return {
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            name: "WebInspector",
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            version: webKitVersion ? webKitVersion[1] : "n/a"
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        };
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
303a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Array.<!Object>}
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _buildPages: function()
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var seenIdentifiers = {};
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var pages = [];
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < this._requests.length; ++i) {
310a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch            var page = this._requests[i].target().networkLog.pageLoadForRequest(this._requests[i]);
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!page || seenIdentifiers[page.id])
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            seenIdentifiers[page.id] = true;
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            pages.push(this._convertPage(page));
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return pages;
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
320a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.PageLoad} page
321a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _convertPage: function(page)
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return {
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            startedDateTime: new Date(page.startTime * 1000),
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            id: "page_" + page.id,
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            title: page.url, // We don't have actual page title here. URL is probably better than nothing.
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            pageTimings: {
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                onContentLoad: this._pageEventTime(page, page.contentLoadTime),
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                onLoad: this._pageEventTime(page, page.loadTime)
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
337a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.NetworkRequest} request
338a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @return {!Object}
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _convertResource: function(request)
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return (new WebInspector.HAREntry(request)).build();
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
346a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.PageLoad} page
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {number} time
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @return {number}
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _pageEventTime: function(page, time)
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var startTime = page.startTime;
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (time === -1 || startTime === -1)
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return -1;
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return WebInspector.HAREntry._toMilliseconds(time - startTime);
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/**
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * @constructor
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HARWriter = function()
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebInspector.HARWriter.prototype = {
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
368a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.OutputStream} stream
369a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!Array.<!WebInspector.NetworkRequest>} requests
370a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.Progress} progress
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    write: function(stream, requests, progress)
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._stream = stream;
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._harLog = (new WebInspector.HARLog(requests)).build();
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._pendingRequests = 1; // Guard against completing resource transfer before all requests are made.
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var entries = this._harLog.entries;
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (var i = 0; i < entries.length; ++i) {
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            var content = requests[i].content;
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (typeof content === "undefined" && requests[i].finished) {
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++this._pendingRequests;
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                requests[i].requestContent(this._onContentAvailable.bind(this, entries[i]));
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            } else if (content !== null)
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                entries[i].response.content.text = content;
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var compositeProgress = new WebInspector.CompositeProgress(progress);
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._writeProgress = compositeProgress.createSubProgress();
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (--this._pendingRequests) {
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._requestsProgress = compositeProgress.createSubProgress();
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._requestsProgress.setTitle(WebInspector.UIString("Collecting content…"));
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._requestsProgress.setTotalWork(this._pendingRequests);
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._beginWrite();
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
397a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!Object} entry
398a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {?string} content
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
4001e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    _onContentAvailable: function(entry, content)
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (content !== null)
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            entry.response.content.text = content;
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this._requestsProgress)
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._requestsProgress.worked();
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!--this._pendingRequests) {
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._requestsProgress.done();
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._beginWrite();
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _beginWrite: function()
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const jsonIndent = 2;
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._text = JSON.stringify({log: this._harLog}, null, jsonIndent);
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._writeProgress.setTitle(WebInspector.UIString("Writing file…"));
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._writeProgress.setTotalWork(this._text.length);
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._bytesWritten = 0;
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._writeNextChunk(this._stream);
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    },
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    /**
423a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)     * @param {!WebInspector.OutputStream} stream
4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     * @param {string=} error
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)     */
4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    _writeNextChunk: function(stream, error)
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    {
4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (this._bytesWritten >= this._text.length || error) {
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stream.close();
4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            this._writeProgress.done();
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const chunkSize = 100000;
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var text = this._text.substring(this._bytesWritten, this._bytesWritten + chunkSize);
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._bytesWritten += text.length;
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        stream.write(text, this._writeNextChunk.bind(this));
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        this._writeProgress.setWorked(this._bytesWritten);
4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
440