diff --git a/src/main/java/org/java_websocket/WebSocketImpl.java b/src/main/java/org/java_websocket/WebSocketImpl.java index 3289aefcf..d4c413f72 100644 --- a/src/main/java/org/java_websocket/WebSocketImpl.java +++ b/src/main/java/org/java_websocket/WebSocketImpl.java @@ -393,7 +393,9 @@ private void decodeFrames(ByteBuffer socketBuffer) { try { frames = draft.translateFrame(socketBuffer); for (Framedata f : frames) { - log.trace("matched frame: {}", f); + if (log.isTraceEnabled()) { + log.trace("matched frame: {}", f); + } draft.processFrame(this, f); } } catch (LimitExceededException e) { @@ -673,12 +675,27 @@ private void send(Collection frames) { } ArrayList outgoingFrames = new ArrayList<>(); for (Framedata f : frames) { - log.trace("send frame: {}", f); + if (log.isTraceEnabled()) { + log.trace("send frame: {}", f); + } outgoingFrames.add(draft.createBinaryFrame(f)); } write(outgoingFrames); } + public ByteBuffer createEncodedBinaryFrame(Framedata framedata) { + return draft.createBinaryFrame(framedata); + } + + public void sendEncodedBinaryFrame(ByteBuffer binaryFrame) { + List bufs = new ArrayList<>(4); + sendEncodedBinaryFrames(bufs); + } + + public void sendEncodedBinaryFrames(List outgoingFrames) { + write(outgoingFrames); + } + @Override public void sendFragmentedFrame(Opcode op, ByteBuffer buffer, boolean fin) { send(draft.continuousFrame(op, buffer, fin)); @@ -734,8 +751,11 @@ public void startHandshake(ClientHandshakeBuilder handshakedata) } private void write(ByteBuffer buf) { - log.trace("write({}): {}", buf.remaining(), - buf.remaining() > 1000 ? "too big to display" : new String(buf.array())); + // should check isTraceEnabled() to avoid performance down because of log + if (log.isTraceEnabled()) { + log.trace("write({}): {}", buf.remaining(), + buf.remaining() > 1000 ? "too big to display" : new String(buf.array())); + } outQueue.add(buf); wsl.onWriteDemand(this); diff --git a/src/main/java/org/java_websocket/drafts/Draft_6455.java b/src/main/java/org/java_websocket/drafts/Draft_6455.java index eb4879976..8b8b933a2 100644 --- a/src/main/java/org/java_websocket/drafts/Draft_6455.java +++ b/src/main/java/org/java_websocket/drafts/Draft_6455.java @@ -27,6 +27,7 @@ import java.math.BigInteger; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -509,11 +510,31 @@ private ByteBuffer createByteBufferFromFramedata(Framedata framedata) { throw new IllegalStateException("Size representation not supported/specified"); } if (mask) { - ByteBuffer maskkey = ByteBuffer.allocate(4); - maskkey.putInt(reuseableRandom.nextInt()); - buf.put(maskkey.array()); - for (int i = 0; mes.hasRemaining(); i++) { - buf.put((byte) (mes.get() ^ maskkey.get(i % 4))); + int maskInt = reuseableRandom.nextInt(); + if (useFastMask) { + //default ByteOrder.BIG_ENDIAN + ByteBuffer maskLongkey = ByteBuffer.allocate(8); + maskLongkey.putInt(maskInt); + maskLongkey.putInt(maskInt); + buf.putInt(maskInt); + // n / 8 eq n >> 3 + int length = mes.remaining() >> 3; + long maskLong = maskLongkey.getLong(0); + for (int i = 0; i < length; i++) { + buf.putLong(mes.getLong() ^ maskLong); + } + for (int i = 0; mes.hasRemaining(); i++) { + // x % 2^n 为 x & (2^n - 1) + buf.put((byte) (mes.get() ^ maskLongkey.get(i & 3))); + } + } else { + ByteBuffer maskkey = ByteBuffer.allocate(4); + maskkey.putInt(maskInt); + buf.put(maskkey.array()); + for (int i = 0; mes.hasRemaining(); i++) { + // x % 2^n 为 x & (2^n - 1) + buf.put((byte) (mes.get() ^ maskkey.get(i & 3))); + } } } else { buf.put(mes); @@ -525,6 +546,8 @@ private ByteBuffer createByteBufferFromFramedata(Framedata framedata) { return buf; } + public static boolean useFastMask = true; + private Framedata translateSingleFrame(ByteBuffer buffer) throws IncompleteException, InvalidDataException { if (buffer == null) { @@ -592,6 +615,11 @@ private Framedata translateSingleFrame(ByteBuffer buffer) (frame.getPayloadData().remaining() > 1000 ? "too big to display" : new String(frame.getPayloadData().array()))); } + + if (frame instanceof TextFrame) { + ((TextFrame) frame).setCanSkipCheckUTF8PlayLoad(true); + } + frame.isValid(); return frame; } @@ -791,6 +819,7 @@ public List createFrames(ByteBuffer binary, boolean mask) { public List createFrames(String text, boolean mask) { TextFrame curframe = new TextFrame(); curframe.setPayload(ByteBuffer.wrap(Charsetfunctions.utf8Bytes(text))); + curframe.setCanSkipCheckUTF8PlayLoad(true); curframe.setTransferemasked(mask); try { curframe.isValid(); diff --git a/src/main/java/org/java_websocket/framing/TextFrame.java b/src/main/java/org/java_websocket/framing/TextFrame.java index 52154b47e..d905d6cc4 100644 --- a/src/main/java/org/java_websocket/framing/TextFrame.java +++ b/src/main/java/org/java_websocket/framing/TextFrame.java @@ -25,15 +25,19 @@ package org.java_websocket.framing; +import java.nio.ByteBuffer; import org.java_websocket.enums.Opcode; import org.java_websocket.exceptions.InvalidDataException; import org.java_websocket.util.Charsetfunctions; + /** * Class to represent a text frames */ public class TextFrame extends DataFrame { + boolean canSkipCheckUTF8PlayLoad = false; + /** * constructor which sets the opcode of this frame to text */ @@ -44,8 +48,26 @@ public TextFrame() { @Override public void isValid() throws InvalidDataException { super.isValid(); - if (!Charsetfunctions.isValidUTF8(getPayloadData())) { - throw new InvalidDataException(CloseFrame.NO_UTF8, "Received text is no valid utf8 string!"); + if (!canSkipCheckUTF8PlayLoad) { + if (!Charsetfunctions.isValidUTF8(getPayloadData())) { + throw new InvalidDataException(CloseFrame.NO_UTF8, "Received text is no valid utf8 string!"); + } + canSkipCheckUTF8PlayLoad = true; } } + + @Override + public void setPayload(ByteBuffer payload) { + super.setPayload(payload); + canSkipCheckUTF8PlayLoad = false; + } + + public boolean hasCheckUTF8PlayLoad() { + return canSkipCheckUTF8PlayLoad; + } + + public void setCanSkipCheckUTF8PlayLoad(boolean canSkipCheckUTF8PlayLoad) { + this.canSkipCheckUTF8PlayLoad = canSkipCheckUTF8PlayLoad; + } + }