Преглед на файлове

[websocket]: Fix ClientWebSocket.ReceiveAsync() with small buffer; bug #22704.

When calling ClientWebSocket.ReceiveAsync() with a buffer that's smaller than
the received chunk, we need to cache the header until next call.
Martin Baulig преди 11 години
родител
ревизия
bbbcc73bde
променени са 1 файла, в които са добавени 37 реда и са изтрити 24 реда
  1. 37 24
      mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs

+ 37 - 24
mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs

@@ -61,6 +61,7 @@ namespace System.Net.WebSockets
 		const int HeaderMaxLength = 14;
 		byte[] headerBuffer;
 		byte[] sendBuffer;
+		long remaining;
 
 		public ClientWebSocket ()
 		{
@@ -226,32 +227,43 @@ namespace System.Net.WebSockets
 			ValidateArraySegment (buffer);
 			return Task.Run (() => {
 				EnsureWebSocketState (WebSocketState.Open, WebSocketState.CloseSent);
-				// First read the two first bytes to know what we are doing next
-				connection.Read (req, headerBuffer, 0, 2);
-				var isLast = (headerBuffer[0] >> 7) > 0;
-				var isMasked = (headerBuffer[1] >> 7) > 0;
-				int mask = 0;
-				var type = WireToMessageType ((byte)(headerBuffer[0] & 0xF));
-				long length = headerBuffer[1] & 0x7F;
-				int offset = 0;
-				if (length == 126) {
-					offset = 2;
-					connection.Read (req, headerBuffer, 2, offset);
+
+				bool isLast;
+				WebSocketMessageType type;
+				long length;
+
+				if (remaining == 0) {
+					// First read the two first bytes to know what we are doing next
+					connection.Read (req, headerBuffer, 0, 2);
+					isLast = (headerBuffer[0] >> 7) > 0;
+					var isMasked = (headerBuffer[1] >> 7) > 0;
+					int mask = 0;
+					type = WireToMessageType ((byte)(headerBuffer[0] & 0xF));
+					length = headerBuffer[1] & 0x7F;
+					int offset = 0;
+					if (length == 126) {
+						offset = 2;
+						connection.Read (req, headerBuffer, 2, offset);
 					length = (headerBuffer[2] << 8) | headerBuffer[3];
-				} else if (length == 127) {
-					offset = 8;
-					connection.Read (req, headerBuffer, 2, offset);
-					length = 0;
-					for (int i = 2; i <= 9; i++)
-						length = (length << 8) | headerBuffer[i];
-				}
+					} else if (length == 127) {
+						offset = 8;
+						connection.Read (req, headerBuffer, 2, offset);
+						length = 0;
+						for (int i = 2; i <= 9; i++)
+							length = (length << 8) | headerBuffer[i];
+					}
 
-				if (isMasked) {
-					connection.Read (req, headerBuffer, 2 + offset, 4);
-					for (int i = 0; i < 4; i++) {
-						var pos = i + offset + 2;
-						mask = (mask << 8) | headerBuffer[pos];
+					if (isMasked) {
+						connection.Read (req, headerBuffer, 2 + offset, 4);
+						for (int i = 0; i < 4; i++) {
+							var pos = i + offset + 2;
+							mask = (mask << 8) | headerBuffer[pos];
+						}
 					}
+				} else {
+					isLast = (headerBuffer[0] >> 7) > 0;
+					type = WireToMessageType ((byte)(headerBuffer[0] & 0xF));
+					length = remaining;
 				}
 
 				if (type == WebSocketMessageType.Close) {
@@ -264,8 +276,9 @@ namespace System.Net.WebSockets
 				} else {
 					var readLength = (int)(buffer.Count < length ? buffer.Count : length);
 					connection.Read (req, buffer.Array, buffer.Offset, readLength);
+					remaining = length - readLength;
 
-					return new WebSocketReceiveResult ((int)length, type, isLast);
+					return new WebSocketReceiveResult ((int)readLength, type, isLast && remaining == 0);
 				}
 			});
 		}