Web Inspector: Allow inspection of Web Socket Frames
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Apr 2012 14:17:45 +0000 (14:17 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Apr 2012 14:17:45 +0000 (14:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=83282

Patch by Konrad Piascik <kpiascik@rim.com> on 2012-04-27
Reviewed by Pavel Feldman.

Source/WebCore:

Tests: http/tests/inspector/web-socket-frame-error.html
       http/tests/inspector/web-socket-frame.html

* English.lproj/localizedStrings.js: Added new Web Inspector front-end UI strings.
* Modules/websockets/WebSocketChannel.cpp:  Added InspectorInstrumentation calls to
                                            the following methods.
(WebCore::WebSocketChannel::fail):
(WebCore::WebSocketChannel::processFrame):
(WebCore::WebSocketChannel::sendFrame):
* WebCore.gypi: Added new Web Inspector resource file.
* WebCore.vcproj/WebCore.vcproj: Added new Web Inspector resource file.
* inspector/Inspector.json: Added new Web Inspector resource file.
* inspector/InspectorInstrumentation.cpp: Added new methods for instrumenting a Web Socket frame or error.
(WebCore::InspectorInstrumentation::didReceiveWebSocketFrameImpl):
(WebCore::InspectorInstrumentation::didReceiveWebSocketFrameErrorImpl):
(WebCore::InspectorInstrumentation::didSendWebSocketFrameImpl):
* inspector/InspectorInstrumentation.h:
(WebCore):
(InspectorInstrumentation):
(WebCore::InspectorInstrumentation::didReceiveWebSocketFrame):
(WebCore::InspectorInstrumentation::didReceiveWebSocketFrameError):
(WebCore::InspectorInstrumentation::didSendWebSocketFrame):
* inspector/InspectorResourceAgent.cpp:
(WebCore::InspectorResourceAgent::didReceiveWebSocketFrame):
(WebCore):
(WebCore::InspectorResourceAgent::didSendWebSocketFrame):
(WebCore::InspectorResourceAgent::didReceiveWebSocketFrameError):
* inspector/InspectorResourceAgent.h:
(WebCore):
(InspectorResourceAgent):
* inspector/compile-front-end.py: Added new Web Inspector resource file.
* inspector/front-end/NetworkItemView.js: Added a new View for inspecting Web Socket frames and errors.
(WebInspector.NetworkItemView):
* inspector/front-end/NetworkManager.js: Implemented callback called by InspectorResourceAgent for
                                         the new Web Socket frame and error calls.
(WebInspector.NetworkDispatcher.prototype.webSocketFrameReceived):
(WebInspector.NetworkDispatcher.prototype.webSocketFrameSent):
(WebInspector.NetworkDispatcher.prototype.webSocketFrameError):
* inspector/front-end/NetworkRequest.js: Added a frames array to a Resource request along
                                         with accessor and helper methods
(WebInspector.NetworkRequest):
(WebInspector.NetworkRequest.prototype.resource):
(WebInspector.NetworkRequest.prototype.hasFrames):
(WebInspector.NetworkRequest.prototype.frameLength):
(WebInspector.NetworkRequest.prototype.getFrame):
(WebInspector.NetworkRequest.prototype.addFrameError):
(WebInspector.NetworkRequest.prototype.addFrame):
(WebInspector.NetworkRequest.prototype._pushFrame):
* inspector/front-end/ResourceWebSocketFrameView.js: Added to help display Web Socket frame and error data.
(WebInspector.ResourceWebSocketFrameView):
* inspector/front-end/WebKit.qrc: Added new Web Inspector resource file.
* inspector/front-end/inspector.html: Added new Web Inspector resource file.

LayoutTests:

* http/tests/inspector/web-socket-frame-error-expected.txt: Added.
* http/tests/inspector/web-socket-frame-error.html: Added.
* http/tests/inspector/web-socket-frame-expected.txt: Added.
* http/tests/inspector/web-socket-frame.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@115427 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/inspector/web-socket-frame-error-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/inspector/web-socket-frame-error.html [new file with mode: 0644]
LayoutTests/http/tests/inspector/web-socket-frame-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/inspector/web-socket-frame.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/English.lproj/localizedStrings.js
Source/WebCore/Modules/websockets/WebSocketChannel.cpp
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/inspector/Inspector.json
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h
Source/WebCore/inspector/InspectorResourceAgent.cpp
Source/WebCore/inspector/InspectorResourceAgent.h
Source/WebCore/inspector/compile-front-end.py
Source/WebCore/inspector/front-end/NetworkItemView.js
Source/WebCore/inspector/front-end/NetworkManager.js
Source/WebCore/inspector/front-end/NetworkRequest.js
Source/WebCore/inspector/front-end/ResourceWebSocketFrameView.js [new file with mode: 0644]
Source/WebCore/inspector/front-end/WebKit.qrc
Source/WebCore/inspector/front-end/inspector.html

index a5e5df3..bbb7aab 100644 (file)
@@ -1,3 +1,15 @@
+2012-04-27  Konrad Piascik  <kpiascik@rim.com>
+
+        Web Inspector: Allow inspection of Web Socket Frames
+        https://bugs.webkit.org/show_bug.cgi?id=83282
+
+        Reviewed by Pavel Feldman.
+
+        * http/tests/inspector/web-socket-frame-error-expected.txt: Added.
+        * http/tests/inspector/web-socket-frame-error.html: Added.
+        * http/tests/inspector/web-socket-frame-expected.txt: Added.
+        * http/tests/inspector/web-socket-frame.html: Added.
+
 2012-04-27  Nikolas Zimmermann  <nzimmermann@rim.com>
 
         Fix repetitions & by animation support for SVGAnimateTransformElement
diff --git a/LayoutTests/http/tests/inspector/web-socket-frame-error-expected.txt b/LayoutTests/http/tests/inspector/web-socket-frame-error-expected.txt
new file mode 100644 (file)
index 0000000..323625e
--- /dev/null
@@ -0,0 +1,6 @@
+CONSOLE MESSAGE: Unexpected response code: 404
+Closed.
+Tests that WebSocketFrames errors are visible to Web Inspector.
+
+1: Unexpected response code: 404
+
diff --git a/LayoutTests/http/tests/inspector/web-socket-frame-error.html b/LayoutTests/http/tests/inspector/web-socket-frame-error.html
new file mode 100644 (file)
index 0000000..b06fc8e
--- /dev/null
@@ -0,0 +1,39 @@
+<html>
+<head>
+<script src="inspector-test.js"></script>
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+<script>
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+var ws;
+function sendMessages() {
+    ws = new WebSocket("ws://localhost:8000/websocket/tests/hybi/does_not_exist");
+    ws.onclose = function()
+    {
+        debug("Closed.");
+    };
+}
+
+function test() {
+    function onRequest(event)
+    {
+        var request = event.data;
+        if (request._type._name === "websocket") {
+            for (var i = 0; i < request.frames().length; i++) {
+                var frame = request.frame(i);
+                var result = String.sprintf("%d: %s", (i + 1), frame.errorMessage);
+                InspectorTest.addResult(result);
+                if (frame.errorMessage)
+                    InspectorTest.completeTest();
+            }
+        }
+    }
+    WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdated, onRequest);
+    InspectorTest.evaluateInPage("sendMessages()");
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests that WebSocketFrames errors are visible to Web Inspector.</p>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/inspector/web-socket-frame-expected.txt b/LayoutTests/http/tests/inspector/web-socket-frame-expected.txt
new file mode 100644 (file)
index 0000000..ef4a5c8
--- /dev/null
@@ -0,0 +1,14 @@
+Connected.
+Tests that WebSocketFrames are being sent and recieved by Web Inspector.
+
+1- sent: test
+1- sent: test
+2- sent: exit
+1- sent: test
+2- sent: exit
+3- received: test
+1- sent: test
+2- sent: exit
+3- received: test
+4- received: exit
+
diff --git a/LayoutTests/http/tests/inspector/web-socket-frame.html b/LayoutTests/http/tests/inspector/web-socket-frame.html
new file mode 100644 (file)
index 0000000..be0d3bf
--- /dev/null
@@ -0,0 +1,41 @@
+<html>
+<head>
+<script src="inspector-test.js"></script>
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+<script>
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+var ws;
+function sendMessages() {
+    ws = new WebSocket("ws://localhost:8880/websocket/tests/hybi/echo");
+    ws.onopen = function()
+    {
+        debug("Connected.");
+        ws.send("test");
+        ws.send("exit");
+    };
+}
+
+function test() {
+    function onRequest(event)
+    {
+        var request = event.data;
+        if (request._type._name === "websocket") {
+            for (var i = 0; i < request.frames().length; i++) {
+                var frame = request.frame(i);
+                var result = String.sprintf("%d-%s: %s", (i + 1), frame.sent ? " sent" : " received", frame.payloadData);
+                InspectorTest.addResult(result);
+                if (!frame.sent && frame.payloadData === "exit")
+                    InspectorTest.completeTest();
+            }
+        }
+    }
+    WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdated, onRequest);
+    InspectorTest.evaluateInPage("sendMessages()");
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests that WebSocketFrames are being sent and recieved by Web Inspector.</p>
+</body>
+</html>
index 5a53b9f..cc27701 100644 (file)
@@ -1,3 +1,63 @@
+2012-04-27  Konrad Piascik  <kpiascik@rim.com>
+
+        Web Inspector: Allow inspection of Web Socket Frames
+        https://bugs.webkit.org/show_bug.cgi?id=83282
+
+        Reviewed by Pavel Feldman.
+
+        Tests: http/tests/inspector/web-socket-frame-error.html
+               http/tests/inspector/web-socket-frame.html
+
+        * English.lproj/localizedStrings.js: Added new Web Inspector front-end UI strings.
+        * Modules/websockets/WebSocketChannel.cpp:  Added InspectorInstrumentation calls to
+                                                    the following methods.
+        (WebCore::WebSocketChannel::fail):
+        (WebCore::WebSocketChannel::processFrame):
+        (WebCore::WebSocketChannel::sendFrame):
+        * WebCore.gypi: Added new Web Inspector resource file.
+        * WebCore.vcproj/WebCore.vcproj: Added new Web Inspector resource file.
+        * inspector/Inspector.json: Added new Web Inspector resource file.
+        * inspector/InspectorInstrumentation.cpp: Added new methods for instrumenting a Web Socket frame or error.
+        (WebCore::InspectorInstrumentation::didReceiveWebSocketFrameImpl):
+        (WebCore::InspectorInstrumentation::didReceiveWebSocketFrameErrorImpl):
+        (WebCore::InspectorInstrumentation::didSendWebSocketFrameImpl):
+        * inspector/InspectorInstrumentation.h:
+        (WebCore):
+        (InspectorInstrumentation):
+        (WebCore::InspectorInstrumentation::didReceiveWebSocketFrame):
+        (WebCore::InspectorInstrumentation::didReceiveWebSocketFrameError):
+        (WebCore::InspectorInstrumentation::didSendWebSocketFrame):
+        * inspector/InspectorResourceAgent.cpp:
+        (WebCore::InspectorResourceAgent::didReceiveWebSocketFrame):
+        (WebCore):
+        (WebCore::InspectorResourceAgent::didSendWebSocketFrame):
+        (WebCore::InspectorResourceAgent::didReceiveWebSocketFrameError):
+        * inspector/InspectorResourceAgent.h:
+        (WebCore):
+        (InspectorResourceAgent):
+        * inspector/compile-front-end.py: Added new Web Inspector resource file.
+        * inspector/front-end/NetworkItemView.js: Added a new View for inspecting Web Socket frames and errors.
+        (WebInspector.NetworkItemView):
+        * inspector/front-end/NetworkManager.js: Implemented callback called by InspectorResourceAgent for
+                                                 the new Web Socket frame and error calls.
+        (WebInspector.NetworkDispatcher.prototype.webSocketFrameReceived):
+        (WebInspector.NetworkDispatcher.prototype.webSocketFrameSent):
+        (WebInspector.NetworkDispatcher.prototype.webSocketFrameError):
+        * inspector/front-end/NetworkRequest.js: Added a frames array to a Resource request along
+                                                 with accessor and helper methods
+        (WebInspector.NetworkRequest):
+        (WebInspector.NetworkRequest.prototype.resource):
+        (WebInspector.NetworkRequest.prototype.hasFrames):
+        (WebInspector.NetworkRequest.prototype.frameLength):
+        (WebInspector.NetworkRequest.prototype.getFrame):
+        (WebInspector.NetworkRequest.prototype.addFrameError):
+        (WebInspector.NetworkRequest.prototype.addFrame):
+        (WebInspector.NetworkRequest.prototype._pushFrame):
+        * inspector/front-end/ResourceWebSocketFrameView.js: Added to help display Web Socket frame and error data.
+        (WebInspector.ResourceWebSocketFrameView):
+        * inspector/front-end/WebKit.qrc: Added new Web Inspector resource file.
+        * inspector/front-end/inspector.html: Added new Web Inspector resource file.
+
 2012-04-27  Nikolas Zimmermann  <nzimmermann@rim.com>
 
         Fix repetitions & by animation support for SVGAnimateTransformElement
index 04290ec..766272c 100644 (file)
Binary files a/Source/WebCore/English.lproj/localizedStrings.js and b/Source/WebCore/English.lproj/localizedStrings.js differ
index 8f9b675..6231f68 100644 (file)
@@ -212,8 +212,10 @@ void WebSocketChannel::fail(const String& reason)
 {
     LOG(Network, "WebSocketChannel %p fail: %s", this, reason.utf8().data());
     ASSERT(!m_suspended);
-    if (m_document)
+    if (m_document) {
+        InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_identifier, reason);
         m_document->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, reason, m_handshake->clientOrigin());
+    }
     if (!m_useHixie76Protocol) {
         // Hybi-10 specification explicitly states we must not continue to handle incoming data
         // once the WebSocket connection is failed (section 7.1.7).
@@ -598,6 +600,8 @@ bool WebSocketChannel::processFrame()
         return false;
     }
 
+    InspectorInstrumentation::didReceiveWebSocketFrame(m_document, m_identifier, frame);
+
     switch (frame.opCode) {
     case WebSocketFrame::OpCodeContinuation:
         // An unexpected continuation frame is received without any leading frame.
@@ -918,6 +922,7 @@ bool WebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data
     ASSERT(!m_suspended);
 
     WebSocketFrame frame(opCode, true, false, true, data, dataLength);
+    InspectorInstrumentation::didSendWebSocketFrame(m_document, m_identifier, frame);
 
     OwnPtr<DeflateResultHolder> deflateResult = m_deflateFramer.deflate(frame);
     if (!deflateResult->succeeded()) {
index f13798c..c7f68a1 100644 (file)
             'inspector/front-end/ResourceType.js',
             'inspector/front-end/ResourceUtils.js',
             'inspector/front-end/ResourceView.js',
+            'inspector/front-end/ResourceWebSocketFrameView.js',
             'inspector/front-end/ResourcesPanel.js',
             'inspector/front-end/ScopeChainSidebarPane.js',
             'inspector/front-end/Script.js',
index 447d745..a8fa31e 100755 (executable)
                                        >
                                </File>
                                <File
+                                       RelativePath="..\inspector\front-end\ResourceWebSocketFrameView.js"
+                                       >
+                               </File>
+                               <File
                                        RelativePath="..\inspector\front-end\ScopeChainSidebarPane.js"
                                        >
                                </File>
index 35f3559..2c818e1 100644 (file)
                 ]
             },
             {
+                "id": "WebSocketFrame",
+                "type": "object",
+                "description": "WebSocket frame data.",
+                "hidden": true,
+                "properties": [
+                    { "name": "opcode", "type": "number", "description": "WebSocket frame opcode." },
+                    { "name": "mask", "type": "boolean", "description": "WebSocke frame mask." },
+                    { "name": "payloadData", "type": "string", "description": "WebSocke frame payload data." }
+                ]
+            },
+            {
                 "id": "CachedResource",
                 "type": "object",
                 "description": "Information about the cached resource.",
                     { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }
                 ],
                 "hidden": true
+            },
+            {
+                "name": "webSocketFrameReceived",
+                "description": "Fired when WebSocket frame is received.",
+                "parameters": [
+                    { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." },
+                    { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." },
+                    { "name": "response", "$ref": "WebSocketFrame", "description": "WebSocket response data." }
+                ],
+                "hidden": true
+            },
+            {
+                "name": "webSocketFrameError",
+                "description": "Fired when WebSocket frame error occurs.",
+                "parameters": [
+                    { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." },
+                    { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." },
+                    { "name": "errorMessage", "type": "string", "description": "WebSocket frame error message." }
+                ],
+                "hidden": true
+            },
+            {
+                "name": "webSocketFrameSent",
+                "description": "Fired when WebSocket frame is sent.",
+                "parameters": [
+                    { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." },
+                    { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." },
+                    { "name": "response", "$ref": "WebSocketFrame", "description": "WebSocket response data." }
+                ],
+                "hidden": true
             }
         ]
     },
index c8aace0..05a8ad6 100644 (file)
@@ -988,6 +988,21 @@ void InspectorInstrumentation::didCloseWebSocketImpl(InstrumentingAgents* instru
     if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
         resourceAgent->didCloseWebSocket(identifier);
 }
+void InspectorInstrumentation::didReceiveWebSocketFrameImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const WebSocketFrame& frame)
+{
+    if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+        resourceAgent->didReceiveWebSocketFrame(identifier, frame);
+}
+void InspectorInstrumentation::didReceiveWebSocketFrameErrorImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const String& errorMessage)
+{
+    if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+        resourceAgent->didReceiveWebSocketFrameError(identifier, errorMessage);
+}
+void InspectorInstrumentation::didSendWebSocketFrameImpl(InstrumentingAgents* instrumentingAgents, unsigned long identifier, const WebSocketFrame& frame)
+{
+    if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent())
+        resourceAgent->didSendWebSocketFrame(identifier, frame);
+}
 #endif
 
 void InspectorInstrumentation::networkStateChangedImpl(InstrumentingAgents* instrumentingAgents)
index e450b9a..a172034 100644 (file)
@@ -71,6 +71,7 @@ class WorkerContextProxy;
 class XMLHttpRequest;
 
 #if ENABLE(WEB_SOCKETS)
+struct WebSocketFrame;
 class WebSocketHandshakeRequest;
 class WebSocketHandshakeResponse;
 #endif
@@ -217,6 +218,9 @@ public:
     static void willSendWebSocketHandshakeRequest(ScriptExecutionContext*, unsigned long identifier, const WebSocketHandshakeRequest&);
     static void didReceiveWebSocketHandshakeResponse(ScriptExecutionContext*, unsigned long identifier, const WebSocketHandshakeResponse&);
     static void didCloseWebSocket(ScriptExecutionContext*, unsigned long identifier);
+    static void didReceiveWebSocketFrame(Document*, unsigned long identifier, const WebSocketFrame&);
+    static void didSendWebSocketFrame(Document*, unsigned long identifier, const WebSocketFrame&);
+    static void didReceiveWebSocketFrameError(Document*, unsigned long identifier, const String& errorMessage);
 #endif
 
     static void networkStateChanged(Page*);
@@ -369,6 +373,9 @@ private:
     static void willSendWebSocketHandshakeRequestImpl(InstrumentingAgents*, unsigned long identifier, const WebSocketHandshakeRequest&);
     static void didReceiveWebSocketHandshakeResponseImpl(InstrumentingAgents*, unsigned long identifier, const WebSocketHandshakeResponse&);
     static void didCloseWebSocketImpl(InstrumentingAgents*, unsigned long identifier);
+    static void didReceiveWebSocketFrameImpl(InstrumentingAgents*, unsigned long identifier, const WebSocketFrame&);
+    static void didSendWebSocketFrameImpl(InstrumentingAgents*, unsigned long identifier, const WebSocketFrame&);
+    static void didReceiveWebSocketFrameErrorImpl(InstrumentingAgents*, unsigned long identifier, const String&);
 #endif
 
     static void networkStateChangedImpl(InstrumentingAgents*);
@@ -1224,6 +1231,27 @@ inline void InspectorInstrumentation::didCloseWebSocket(ScriptExecutionContext*
         didCloseWebSocketImpl(instrumentingAgents, identifier);
 #endif
 }
+inline void InspectorInstrumentation::didReceiveWebSocketFrame(Document* document, unsigned long identifier, const WebSocketFrame& frame)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+        didReceiveWebSocketFrameImpl(instrumentingAgents, identifier, frame);
+#endif
+}
+inline void InspectorInstrumentation::didReceiveWebSocketFrameError(Document* document, unsigned long identifier, const String& errorMessage)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+        didReceiveWebSocketFrameErrorImpl(instrumentingAgents, identifier, errorMessage);
+#endif
+}
+inline void InspectorInstrumentation::didSendWebSocketFrame(Document* document, unsigned long identifier, const WebSocketFrame& frame)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document))
+        didSendWebSocketFrameImpl(instrumentingAgents, identifier, frame);
+#endif
+}
 #endif
 
 inline void InspectorInstrumentation::networkStateChanged(Page* page)
