Skip to content

Commit ceb0992

Browse files
authored
Merge pull request #21 from AlexanderShirokih/master
add frame fragmentation support (continuation)
2 parents a3dc773 + e978d45 commit ceb0992

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

src/main/java/tech/gusavila92/websocketclient/WebSocketClient.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -947,17 +947,28 @@ private void send(int opcode, byte[] payload) throws IOException {
947947
* @throws IOException
948948
*/
949949
private void read() throws IOException {
950+
// If message contains fragmented parts we should put it all together.
951+
LinkedList<byte[]> messageParts = new LinkedList<>();
952+
950953
// The first byte of every data frame
951954
int firstByte;
955+
int opcode = 0;
952956

953957
// Loop until end of stream is reached.
954958
while ((firstByte = bis.read()) != -1) {
955959
// Data contained in the first byte
956-
// int fin = (firstByte << 24) >>> 31;
960+
// If the flag is on we have more frames for this message.
961+
int fin = (firstByte << 24) >>> 31;
957962
// int rsv1 = (firstByte << 25) >>> 31;
958963
// int rsv2 = (firstByte << 26) >>> 31;
959964
// int rsv3 = (firstByte << 27) >>> 31;
960-
int opcode = (firstByte << 28) >>> 28;
965+
966+
// Only first frame will have real opcode (text or binary),
967+
// In next frames opcode will be zero (continuation)
968+
if (messageParts.isEmpty())
969+
opcode = (firstByte << 28) >>> 28;
970+
971+
boolean isLast = fin == 1;
961972

962973
// Reads the second byte
963974
int secondByte = bis.read();
@@ -1010,10 +1021,39 @@ private void read() throws IOException {
10101021
data[i] = b;
10111022
}
10121023

1024+
if (isLast) {
1025+
// If we already have some fragments, just add last and put it together
1026+
if (!messageParts.isEmpty()) {
1027+
messageParts.add(data);
1028+
// Calculate total size of all parts
1029+
int fullSize = 0;
1030+
int offset = 0;
1031+
for (byte[] fragment : messageParts)
1032+
fullSize += fragment.length;
1033+
1034+
byte[] fullMessage = new byte[fullSize];
1035+
1036+
// Copy all parts into one array
1037+
for (byte[] fragment : messageParts) {
1038+
System.arraycopy(fragment, 0, fullMessage, offset, fragment.length);
1039+
offset += fragment.length;
1040+
}
1041+
1042+
data = fullMessage;
1043+
messageParts.clear();
1044+
}
1045+
// else: Single framed message - do nothing
1046+
} else {
1047+
// Collect this fragment and go read next frame.
1048+
messageParts.add(data);
1049+
continue;
1050+
}
1051+
10131052
// Execute the action depending on the opcode
10141053
switch (opcode) {
10151054
case OPCODE_CONTINUATION:
1016-
// Should be implemented
1055+
// Implemented above
1056+
// I think this case should never happen
10171057
break;
10181058
case OPCODE_TEXT:
10191059
notifyOnTextReceived(new String(data, Charset.forName("UTF-8")));

0 commit comments

Comments
 (0)