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();