index 9162e6e..c684545 100644 (file)
@@ -59,6 +59,7 @@
 #include "ScriptCallStack.h"
 #include "ScriptCallStackFactory.h"
 #include "ScriptableDocumentParser.h"
+#include "WebSocketFrame.h"
 #include "WebSocketHandshakeRequest.h"
 #include "WebSocketHandshakeResponse.h"
 
@@ -455,6 +456,31 @@ void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier)
 {
     m_frontend->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
 }
+void InspectorResourceAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
+{
+    String payload = frame.payload;
+    RefPtr<TypeBuilder::Network::WebSocketFrame> frameObject = TypeBuilder::Network::WebSocketFrame::create()
+        .setOpcode(frame.opCode)
+        .setMask(frame.masked)
+        .setPayloadData(payload.substring(0, frame.payloadLength));
+    m_frontend->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
+}
+
+void InspectorResourceAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
+{
+    String payload = frame.payload;
+    RefPtr<TypeBuilder::Network::WebSocketFrame> frameObject = TypeBuilder::Network::WebSocketFrame::create()
+        .setOpcode(frame.opCode)
+        .setMask(frame.masked)
+        .setPayloadData(payload.substring(0, frame.payloadLength));
+    m_frontend->webSocketFrameSent(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
+}
+
+void InspectorResourceAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
+{
+    m_frontend->webSocketFrameError(IdentifiersFactory::requestId(identifier), currentTime(), errorMessage);
+}
+
 #endif // ENABLE(WEB_SOCKETS)
 
 // called from Internals for layout test purposes.
index f7d96f7..54cf48e 100644 (file)
@@ -67,6 +67,7 @@ class ResourceResponse;
 class SharedBuffer;
 
 #if ENABLE(WEB_SOCKETS)
+struct WebSocketFrame;
 class WebSocketHandshakeRequest;
 class WebSocketHandshakeResponse;
 #endif
@@ -117,6 +118,9 @@ public:
     void willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest&);
     void didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse&);
     void didCloseWebSocket(unsigned long identifier);
