Title: [129336] trunk
Revision
129336
Author
[email protected]
Date
2012-09-24 02:23:20 -0700 (Mon, 24 Sep 2012)

Log Message

Web Inspector: support saving HAR with resources content
https://bugs.webkit.org/show_bug.cgi?id=97341

Reviewed by Vsevolod Vlasov.

Source/WebCore:

- add WebInspector.HARWriter that writes HAR with content to a stream;
- replace Save all as HAR with Save all with Content as HAR in network's panel context menu;
- remove entries for copying/saving of individual request items to reduce clutter in context menu;
- a drive-by fix of an exception when invoking context menu not on a network item;

Test: http/tests/inspector/network/har-content.html

* English.lproj/localizedStrings.js:
* inspector/front-end/FileUtils.js:
* inspector/front-end/HAREntry.js:
(WebInspector.HAREntry.prototype._buildPostData):
(WebInspector.HARLog.prototype.build):
(WebInspector.HARLog.prototype._creator):
(WebInspector.HARWriter):
(WebInspector.HARWriter.prototype.write):
(WebInspector.HARWriter.prototype._onContentAvailable):
(WebInspector.HARWriter.prototype._beginWrite):
(WebInspector.HARWriter.prototype._writeNextChunk):
* inspector/front-end/NetworkPanel.js:
(WebInspector.NetworkLogView.prototype.get statusBarItems):
(WebInspector.NetworkLogView.prototype._createStatusBarItems):
(WebInspector.NetworkLogView.prototype._contextMenu):
(WebInspector.NetworkLogView.prototype._exportAll.openCallback):
(WebInspector.NetworkLogView.prototype._exportAll):

LayoutTests:

- moved StringOutputStream to inspector-test.js for reuse;
- added test for HARWriter and response content in HAR.

* http/tests/inspector/inspector-test.js:
(initialize_InspectorTest):
(initialize_InspectorTest.):
* http/tests/inspector/network/har-content-expected.txt: Added.
* http/tests/inspector/network/har-content.html: Added.
* inspector/timeline/timeline-test.js:
(initialize_Timeline):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (129335 => 129336)


--- trunk/LayoutTests/ChangeLog	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/LayoutTests/ChangeLog	2012-09-24 09:23:20 UTC (rev 129336)
@@ -1,3 +1,21 @@
+2012-09-21  Andrey Kosyakov  <[email protected]>
+
+        Web Inspector: support saving HAR with resources content
+        https://bugs.webkit.org/show_bug.cgi?id=97341
+
+        Reviewed by Vsevolod Vlasov.
+
+        - moved StringOutputStream to inspector-test.js for reuse;
+        - added test for HARWriter and response content in HAR.
+
+        * http/tests/inspector/inspector-test.js:
+        (initialize_InspectorTest):
+        (initialize_InspectorTest.):
+        * http/tests/inspector/network/har-content-expected.txt: Added.
+        * http/tests/inspector/network/har-content.html: Added.
+        * inspector/timeline/timeline-test.js:
+        (initialize_Timeline):
+
 2012-09-24  Yury Semikhatsky  <[email protected]>
 
         Unreviewed. Updated test expectations for webaudio/biquad-getFrequencyResponse.html

Modified: trunk/LayoutTests/http/tests/inspector/inspector-test.js (129335 => 129336)


--- trunk/LayoutTests/http/tests/inspector/inspector-test.js	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/LayoutTests/http/tests/inspector/inspector-test.js	2012-09-24 09:23:20 UTC (rev 129336)
@@ -372,8 +372,28 @@
     return buffer;
 }
 
+InspectorTest.StringOutputStream = function(callback)
+{
+    this._callback = callback;
+    this._buffer = "";
 };
 
+InspectorTest.StringOutputStream.prototype = {
+    write: function(chunk, callback)
+    {
+        this._buffer += chunk;
+        if (callback)
+            callback(this);
+    },
+
+    close: function()
+    {
+        this._callback(this._buffer);
+    }
+};
+
+};
+
 var initializeCallId = 0;
 var runTestCallId = 1;
 var completeTestCallId = 2;

Added: trunk/LayoutTests/http/tests/inspector/network/har-content-expected.txt (0 => 129336)


