This commit is contained in:
@@ -206,7 +206,7 @@ public final class WebSocketPacket {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
WebSocketPacket decode(final Logger logger, final ByteBuffer buffer, ByteBuffer... exbuffers) {
|
WebSocketPacket decode(final Logger logger, final ByteBuffer buffer, ByteBuffer... exbuffers) {
|
||||||
final boolean debug = true;
|
final boolean debug = false; //调试开关
|
||||||
if (debug) {
|
if (debug) {
|
||||||
int remain = buffer.remaining();
|
int remain = buffer.remaining();
|
||||||
if (exbuffers != null) {
|
if (exbuffers != null) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import static org.redkale.net.http.WebSocket.*;
|
|||||||
import org.redkale.net.http.WebSocketPacket.FrameType;
|
import org.redkale.net.http.WebSocketPacket.FrameType;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -282,281 +281,4 @@ public class WebSocketRunner implements Runnable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Masker {
|
|
||||||
|
|
||||||
public static final int MASK_SIZE = 4;
|
|
||||||
|
|
||||||
private ByteBuffer buffer;
|
|
||||||
|
|
||||||
private ByteBuffer[] exbuffers;
|
|
||||||
|
|
||||||
private byte[] mask;
|
|
||||||
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
public Masker(ByteBuffer buffer, ByteBuffer... exbuffers) {
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.exbuffers = exbuffers == null || exbuffers.length == 0 ? null : exbuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Masker() {
|
|
||||||
generateMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int remaining() {
|
|
||||||
int r = buffer.remaining();
|
|
||||||
if (exbuffers != null) {
|
|
||||||
for (ByteBuffer b : exbuffers) {
|
|
||||||
r += b.remaining();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte get() {
|
|
||||||
return buffer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] get(final int size) {
|
|
||||||
byte[] bytes = new byte[size];
|
|
||||||
if (buffer.remaining() >= size) {
|
|
||||||
buffer.get(bytes);
|
|
||||||
} else { //必须有 exbuffers
|
|
||||||
int offset = buffer.remaining();
|
|
||||||
buffer.get(bytes, 0, buffer.remaining());
|
|
||||||
for (ByteBuffer b : exbuffers) {
|
|
||||||
b.get(bytes, offset, b.remaining());
|
|
||||||
offset += b.remaining();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte unmask() {
|
|
||||||
final byte b = get();
|
|
||||||
return mask == null ? b : (byte) (b ^ mask[index++ % MASK_SIZE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] unmask(int count) {
|
|
||||||
byte[] bytes = get(count);
|
|
||||||
if (mask != null) {
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
bytes[i] ^= mask[index++ % MASK_SIZE];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateMask() {
|
|
||||||
mask = new byte[MASK_SIZE];
|
|
||||||
new SecureRandom().nextBytes(mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mask(byte[] bytes, int location, byte b) {
|
|
||||||
bytes[location] = mask == null ? b : (byte) (b ^ mask[index++ % MASK_SIZE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void mask(byte[] target, int location, byte[] bytes) {
|
|
||||||
if (bytes != null && target != null) {
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
target[location + i] = mask == null ? bytes[i] : (byte) (bytes[i] ^ mask[index++ % MASK_SIZE]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] maskAndPrepend(byte[] packet) {
|
|
||||||
byte[] masked = new byte[packet.length + MASK_SIZE];
|
|
||||||
System.arraycopy(getMask(), 0, masked, 0, MASK_SIZE);
|
|
||||||
mask(masked, MASK_SIZE, packet);
|
|
||||||
return masked;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBuffer(ByteBuffer buffer) {
|
|
||||||
this.buffer = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getMask() {
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readMask() {
|
|
||||||
mask = get(MASK_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class WebSocketCoder {
|
|
||||||
|
|
||||||
protected byte inFragmentedType;
|
|
||||||
|
|
||||||
protected byte outFragmentedType;
|
|
||||||
|
|
||||||
protected final boolean maskData = false;
|
|
||||||
|
|
||||||
protected boolean processingFragment;
|
|
||||||
|
|
||||||
private boolean debugable;
|
|
||||||
|
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 0 1 2 3
|
|
||||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
||||||
* +-+-+-+-+-------+-+-------------+-------------------------------+
|
|
||||||
* |F|R|R|R| opcode|M| Payload len | Extended payload length |
|
|
||||||
* |I|S|S|S| (4) |A| (7) | (16/64) |
|
|
||||||
* |N|V|V|V| |S| | (if payload len==126/127) |
|
|
||||||
* | |1|2|3| |K| | |
|
|
||||||
* +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
|
||||||
* | Extended payload length continued, if payload len == 127 |
|
|
||||||
* + - - - - - - - - - - - - - - - +-------------------------------+
|
|
||||||
* | |Masking-key, if MASK set to 1 |
|
|
||||||
* +-------------------------------+-------------------------------+
|
|
||||||
* | Masking-key (continued) | Payload Data |
|
|
||||||
* +-------------------------------- - - - - - - - - - - - - - - - +
|
|
||||||
* : Payload Data continued :
|
|
||||||
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|
|
||||||
* | Payload Data continued |
|
|
||||||
* +-----------------------------------------------------------------------+
|
|
||||||
*
|
|
||||||
* @param buffer
|
|
||||||
* @param exbuffers
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public WebSocketPacket decode(final ByteBuffer buffer, ByteBuffer... exbuffers) {
|
|
||||||
final boolean debug = this.debugable;
|
|
||||||
if (debug) {
|
|
||||||
int remain = buffer.remaining();
|
|
||||||
if (exbuffers != null) {
|
|
||||||
for (ByteBuffer b : exbuffers) {
|
|
||||||
remain += b == null ? 0 : b.remaining();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.log(Level.FINEST, "read web socket message's length = " + remain);
|
|
||||||
}
|
|
||||||
if (buffer.remaining() < 2) return null;
|
|
||||||
byte opcode = buffer.get();
|
|
||||||
final boolean last = (opcode & 0b1000000) != 0;
|
|
||||||
final boolean checkrsv = false;//暂时不校验
|
|
||||||
if (checkrsv && (opcode & 0b01110000) != 0) {
|
|
||||||
if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + opcode + ")");
|
|
||||||
return null; //rsv1 rsv2 rsv3 must be 0
|
|
||||||
}
|
|
||||||
//0x00 表示一个后续帧
|
|
||||||
//0x01 表示一个文本帧
|
|
||||||
//0x02 表示一个二进制帧
|
|
||||||
//0x03-07 为以后的非控制帧保留
|
|
||||||
//0x8 表示一个连接关闭
|
|
||||||
//0x9 表示一个ping
|
|
||||||
//0xA 表示一个pong
|
|
||||||
//0x0B-0F 为以后的控制帧保留
|
|
||||||
final boolean control = (opcode & 0x08) == 0x08; //是否控制帧
|
|
||||||
//final boolean continuation = opcode == 0;
|
|
||||||
FrameType type = FrameType.valueOf(opcode & 0xf);
|
|
||||||
if (type == FrameType.CLOSE) {
|
|
||||||
if (debug) logger.log(Level.FINEST, " receive close command from websocket client");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
byte lengthCode = buffer.get();
|
|
||||||
final Masker masker = new Masker(buffer, exbuffers);
|
|
||||||
final boolean masked = (lengthCode & 0x80) == 0x80;
|
|
||||||
if (masked) lengthCode ^= 0x80; //mask
|
|
||||||
int length;
|
|
||||||
if (lengthCode <= 125) {
|
|
||||||
length = lengthCode;
|
|
||||||
} else {
|
|
||||||
if (control) {
|
|
||||||
if (debug) logger.log(Level.FINE, " receive control command from websocket client");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int lengthBytes = lengthCode == 126 ? 2 : 8;
|
|
||||||
if (buffer.remaining() < lengthBytes) {
|
|
||||||
if (debug) logger.log(Level.FINE, " read illegal message length from websocket, expect " + lengthBytes + " but " + buffer.remaining());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
length = toInt(masker.unmask(lengthBytes));
|
|
||||||
}
|
|
||||||
if (masked) {
|
|
||||||
if (buffer.remaining() < Masker.MASK_SIZE) {
|
|
||||||
if (debug) logger.log(Level.FINE, " read illegal masker length from websocket, expect " + Masker.MASK_SIZE + " but " + buffer.remaining());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
masker.readMask();
|
|
||||||
}
|
|
||||||
if (masker.remaining() < length) {
|
|
||||||
if (debug) logger.log(Level.FINE, " read illegal remaining length from websocket, expect " + length + " but " + masker.remaining());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final byte[] data = masker.unmask(length);
|
|
||||||
if (data.length != length) {
|
|
||||||
if (debug) logger.log(Level.FINE, " read illegal unmask length from websocket, expect " + length + " but " + data.length);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new WebSocketPacket(type, data, last);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] encode(WebSocketPacket frame) {
|
|
||||||
byte opcode = (byte) (frame.type.getValue() | 0x80);
|
|
||||||
final byte[] bytes = frame.getContent();
|
|
||||||
final byte[] lengthBytes = encodeLength(bytes.length);
|
|
||||||
|
|
||||||
int length = 1 + lengthBytes.length + bytes.length + (maskData ? Masker.MASK_SIZE : 0);
|
|
||||||
int payloadStart = 1 + lengthBytes.length + (maskData ? Masker.MASK_SIZE : 0);
|
|
||||||
final byte[] packet = new byte[length];
|
|
||||||
packet[0] = opcode;
|
|
||||||
System.arraycopy(lengthBytes, 0, packet, 1, lengthBytes.length);
|
|
||||||
if (maskData) {
|
|
||||||
Masker masker = new Masker();
|
|
||||||
packet[1] |= 0x80;
|
|
||||||
masker.mask(packet, payloadStart, bytes);
|
|
||||||
System.arraycopy(masker.getMask(), 0, packet, payloadStart - Masker.MASK_SIZE, Masker.MASK_SIZE);
|
|
||||||
} else {
|
|
||||||
System.arraycopy(bytes, 0, packet, payloadStart, bytes.length);
|
|
||||||
}
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] encodeLength(final int length) {
|
|
||||||
byte[] lengthBytes;
|
|
||||||
if (length <= 125) {
|
|
||||||
lengthBytes = new byte[1];
|
|
||||||
lengthBytes[0] = (byte) length;
|
|
||||||
} else {
|
|
||||||
byte[] b = toArray(length);
|
|
||||||
if (length <= 0xFFFF) {
|
|
||||||
lengthBytes = new byte[3];
|
|
||||||
lengthBytes[0] = 126;
|
|
||||||
System.arraycopy(b, 6, lengthBytes, 1, 2);
|
|
||||||
} else {
|
|
||||||
lengthBytes = new byte[9];
|
|
||||||
lengthBytes[0] = 127;
|
|
||||||
System.arraycopy(b, 0, lengthBytes, 1, 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lengthBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] toArray(long length) {
|
|
||||||
long value = length;
|
|
||||||
byte[] b = new byte[8];
|
|
||||||
for (int i = 7; i >= 0 && value > 0; i--) {
|
|
||||||
b[i] = (byte) (value & 0xFF);
|
|
||||||
value >>= 8;
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int toInt(byte[] bytes) {
|
|
||||||
int value = 0;
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
value <<= 8;
|
|
||||||
value ^= (int) bytes[i] & 0xFF;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user