+    void didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame&);
+    void didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame&);
+    void didReceiveWebSocketFrameError(unsigned long identifier, const String&);
 #endif
 
     // called from Internals for layout test purposes.
index 22250ba..b19159e 100755 (executable)
@@ -188,6 +188,7 @@ modules = [
             "RequestTimingView.js",
             "RequestView.js",
             "ResourceView.js",
+            "ResourceWebSocketFrameView.js",
             "NetworkPanel.js",
         ]
     },
index a28cdec..6c0c647 100644 (file)
@@ -57,6 +57,11 @@ WebInspector.NetworkItemView = function(request)
         this.appendTab("timing", WebInspector.UIString("Timing"), timingView);
     }
 
+    if (request.frames().length > 0) {
+        var frameView = new WebInspector.ResourceWebSocketFrameView(request);
+        this.appendTab("webSocketFrames", WebInspector.UIString("WebSocket Frames"), frameView);
+    }
+
     this.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
 }
 
index 71959c6..40d3b9b 100644 (file)
@@ -456,6 +456,57 @@ WebInspector.NetworkDispatcher.prototype = {
     /**
      * @param {NetworkAgent.RequestId} requestId
      * @param {NetworkAgent.Timestamp} time
+     * @param {NetworkAgent.WebSocketFrame} response
+     */
+    webSocketFrameReceived: function(requestId, time, response)
+    {
+        var networkRequest = this._inflightRequestsById[requestId];
+        if (!networkRequest)
+            return;
+
+        networkRequest.addFrame(response, time);
+        networkRequest.responseReceivedTime = time;
+
+        this._updateNetworkRequest(networkRequest);
+    },
+
+    /**
+     * @param {NetworkAgent.RequestId} requestId
+     * @param {NetworkAgent.Timestamp} time
+     * @param {NetworkAgent.WebSocketFrame} response
+     */
+    webSocketFrameSent: function(requestId, time, response)
+    {
+        var networkRequest = this._inflightRequestsById[requestId];
+        if (!networkRequest)
+            return;
+
+        networkRequest.addFrame(response, time, true);
+        networkRequest.responseReceivedTime = time;
+
+        this._updateNetworkRequest(networkRequest);
+    },
+
+    /**
+     * @param {NetworkAgent.RequestId} requestId
+     * @param {NetworkAgent.Timestamp} time
+     * @param {string} errorMessage
+     */
+    webSocketFrameError: function(requestId, time, errorMessage)
+    {
+        var networkRequest = this._inflightRequestsById[requestId];
+        if (!networkRequest)
+            return;
+
+        networkRequest.addFrameError(errorMessage, time);
+        networkRequest.responseReceivedTime = time;
+
+        this._updateNetworkRequest(networkRequest);
+    },
+
+    /**
+     * @param {NetworkAgent.RequestId} requestId
+     * @param {NetworkAgent.Timestamp} time
      */
     webSocketClosed: function(requestId, time)
     {
index 949b64d..804b825 100644 (file)
@@ -58,6 +58,7 @@ WebInspector.NetworkRequest = function(requestId, url, documentURL, frameId, loa
     this._content = undefined;
     this._contentEncoded = false;
     this._pendingContentCallbacks = [];
+    this._frames = [];
 }
 
 WebInspector.NetworkRequest.Events = {
@@ -804,6 +805,56 @@ WebInspector.NetworkRequest.prototype = {
     resource: function()
     {
         return this._resource;
+    },
+
+    /**
+     * @return {Object}
+     */
+    frames: function()
+    {
+        return this._frames;
+    },
+
+    /**
+     * @param {number} position
+     * @return {Object}
+     */
+    frame: function(position)
+    {
+        return this._frames[position];
+    },
+
+    /**
+     * @param {string} errorMessage
+     * @param {number} time
+     */
+    addFrameError: function(errorMessage, time)
+    {
+        errorObject = {};
+        errorObject.errorMessage = errorMessage;
+        errorObject.time = time;
+        this._pushFrame(errorObject);
+    },
+
+    /**
+     * @param {Object} response
+     * @param {number} time
+     * @param {boolean} sent
+     */
+    addFrame: function(response, time, sent)
+    {
+        response.time = time;
+        if (sent)
+            response.sent = true;
+        this._pushFrame(response);
+    },
+
+    _pushFrame: function(object)
+    {
+        if (this._frames.length >= 100) {
+            this._frames.splice(0, 10);
+        }
+        this._frames.push(object);
     }
 }
 
diff --git a/Source/WebCore/inspector/front-end/ResourceWebSocketFrameView.js b/Source/WebCore/inspector/front-end/ResourceWebSocketFrameView.js
new file mode 100644 (file)
index 0000000..3f5739d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ */
+WebInspector.ResourceWebSocketFrameView = function(resource)
+{
+    WebInspector.View.call(this);
+    this.element.addStyleClass("html");
+    this.resource = resource;
+    this.element.removeChildren();
+    var table = document.createElement("table");
+    var header = document.createElement("thead");
+
+    var headerRow = document.createElement("tr");
+    headerRow.createChild("td");
+
+    var timeHeader = document.createElement("td");
+    timeHeader.innerText = WebInspector.UIString("Time");
+    headerRow.appendChild(timeHeader);
+
+    var opCodeHeader = document.createElement("td");
+    opCodeHeader.innerText = WebInspector.UIString("OpCode");
+    headerRow.appendChild(opCodeHeader);
+
+    var maskHeader = document.createElement("td");
+    maskHeader.innerText = WebInspector.UIString("Mask");
+    headerRow.appendChild(maskHeader);
+
+    var lengthHeader = document.createElement("td");
+    lengthHeader.innerText = WebInspector.UIString("Length");
+    headerRow.appendChild(lengthHeader);
+
+    var dataHeader = document.createElement("td");
+    dataHeader.innerText = WebInspector.UIString("Data");
+    headerRow.appendChild(dataHeader);
+    table.appendChild(headerRow);
+
+    var frames = this.resource.frames();
+    for (var i = 0; i < frames.length; i++) {
+        var payload = frames[i];
+
+        var row = document.createElement("tr");
+
+        var count = document.createElement("td");
+        count.innerText = i + 1;
+        row.appendChild(count);
+
+        var dateCell = document.createElement("td");
+        var date = new Date();
+        date.setTime(payload.time * 1000);
+        dateCell.innerText = String.sprintf("%s %s", (payload.sent ? "\u2192" : (payload.errorMessage ? "" : "\u2190")), date.toISOString());
+        row.appendChild(dateCell);
+
+        if (payload.errorMessage) {
+            var spanCell = document.createElement("td");
+            spanCell.setAttribute("colspan", 4);
+            spanCell.innerText = payload.errorMessage;
+            row.appendChild(spanCell);
+        } else {
+            var opcode = document.createElement("td");
+            opcode.innerText = payload.opcode;
+            row.appendChild(opcode);
+
+            var mask = document.createElement("td");
+            mask.innerText = payload.mask;
+            row.appendChild(mask);
+
+            var length = document.createElement("td");
+            length.innerText = payload.payloadData.length;
+            row.appendChild(length);
+
+            var data = document.createElement("td");
+            data.textContent = payload.payloadData;
+            row.appendChild(data);
+        }
+        table.appendChild(row);
+    }
+    this.element.appendChild(table);
+}
+
+WebInspector.ResourceWebSocketFrameView.prototype.__proto__ = WebInspector.View.prototype;
index 285b374..0db66e7 100644 (file)
     <file>ResourceType.js</file>
     <file>ResourceUtils.js</file>
     <file>ResourceView.js</file>
+    <file>ResourceWebSocketFrameView.js</file>
     <file>ResourcesPanel.js</file>
     <file>ScopeChainSidebarPane.js</file>
     <file>Script.js</file>
index c2b3fce..ff70725 100644 (file)
@@ -149,6 +149,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="RequestHTMLView.js"></script>
     <script type="text/javascript" src="RequestResponseView.js"></script>
     <script type="text/javascript" src="RequestPreviewView.js"></script>
+    <script type="text/javascript" src="ResourceWebSocketFrameView.js"></script>
     <script type="text/javascript" src="ScriptFormatter.js"></script>
     <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script>
     <script type="text/javascript" src="TextEditorModel.js"></script>