Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java')
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java305
1 files changed, 146 insertions, 159 deletions
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java
index f16e7dec1e..b431dbbff1 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java
@@ -23,8 +23,6 @@ import java.util.List;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.ProtocolException;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
@@ -57,7 +55,6 @@ import org.eclipse.jetty.websocket.api.extensions.Frame;
*/
public class Generator
{
- private static final Logger LOG = Log.getLogger(Generator.class);
/**
* The overhead (maximum) for a framing header. Assuming a maximum sized payload with masking key.
*/
@@ -65,7 +62,7 @@ public class Generator
private final WebSocketBehavior behavior;
private final ByteBufferPool bufferPool;
- private boolean validating;
+ private final boolean validating;
/** Is there an extension using RSV1 */
private boolean rsv1InUse = false;
@@ -132,7 +129,7 @@ public class Generator
throw new ProtocolException("RSV3 not allowed to be set");
}
- if (frame.getType().isControl())
+ if (OpCode.isControlFrame(frame.getOpCode()))
{
/*
* RFC 6455 Section 5.5
@@ -154,7 +151,7 @@ public class Generator
*
* close frame payload is specially formatted which is checked in CloseInfo
*/
- if (frame.getType().getOpCode() == OpCode.CLOSE)
+ if (frame.getOpCode() == OpCode.CLOSE)
{
ByteBuffer payload = frame.getPayload();
@@ -175,7 +172,7 @@ public class Generator
this.rsv3InUse = false;
// configure from list of extensions in use
- for(Extension ext: exts)
+ for (Extension ext : exts)
{
if (ext.isRsv1User())
{
@@ -192,186 +189,145 @@ public class Generator
}
}
- /**
- * generate a byte buffer based on the frame being passed in
- *
- * bufferSize is determined by the length of the payload + 28 for frame overhead
- *
- * @param frame
- * @return
- */
- public synchronized ByteBuffer generate(Frame frame)
- {
- int bufferSize = frame.getPayloadLength() + OVERHEAD;
- return generate(bufferSize,frame);
- }
-
- /**
- * Generate, into a ByteBuffer, no more than bufferSize of contents from the frame. If the frame exceeds the bufferSize, then multiple calls to
- * {@link #generate(int, WebSocketFrame)} are required to obtain each window of ByteBuffer to complete the frame.
- */
- public synchronized ByteBuffer generate(int windowSize, Frame frame)
+ public ByteBuffer generateHeaderBytes(Frame frame)
{
- if (windowSize < OVERHEAD)
- {
- throw new IllegalArgumentException("Cannot have windowSize less than " + OVERHEAD);
- }
+ // we need a framing header
+ assertFrameValid(frame);
- LOG.debug("{} Generate: {} (windowSize {})",behavior,frame,windowSize);
+ ByteBuffer buffer = bufferPool.acquire(OVERHEAD,true);
+ BufferUtil.clearToFill(buffer);
/*
- * prepare the byte buffer to put frame into
+ * start the generation process
*/
- ByteBuffer buffer = bufferPool.acquire(windowSize,false);
- BufferUtil.clearToFill(buffer);
- if (LOG.isDebugEnabled())
+ byte b;
+
+ // Setup fin thru opcode
+ b = 0x00;
+ if (frame.isFin())
{
- LOG.debug("Acquired Buffer (windowSize={}): {}",windowSize,BufferUtil.toDetailString(buffer));
+ b |= 0x80; // 1000_0000
}
- // since the buffer from the pool can exceed the window size, artificially
- // limit the buffer to the window size.
- int newlimit = Math.min(buffer.position() + windowSize,buffer.limit());
- buffer.limit(newlimit);
- LOG.debug("Buffer limited: {}",buffer);
-
- if (frame.remaining() == frame.getPayloadLength())
+ if (frame.isRsv1())
{
- // we need a framing header
- assertFrameValid(frame);
-
- /*
- * start the generation process
- */
- byte b;
-
- // Setup fin thru opcode
- b = 0x00;
- if (frame.isFin())
- {
- b |= 0x80; // 1000_0000
- }
- if (frame.isRsv1())
- {
- b |= 0x40; // 0100_0000
- }
- if (frame.isRsv2())
- {
- b |= 0x20; // 0010_0000
- }
- if (frame.isRsv3())
- {
- b |= 0x10;
- }
-
- // NOTE: using .getOpCode() here, not .getType().getOpCode() for testing reasons
- byte opcode = frame.getOpCode();
+ b |= 0x40; // 0100_0000
+ }
+ if (frame.isRsv2())
+ {
+ b |= 0x20; // 0010_0000
+ }
+ if (frame.isRsv3())
+ {
+ b |= 0x10; // 0001_0000
+ }
- if (frame.isContinuation())
- {
- // Continuations are not the same OPCODE
- opcode = OpCode.CONTINUATION;
- }
+ // NOTE: using .getOpCode() here, not .getType().getOpCode() for testing reasons
+ byte opcode = frame.getOpCode();
- b |= opcode & 0x0F;
+ if (frame.getOpCode() == OpCode.CONTINUATION)
+ {
+ // Continuations are not the same OPCODE
+ opcode = OpCode.CONTINUATION;
+ }
- buffer.put(b);
+ b |= opcode & 0x0F;
- // is masked
- b = 0x00;
- b |= (frame.isMasked()?0x80:0x00);
+ buffer.put(b);
- // payload lengths
- int payloadLength = frame.getPayloadLength();
+ // is masked
+ b = 0x00;
+ b |= (frame.isMasked()?0x80:0x00);
- /*
- * if length is over 65535 then its a 7 + 64 bit length
- */
- if (payloadLength > 0xFF_FF)
- {
- // we have a 64 bit length
- b |= 0x7F;
- buffer.put(b); // indicate 8 byte length
- buffer.put((byte)0); //
- buffer.put((byte)0); // anything over an
- buffer.put((byte)0); // int is just
- buffer.put((byte)0); // intsane!
- buffer.put((byte)((payloadLength >> 24) & 0xFF));
- buffer.put((byte)((payloadLength >> 16) & 0xFF));
- buffer.put((byte)((payloadLength >> 8) & 0xFF));
- buffer.put((byte)(payloadLength & 0xFF));
- }
- /*
- * if payload is ge 126 we have a 7 + 16 bit length
- */
- else if (payloadLength >= 0x7E)
- {
- b |= 0x7E;
- buffer.put(b); // indicate 2 byte length
- buffer.put((byte)(payloadLength >> 8));
- buffer.put((byte)(payloadLength & 0xFF));
- }
- /*
- * we have a 7 bit length
- */
- else
- {
- b |= (payloadLength & 0x7F);
- buffer.put(b);
- }
+ // payload lengths
+ int payloadLength = frame.getPayloadLength();
- // masking key
- if (frame.isMasked())
- {
- buffer.put(frame.getMask());
- }
+ /*
+ * if length is over 65535 then its a 7 + 64 bit length
+ */
+ if (payloadLength > 0xFF_FF)
+ {
+ // we have a 64 bit length
+ b |= 0x7F;
+ buffer.put(b); // indicate 8 byte length
+ buffer.put((byte)0); //
+ buffer.put((byte)0); // anything over an
+ buffer.put((byte)0); // int is just
+ buffer.put((byte)0); // intsane!
+ buffer.put((byte)((payloadLength >> 24) & 0xFF));
+ buffer.put((byte)((payloadLength >> 16) & 0xFF));
+ buffer.put((byte)((payloadLength >> 8) & 0xFF));
+ buffer.put((byte)(payloadLength & 0xFF));
}
-
- // copy payload
- if (frame.hasPayload())
+ /*
+ * if payload is greater 126 we have a 7 + 16 bit length
+ */
+ else if (payloadLength >= 0x7E)
{
- // remember the position
- int maskingStartPosition = buffer.position();
-
- // remember the offset within the frame payload (for working with
- // windowed frames that don't split on 4 byte barriers)
- int payloadOffset = frame.getPayload().position();
- int payloadStart = frame.getPayloadStart();
+ b |= 0x7E;
+ buffer.put(b); // indicate 2 byte length
+ buffer.put((byte)(payloadLength >> 8));
+ buffer.put((byte)(payloadLength & 0xFF));
+ }
+ /*
+ * we have a 7 bit length
+ */
+ else
+ {
+ b |= (payloadLength & 0x7F);
+ buffer.put(b);
+ }
- // put as much as possible into the buffer
- BufferUtil.put(frame.getPayload(),buffer);
+ // masking key
+ if (frame.isMasked())
+ {
+ byte[] mask = frame.getMask();
+ buffer.put(mask);
+ int maskInt = ByteBuffer.wrap(mask).getInt();
- // mask it if needed
- if (frame.isMasked())
+ // perform data masking here
+ ByteBuffer payload = frame.getPayload();
+ if ((payload != null) && (payload.remaining() > 0))
{
- // move back to remembered position.
- int size = buffer.position() - maskingStartPosition;
- byte[] mask = frame.getMask();
- byte b;
- int posBuf;
- int posFrame;
- for (int i = 0; i < size; i++)
+ int maskOffset = 0;
+ int start = payload.position();
+ int end = payload.limit();
+ int remaining;
+ while ((remaining = end - start) > 0)
{
- posBuf = i + maskingStartPosition;
- posFrame = i + (payloadOffset - payloadStart);
-
- // get raw byte from buffer.
- b = buffer.get(posBuf);
-
- // mask, using offset information from frame windowing.
- b ^= mask[posFrame % 4];
-
- // Mask each byte by its absolute position in the bytebuffer
- buffer.put(posBuf,b);
+ if (remaining >= 4)
+ {
+ payload.putInt(start, payload.getInt(start) ^ maskInt);
+ start += 4;
+ }
+ else
+ {
+ payload.put(start, (byte)(payload.get(start) ^ mask[maskOffset & 3]));
+ ++start;
+ ++maskOffset;
+ }
}
}
}
BufferUtil.flipToFlush(buffer,0);
- if (LOG.isDebugEnabled())
+ return buffer;
+ }
+
+ /**
+ * Generate the whole frame (header + payload copy) into a single ByteBuffer.
+ * <p>
+ * Note: THIS IS SLOW. Only use this if you must.
+ *
+ * @param frame
+ * the frame to generate
+ */
+ public void generateWholeFrame(Frame frame, ByteBuffer buf)
+ {
+ buf.put(generateHeaderBytes(frame));
+ if (frame.hasPayload())
{
- LOG.debug("Generated Buffer: {}",BufferUtil.toDetailString(buffer));
+ buf.put(getPayloadWindow(frame.getPayloadLength(),frame));
}
- return buffer;
}
public ByteBufferPool getBufferPool()
@@ -379,6 +335,37 @@ public class Generator
return bufferPool;
}
+ public ByteBuffer getPayloadWindow(int windowSize, Frame frame)
+ {
+ if (!frame.hasPayload())
+ {
+ return BufferUtil.EMPTY_BUFFER;
+ }
+
+ ByteBuffer buffer;
+
+ // We will create a slice representing the windowSize of this payload
+ if (frame.getPayload().remaining() <= windowSize)
+ {
+ // remaining will fit within window
+ buffer = frame.getPayload().slice();
+ // adjust the frame payload position (mark as read)
+ frame.getPayload().position(frame.getPayload().limit());
+ }
+ else
+ {
+ // remaining is over the window size limit, slice it
+ buffer = frame.getPayload().slice();
+ buffer.limit(windowSize);
+ int offset = frame.getPayload().position(); // offset within frame payload
+ // adjust the frame payload position
+ int newpos = Math.min(offset + windowSize,frame.getPayload().limit());
+ frame.getPayload().position(newpos);
+ }
+
+ return buffer;
+ }
+
public boolean isRsv1InUse()
{
return rsv1InUse;

Back to the top