--- trunk/LayoutTests/http/tests/inspector/network/har-content-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/network/har-content-expected.txt	2012-09-24 09:23:20 UTC (rev 129336)
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: line 6: XHR loaded: 1
+Tests conversion of Inspector's resource representation into HAR format.
+
+initiator.css: .image-background {
+    background-image: url("resource.php?type=image&random=1&size=200");
+}
+
+.image-background-2 {
+    background-image: url("resource.php?type=image&random=1&size=300");
+}
+
+
+
Property changes on: trunk/LayoutTests/http/tests/inspector/network/har-content-expected.txt
___________________________________________________________________

Added: svn:eol-style

Added: trunk/LayoutTests/http/tests/inspector/network/har-content.html (0 => 129336)


--- trunk/LayoutTests/http/tests/inspector/network/har-content.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/network/har-content.html	2012-09-24 09:23:20 UTC (rev 129336)
@@ -0,0 +1,51 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script src=""
+
+<script>
+var test = function()
+{
+    const requestRegExp = /\/initiator.css$/;
+
+    function onRequestFinished()
+    {
+        var writer = new WebInspector.HARWriter();
+        var stream = new InspectorTest.StringOutputStream(onSaved);
+        writer.write(stream, WebInspector.networkLog.requests, new WebInspector.Progress());
+    }
+
+    function onSaved(data)
+    {
+        var har = JSON.parse(data);
+        InspectorTest.addResult("initiator.css: " + findEntry(har, requestRegExp).response.content.text);
+        InspectorTest.completeTest();
+    }
+
+    function findEntry(har, regexp)
+    {
+        var entries = har.log.entries;
+        for (var i = 0; i < entries.length; ++i) {
+             var entry = entries[i];
+             if (regexp.test(entry.request.url))
+                 return entry;
+        }
+        InspectorTest.addResult("FAIL: can't find resource for " + regexp);
+        return null;
+    }
+
+    InspectorTest.makeSimpleXHR("GET", "resources/initiator.css", false, onRequestFinished);
+}
+</script>
+
+
+</head>
+
+<body _onload_="runTest()">
+<p>
+Tests conversion of Inspector's resource representation into HAR format.
+</p>
+
+</body>
+</html>
Property changes on: trunk/LayoutTests/http/tests/inspector/network/har-content.html
___________________________________________________________________

Added: svn:eol-style

Modified: trunk/LayoutTests/inspector/timeline/timeline-test.js (129335 => 129336)


--- trunk/LayoutTests/inspector/timeline/timeline-test.js	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/LayoutTests/inspector/timeline/timeline-test.js	2012-09-24 09:23:20 UTC (rev 129336)
@@ -207,24 +207,4 @@
     }
 };
 
-InspectorTest.StringOutputStream = function(callback)
-{
-    this._callback = callback;
-    this._buffer = "";
 };
-
-InspectorTest.StringOutputStream.prototype = {
-    write: function(chunk, callback)
-    {
-        this._buffer += chunk;
-        if (callback)
-            callback(this);
-    },
-
-    close: function()
-    {
-        this._callback(this._buffer);
-    }
-};
-
-};

Modified: trunk/Source/WebCore/ChangeLog (129335 => 129336)


