Title: [111829] trunk
Revision
111829
Author
[email protected]
Date
2012-03-22 23:08:40 -0700 (Thu, 22 Mar 2012)

Log Message

Source/WebCore: A client MUST close a connection if it detects a masked frame
https://bugs.webkit.org/show_bug.cgi?id=81361

Patch by Li Yin <[email protected]> on 2012-03-22
Reviewed by Kent Tamura.

A server must not mask any frames that it sends to the client.
Change the test case, not mask the frames from server to client.

Test: http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html

* Modules/websockets/WebSocketChannel.cpp:
(WebCore::WebSocketChannel::processFrame):

LayoutTests: [WebSocket]A client must close a connection if it detects a masked frame
https://bugs.webkit.org/show_bug.cgi?id=81361

Patch by Li Yin <[email protected]> on 2012-03-22
Reviewed by Kent Tamura.

* http/tests/websocket/tests/hybi/invalid-masked-frames-from-server-expected.txt: Added.
* http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html: Added.
* http/tests/websocket/tests/hybi/invalid-masked-frames-from-server_wsh.py: Added.
* http/tests/websocket/tests/hybi/unmasked-frames-expected.txt: Renamed from LayoutTests/http/tests/websocket/tests/hybi/masked-frames-expected.txt.
* http/tests/websocket/tests/hybi/unmasked-frames.html: Renamed from LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html.
* http/tests/websocket/tests/hybi/unmasked-frames_wsh.py: Renamed from LayoutTests/http/tests/websocket/tests/hybi/masked-frames_wsh.py.
(web_socket_do_extra_handshake):
(web_socket_transfer_data):

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (111828 => 111829)


--- trunk/LayoutTests/ChangeLog	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/LayoutTests/ChangeLog	2012-03-23 06:08:40 UTC (rev 111829)
@@ -1,5 +1,21 @@
 2012-03-22  Li Yin  <[email protected]>
 
+        [WebSocket]A client must close a connection if it detects a masked frame
+        https://bugs.webkit.org/show_bug.cgi?id=81361
+
+        Reviewed by Kent Tamura.
+
+        * http/tests/websocket/tests/hybi/invalid-masked-frames-from-server-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html: Added.
+        * http/tests/websocket/tests/hybi/invalid-masked-frames-from-server_wsh.py: Added.
+        * http/tests/websocket/tests/hybi/unmasked-frames-expected.txt: Renamed from LayoutTests/http/tests/websocket/tests/hybi/masked-frames-expected.txt.
+        * http/tests/websocket/tests/hybi/unmasked-frames.html: Renamed from LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html.
+        * http/tests/websocket/tests/hybi/unmasked-frames_wsh.py: Renamed from LayoutTests/http/tests/websocket/tests/hybi/masked-frames_wsh.py.
+        (web_socket_do_extra_handshake):
+        (web_socket_transfer_data):
+
+2012-03-22  Li Yin  <[email protected]>
+
         [WebSocket]The minimal number of bytes MUST be used to encode the length
         https://bugs.webkit.org/show_bug.cgi?id=81443
 

Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server-expected.txt (0 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server-expected.txt	2012-03-23 06:08:40 UTC (rev 111829)
@@ -0,0 +1,11 @@
+CONSOLE MESSAGE: A server must not mask any frames that it sends to the client.
+Test whether WebSocket aborts the connection when it receives an masked frames from server.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+onopen() was called.
+PASS closeEvent.wasClean is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Copied: trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html (from rev 111828, trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html) (0 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html	2012-03-23 06:08:40 UTC (rev 111829)
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Test whether WebSocket aborts the connection when it receives an masked frames from server.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var url = ""
+var ws = new WebSocket(url);
+var closeEvent;
+
+ws._onopen_ = function()
+{
+    debug("onopen() was called.");
+};
+
+ws._onmessage_ = function(event)
+{
+    var message = event.data;
+    testFailed("onmessage() was called. (message = \"" + message + "\")");
+};
+
+ws._onclose_ = function(event)
+{
+    closeEvent = event;
+    shouldBeFalse("closeEvent.wasClean");
+    finishJSTest();
+};
+
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server_wsh.py (0 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server_wsh.py	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/invalid-masked-frames-from-server_wsh.py	2012-03-23 06:08:40 UTC (rev 111829)
@@ -0,0 +1,8 @@
+from mod_pywebsocket import stream
+
+def web_socket_do_extra_handshake(request):
+    pass
+
+def web_socket_transfer_data(request):
+    # pywebsocket does not mask message by default. We need to build a frame manually to mask it.
+    request.connection.write(stream.create_text_frame('The Masked Message', mask=True))

Deleted: trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames-expected.txt (111828 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames-expected.txt	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames-expected.txt	2012-03-23 06:08:40 UTC (rev 111829)
@@ -1,18 +0,0 @@
-Receive masked WebSocket frames.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-onopen() was called.
-onmessage() was called. (message = "First message")
-onmessage() was called. (message = "Fragmented message")
-onmessage() was called. (message = "")
-onmessage() was called. (message = "END")
-PASS actualMessages.length === expectedMessages.length is true
-PASS actualMessages[0] is "First message"
-PASS actualMessages[1] is "Fragmented message"
-PASS actualMessages[2] is ""
-PASS closeEvent.wasClean is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-

Deleted: trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html (111828 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html	2012-03-23 06:08:40 UTC (rev 111829)
@@ -1,52 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<script src=""
-</head>
-<body>
-<div id="description"></div>
-<div id="console"></div>
-<script>
-description("Receive masked WebSocket frames.");
-
-window.jsTestIsAsync = true;
-if (window.layoutTestController)
-    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
-
-var url = ""
-var ws = new WebSocket(url);
-var closeEvent;
-var expectedMessages = ["First message", "Fragmented message", ""];
-var actualMessages = [];
-
-ws._onopen_ = function()
-{
-    debug("onopen() was called.");
-    ws.close();
-};
-
-ws._onmessage_ = function(event)
-{
-    var message = event.data;
-    debug("onmessage() was called. (message = \"" + message + "\")");
-    if (message === "END") {
-        ws.close();
-        return;
-    }
-    actualMessages.push(message);
-};
-
-ws._onclose_ = function(event)
-{
-    closeEvent = event;
-    shouldBeTrue("actualMessages.length === expectedMessages.length");
-    for (var i = 0; i < expectedMessages.length; ++i)
-        shouldBeEqualToString("actualMessages[" + i + "]", expectedMessages[i]);
-    shouldBeTrue("closeEvent.wasClean");
-    finishJSTest();
-};
-
-</script>
-<script src=""
-</body>
-</html>

Deleted: trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames_wsh.py (111828 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames_wsh.py	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames_wsh.py	2012-03-23 06:08:40 UTC (rev 111829)
@@ -1,35 +0,0 @@
-from mod_pywebsocket import common
-from mod_pywebsocket import handshake
-from mod_pywebsocket import stream
-from mod_pywebsocket import msgutil
-
-
-def web_socket_do_extra_handshake(request):
-    pass
-
-
-def web_socket_transfer_data(request):
-    # pywebsocket does not mask message by default. We need to build a frame manually to mask it.
-    request.connection.write(stream.create_text_frame('First message', mask=True))
-
-    request.connection.write(stream.create_text_frame('Fragmented ', opcode=common.OPCODE_TEXT, fin=0, mask=True))
-    request.connection.write(stream.create_text_frame('message', opcode=common.OPCODE_CONTINUATION, fin=1, mask=True))
-
-    request.connection.write(stream.create_text_frame('', mask=True))
-
-    msgutil.send_message(request, 'END')
-
-    # Wait for the client to start closing handshake.
-    # To receive a close frame, we must use an internal method of request.ws_stream.
-    opcode, payload, final, reserved1, reserved2, reserved3 = request.ws_stream._receive_frame()
-    assert opcode == common.OPCODE_CLOSE
-    assert final
-    assert not reserved1
-    assert not reserved2
-    assert not reserved3
-
-    # Send a masked close frame. Clients should be able to handle this frame and
-    # the WebSocket object should be closed cleanly.
-    request.connection.write(stream.create_close_frame('', mask=True))
-
-    raise handshake.AbortedByUserException('Abort the connection') # Prevents pywebsocket from starting its own closing handshake.

Copied: trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames-expected.txt (from rev 111828, trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames-expected.txt) (0 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames-expected.txt	2012-03-23 06:08:40 UTC (rev 111829)
@@ -0,0 +1,18 @@
+Receive unmasked WebSocket frames.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+onopen() was called.
+onmessage() was called. (message = "First message")
+onmessage() was called. (message = "Fragmented message")
+onmessage() was called. (message = "")
+onmessage() was called. (message = "END")
+PASS actualMessages.length === expectedMessages.length is true
+PASS actualMessages[0] is "First message"
+PASS actualMessages[1] is "Fragmented message"
+PASS actualMessages[2] is ""
+PASS closeEvent.wasClean is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Copied: trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames.html (from rev 111828, trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames.html) (0 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames.html	2012-03-23 06:08:40 UTC (rev 111829)
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Receive unmasked WebSocket frames.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var url = ""
+var ws = new WebSocket(url);
+var closeEvent;
+var expectedMessages = ["First message", "Fragmented message", ""];
+var actualMessages = [];
+
+ws._onopen_ = function()
+{
+    debug("onopen() was called.");
+    ws.close();
+};
+
+ws._onmessage_ = function(event)
+{
+    var message = event.data;
+    debug("onmessage() was called. (message = \"" + message + "\")");
+    if (message === "END") {
+        ws.close();
+        return;
+    }
+    actualMessages.push(message);
+};
+
+ws._onclose_ = function(event)
+{
+    closeEvent = event;
+    shouldBeTrue("actualMessages.length === expectedMessages.length");
+    for (var i = 0; i < expectedMessages.length; ++i)
+        shouldBeEqualToString("actualMessages[" + i + "]", expectedMessages[i]);
+    shouldBeTrue("closeEvent.wasClean");
+    finishJSTest();
+};
+
+</script>
+<script src=""
+</body>
+</html>

Copied: trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames_wsh.py (from rev 111828, trunk/LayoutTests/http/tests/websocket/tests/hybi/masked-frames_wsh.py) (0 => 111829)


--- trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames_wsh.py	                        (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/unmasked-frames_wsh.py	2012-03-23 06:08:40 UTC (rev 111829)
@@ -0,0 +1,35 @@
+from mod_pywebsocket import common
+from mod_pywebsocket import handshake
+from mod_pywebsocket import stream
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass
+
+
+def web_socket_transfer_data(request):
+    # pywebsocket does not mask message by default. We need to build a frame manually to mask it.
+    request.connection.write(stream.create_text_frame('First message', mask=False))
+
+    request.connection.write(stream.create_text_frame('Fragmented ', opcode=common.OPCODE_TEXT, fin=0, mask=False))
+    request.connection.write(stream.create_text_frame('message', opcode=common.OPCODE_CONTINUATION, fin=1, mask=False))
+
+    request.connection.write(stream.create_text_frame('', mask=False))
+
+    msgutil.send_message(request, 'END')
+
+    # Wait for the client to start closing handshake.
+    # To receive a close frame, we must use an internal method of request.ws_stream.
+    opcode, payload, final, reserved1, reserved2, reserved3 = request.ws_stream._receive_frame()
+    assert opcode == common.OPCODE_CLOSE
+    assert final
+    assert not reserved1
+    assert not reserved2
+    assert not reserved3
+
+    # Send a masked close frame. Clients should be able to handle this frame and
+    # the WebSocket object should be closed cleanly.
+    request.connection.write(stream.create_close_frame('', mask=False))
+
+    raise handshake.AbortedByUserException('Abort the connection') # Prevents pywebsocket from starting its own closing handshake.

Modified: trunk/Source/WebCore/ChangeLog (111828 => 111829)


--- trunk/Source/WebCore/ChangeLog	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/Source/WebCore/ChangeLog	2012-03-23 06:08:40 UTC (rev 111829)
@@ -1,5 +1,20 @@
 2012-03-22  Li Yin  <[email protected]>
 
+        A client MUST close a connection if it detects a masked frame
+        https://bugs.webkit.org/show_bug.cgi?id=81361
+
+        Reviewed by Kent Tamura.
+
+        A server must not mask any frames that it sends to the client.
+        Change the test case, not mask the frames from server to client.
+        
+        Test: http/tests/websocket/tests/hybi/invalid-masked-frames-from-server.html
+
+        * Modules/websockets/WebSocketChannel.cpp:
+        (WebCore::WebSocketChannel::processFrame):
+
+2012-03-22  Li Yin  <[email protected]>
+
         [WebSocket]The minimal number of bytes MUST be used to encode the length
         https://bugs.webkit.org/show_bug.cgi?id=81443
 

Modified: trunk/Source/WebCore/Modules/websockets/WebSocketChannel.cpp (111828 => 111829)


--- trunk/Source/WebCore/Modules/websockets/WebSocketChannel.cpp	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/Source/WebCore/Modules/websockets/WebSocketChannel.cpp	2012-03-23 06:08:40 UTC (rev 111829)
@@ -569,6 +569,10 @@
     unsigned char opCode = firstByte & opCodeMask;
 
     bool masked = secondByte & maskBit;
+    if (masked) {
+        fail("A server must not mask any frames that it sends to the client.");
+        return FrameError;
+    }
     uint64_t payloadLength64 = secondByte & payloadLengthMask;
     if (payloadLength64 > maxPayloadLengthWithoutExtendedLengthField) {
         int extendedPayloadLengthSize;
@@ -601,32 +605,24 @@
 #else
     static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFull;
 #endif
-    size_t maskingKeyLength = masked ? maskingKeyWidthInBytes : 0;
-    if (payloadLength64 > maxPayloadLength || payloadLength64 + maskingKeyLength > numeric_limits<size_t>::max()) {
+    if (payloadLength64 > maxPayloadLength || payloadLength64 > numeric_limits<size_t>::max()) {
         fail("WebSocket frame length too large: " + String::number(payloadLength64) + " bytes");
         return FrameError;
     }
     size_t payloadLength = static_cast<size_t>(payloadLength64);
 
-    if (static_cast<size_t>(bufferEnd - p) < maskingKeyLength + payloadLength)
+    if (static_cast<size_t>(bufferEnd - p) < payloadLength)
         return FrameIncomplete;
 
-    if (masked) {
-        const char* maskingKey = p;
-        char* payload = const_cast<char*>(p + maskingKeyWidthInBytes);
-        for (size_t i = 0; i < payloadLength; ++i)
-            payload[i] ^= maskingKey[i % maskingKeyWidthInBytes]; // Unmask the payload.
-    }
-
     frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode);
     frame.final = final;
     frame.compress = compress;
     frame.reserved2 = reserved2;
     frame.reserved3 = reserved3;
     frame.masked = masked;
-    frame.payload = p + maskingKeyLength;
+    frame.payload = p;
     frame.payloadLength = payloadLength;
-    frameEnd = p + maskingKeyLength + payloadLength;
+    frameEnd = p + payloadLength;
     return FrameOK;
 }
 

Modified: trunk/Source/WebCore/Modules/websockets/WebSocketChannel.h (111828 => 111829)


--- trunk/Source/WebCore/Modules/websockets/WebSocketChannel.h	2012-03-23 06:04:00 UTC (rev 111828)
+++ trunk/Source/WebCore/Modules/websockets/WebSocketChannel.h	2012-03-23 06:08:40 UTC (rev 111829)
@@ -138,7 +138,7 @@
         FrameError
     };
 
-    ParseFrameResult parseFrame(WebSocketFrame&, const char*& frameEnd); // May modify part of m_buffer to unmask the frame.
+    ParseFrameResult parseFrame(WebSocketFrame&, const char*& frameEnd);
 
     bool processFrame();
     bool processFrameHixie76();
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to