--- trunk/Source/WebCore/ChangeLog	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/Source/WebCore/ChangeLog	2012-09-24 09:23:20 UTC (rev 129336)
@@ -1,3 +1,35 @@
+2012-09-21  Andrey Kosyakov  <[email protected]>
+
+        Web Inspector: support saving HAR with resources content
+        https://bugs.webkit.org/show_bug.cgi?id=97341
+
+        Reviewed by Vsevolod Vlasov.
+
+        - add WebInspector.HARWriter that writes HAR with content to a stream;
+        - replace Save all as HAR with Save all with Content as HAR in network's panel context menu;
+        - remove entries for copying/saving of individual request items to reduce clutter in context menu;
+        - a drive-by fix of an exception when invoking context menu not on a network item;
+
+        Test: http/tests/inspector/network/har-content.html
+
+        * English.lproj/localizedStrings.js:
+        * inspector/front-end/FileUtils.js:
+        * inspector/front-end/HAREntry.js:
+        (WebInspector.HAREntry.prototype._buildPostData):
+        (WebInspector.HARLog.prototype.build):
+        (WebInspector.HARLog.prototype._creator):
+        (WebInspector.HARWriter):
+        (WebInspector.HARWriter.prototype.write):
+        (WebInspector.HARWriter.prototype._onContentAvailable):
+        (WebInspector.HARWriter.prototype._beginWrite):
+        (WebInspector.HARWriter.prototype._writeNextChunk):
+        * inspector/front-end/NetworkPanel.js:
+        (WebInspector.NetworkLogView.prototype.get statusBarItems):
+        (WebInspector.NetworkLogView.prototype._createStatusBarItems):
+        (WebInspector.NetworkLogView.prototype._contextMenu):
+        (WebInspector.NetworkLogView.prototype._exportAll.openCallback):
+        (WebInspector.NetworkLogView.prototype._exportAll):
+
 2012-09-24  Nico Weber  <[email protected]>
 
         [chromium] Remove BitLockerSkia. It's apparently not used.

Modified: trunk/Source/WebCore/English.lproj/localizedStrings.js (129335 => 129336)


--- trunk/Source/WebCore/English.lproj/localizedStrings.js	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/Source/WebCore/English.lproj/localizedStrings.js	2012-09-24 09:23:20 UTC (rev 129336)
@@ -129,14 +129,10 @@
 localizedStrings["Continue to here"] = "Continue to here";
 localizedStrings["Continue"] = "Continue";
 localizedStrings["Copy as HTML"] = "Copy as HTML";
-localizedStrings["Copy entry as HAR"] = "Copy entry as HAR";
-localizedStrings["Copy Entry as HAR"] = "Copy Entry as HAR";
-localizedStrings["Save entry as HAR"] = "Save entry as HAR";
-localizedStrings["Save Entry as HAR"] = "Save Entry as HAR";
 localizedStrings["Copy all as HAR"] = "Copy all as HAR";
 localizedStrings["Copy All as HAR"] = "Copy All as HAR";
-localizedStrings["Save all as HAR"] = "Save all as HAR";
-localizedStrings["Save All as HAR"] = "Save All as HAR";
+localizedStrings["Save as HAR with content"] = "Save as HAR with content";
+localizedStrings["Save as HAR with Content"] = "Save as HAR with Content";
 localizedStrings["Copy link address"] = "Copy link address";
 localizedStrings["Copy Link Address"] = "Copy Link Address";
 localizedStrings["Copy request headers"] = "Copy request headers";
@@ -749,3 +745,5 @@
 localizedStrings["Paused on assertion."] = "Paused on assertion.";
 localizedStrings["%s (%s%s)"] = "%s (%s%s)";
 localizedStrings["Running audit"] = "Running audit";
+localizedStrings["Collecting content…"] = "Collecting content…";
+localizedStrings["Writing file…"] = "Writing file…";

Modified: trunk/Source/WebCore/inspector/front-end/FileUtils.js (129335 => 129336)


--- trunk/Source/WebCore/inspector/front-end/FileUtils.js	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/Source/WebCore/inspector/front-end/FileUtils.js	2012-09-24 09:23:20 UTC (rev 129336)
@@ -40,8 +40,6 @@
 
     onChunkTransferred: function(source) { },
 
-    onTransferFinished: function(source) { },
-
     onError: function(source, event) { }
 }
 

Modified: trunk/Source/WebCore/inspector/front-end/HAREntry.js (129335 => 129336)


--- trunk/Source/WebCore/inspector/front-end/HAREntry.js	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/Source/WebCore/inspector/front-end/HAREntry.js	2012-09-24 09:23:20 UTC (rev 129336)
@@ -164,7 +164,7 @@
             text: this._request.requestFormData
         };
         if (this._request.formParameters)
-           res.params = this._buildParameters(this._request.formParameters);
+            res.params = this._buildParameters(this._request.formParameters);
         return res;
     },
 
@@ -279,19 +279,24 @@
      */
     build: function()
     {
-        var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
-
         return {
             version: "1.2",
-            creator: {
-                name: "WebInspector",
-                version: webKitVersion ? webKitVersion[1] : "n/a"
-            },
+            creator: this._creator(),
             pages: this._buildPages(),
             entries: this._requests.map(this._convertResource.bind(this))
         }
     },
 
+    _creator: function()
+    {
+        var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent);
+
+        return {
+            name: "WebInspector",
+            version: webKitVersion ? webKitVersion[1] : "n/a"
+        };
+    },
+
     /**
      * @return {Array}
      */
@@ -348,3 +353,87 @@
         return WebInspector.HAREntry._toMilliseconds(time - startTime);
     }
 }
+
+/**
+ * @constructor
+ */
+WebInspector.HARWriter = function()
+{
+}
+
+WebInspector.HARWriter.prototype = {
+    /**
+     * @param {WebInspector.OutputStream} stream
+     * @param {Array.<WebInspector.NetworkRequest>} requests
+     * @param {WebInspector.Progress} progress
+     */
+    write: function(stream, requests, progress)
+    {
+        this._stream = stream;
+        this._harLog = (new WebInspector.HARLog(requests)).build();
+        this._pendingRequests = 1; // Guard against completing resource transfer before all requests are made.
+        var entries = this._harLog.entries;
+        for (var i = 0; i < entries.length; ++i) {
+            var content = requests[i].content;
+            if (typeof content === "undefined" && requests[i].finished) {
+                ++this._pendingRequests;
+                requests[i].requestContent(this._onContentAvailable.bind(this, entries[i]));
+            } else if (content !== null)
+                entries[i].response.content.text = content;
+        }
+        var compositeProgress = new WebInspector.CompositeProgress(progress);
+        this._writeProgress = compositeProgress.createSubProgress();
+        if (--this._pendingRequests) {
+            this._requestsProgress = compositeProgress.createSubProgress();
+            this._requestsProgress.setTitle(WebInspector.UIString("Collecting content…"));
+            this._requestsProgress.setTotalWork(this._pendingRequests);
+        } else
+            this._beginWrite();
+    },
+
+    /**
+     * @param {Object} entry
+     * @param {string|null} content
+     * @param {boolean} contentEncoded
+     * @param {string=} mimeType
+     */
+    _onContentAvailable: function(entry, content, contentEncoded, mimeType)
+    {
+        if (content !== null)
+            entry.response.content.text = content;
+        if (this._requestsProgress)
+            this._requestsProgress.worked();
+        if (!--this._pendingRequests) {
+            this._requestsProgress.done();
+            this._beginWrite();
+        }
+    },
+
+    _beginWrite: function()
+    {
+        const jsonIndent = 2;
+        this._text = JSON.stringify({log: this._harLog}, null, jsonIndent);
+        this._writeProgress.setTitle(WebInspector.UIString("Writing file…"));
+        this._writeProgress.setTotalWork(this._text.length);
+        this._bytesWritten = 0;
+        this._writeNextChunk(this._stream);
+    },
+
+    /**
+     * @param {WebInspector.OutputStream} stream
+     * @param {string} error
+     */
+    _writeNextChunk: function(stream, error)
+    {
+        if (this._bytesWritten >= this._text.length || error) {
+            stream.close();
+            this._writeProgress.done();
+            return;
+        }
+        const chunkSize = 100000;
+        var text = this._text.substring(this._bytesWritten, this._bytesWritten + chunkSize);
+        this._bytesWritten += text.length;
+        stream.write(text, this._writeNextChunk.bind(this));
+        this._writeProgress.setWorked(this._bytesWritten);
+    }
+}

Modified: trunk/Source/WebCore/inspector/front-end/NetworkPanel.js (129335 => 129336)


--- trunk/Source/WebCore/inspector/front-end/NetworkPanel.js	2012-09-24 09:15:49 UTC (rev 129335)
+++ trunk/Source/WebCore/inspector/front-end/NetworkPanel.js	2012-09-24 09:23:20 UTC (rev 129336)
@@ -65,7 +65,7 @@
     this._currentMatchedRequestIndex = -1;
 
     this._createStatusbarButtons();
-    this._createFilterStatusBarItems();
+    this._createStatusBarItems();
     this._linkifier = new WebInspector.Linkifier();
 
     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
@@ -118,7 +118,7 @@
 
     get statusBarItems()
     {
-        return [this._largerRequestsButton.element, this._preserveLogToggle.element, this._clearButton.element, this._filterBarElement];
+        return [this._largerRequestsButton.element, this._preserveLogToggle.element, this._clearButton.element, this._filterBarElement, this._progressBarContainer];
     },
 
     get useLargeRows()
@@ -325,7 +325,7 @@
         this._updateOffscreenRows();
     },
 
-    _createFilterStatusBarItems: function()
+    _createStatusBarItems: function()
     {
         var filterBarElement = document.createElement("div");
         filterBarElement.className = "scope-bar status-bar-item";
@@ -358,6 +358,8 @@
             createFilterElement.call(this, type.name(), type.categoryTitle());
         }
         this._filterBarElement = filterBarElement;
+        this._progressBarContainer = document.createElement("div");
+        this._progressBarContainer.className = "status-bar-item";
     },
 
     _createSummaryBar: function()
@@ -944,15 +946,12 @@
                 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy request headers" : "Copy Request Headers"), this._copyRequestHeaders.bind(this, request));
             if (request.responseHeadersText)
                 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy response headers" : "Copy Response Headers"), this._copyResponseHeaders.bind(this, request));
-            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy entry as HAR" : "Copy Entry as HAR"), this._copyRequest.bind(this, request));
         }
         contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy all as HAR" : "Copy All as HAR"), this._copyAll.bind(this));
 
         if (InspectorFrontendHost.canSave()) {
             contextMenu.appendSeparator();
-            if (request)
-                contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save entry as HAR" : "Save Entry as HAR"), this._exportRequest.bind(this, request));
-            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save all as HAR" : "Save All as HAR"), this._exportAll.bind(this));
+            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as HAR with content" : "Save as HAR with Content"), this._exportAll.bind(this));
         }
 
         if (this._canClearBrowserCache || this._canClearBrowserCookies)
@@ -963,7 +962,7 @@
             contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear browser cookies" : "Clear Browser Cookies"), this._clearBrowserCookies.bind(this));
 
 
-        if (request.type === WebInspector.resourceTypes.XHR) {
+        if (request && request.type === WebInspector.resourceTypes.XHR) {
             contextMenu.appendSeparator();
             contextMenu.appendItem(WebInspector.UIString("Replay XHR"), this._replayXHR.bind(this, request.requestId));
             contextMenu.appendSeparator();
@@ -986,12 +985,6 @@
         InspectorFrontendHost.copyText(JSON.stringify(harArchive, null, 2));
     },
 
-    _copyRequest: function(request)
-    {
-        var har = (new WebInspector.HAREntry(request)).build();
-        InspectorFrontendHost.copyText(JSON.stringify(har, null, 2));
-    },
-
     _copyLocation: function(request)
     {
         InspectorFrontendHost.copyText(request.url);
@@ -1009,19 +1002,18 @@
 
     _exportAll: function()
     {
-        var harArchive = {
-            log: (new WebInspector.HARLog(this._requests)).build()
-        };
-        
-        WebInspector.fileManager.save(WebInspector.inspectedPageDomain + ".har", JSON.stringify(harArchive, null, 2), true);
+        var filename = WebInspector.inspectedPageDomain + ".har";
+        var stream = new WebInspector.FileOutputStream();
+        stream.open(filename, openCallback.bind(this));
+        function openCallback()
+        {
+            var progressIndicator = new WebInspector.ProgressIndicator();
+            this._progressBarContainer.appendChild(progressIndicator.element);
+            var harWriter = new WebInspector.HARWriter();
+            harWriter.write(stream, this._requests, progressIndicator);
+        }
     },
 
-    _exportRequest: function(request)
-    {
-        var har = (new WebInspector.HAREntry(request)).build();
-        WebInspector.fileManager.save(request.displayName + ".har", JSON.stringify(har, null, 2), true);
-    },
-
     _clearBrowserCache: function(event)
     {
         if (confirm(WebInspector.UIString("Are you sure you want to clear browser cache?")))
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to