From 4a1f50c7a6faf357fcec8c0b6ba53de2e7e4d0c5 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Mon, 9 Jul 2012 17:20:58 -0500 Subject: [PATCH] switch generator to use bytebuffer again and wire pool back in, update frame builder to use static internal pool for time being, remove FrameGenerator --- .../websocket/generator/FrameGenerator.java | 231 ------------------ .../jetty/websocket/generator/Generator.java | 205 ++++++++++++++-- .../websocket/protocol/FrameBuilder.java | 21 +- 3 files changed, 193 insertions(+), 264 deletions(-) delete mode 100644 jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/generator/FrameGenerator.java diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/generator/FrameGenerator.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/generator/FrameGenerator.java deleted file mode 100644 index 17d28b1c7a7..00000000000 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/generator/FrameGenerator.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.eclipse.jetty.websocket.generator; - -import java.nio.ByteBuffer; - -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.WebSocketPolicy; -import org.eclipse.jetty.websocket.protocol.CloseInfo; -import org.eclipse.jetty.websocket.protocol.OpCode; -import org.eclipse.jetty.websocket.protocol.WebSocketFrame; - -/** - *
- *    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 - */ -public class FrameGenerator -{ - private static final Logger LOG = Log.getLogger(FrameGenerator.class); - - /** - * The overhead (maximum) for a framing header. Assuming a maximum sized payload with masking key. - */ - public static final int OVERHEAD = 28; - private final WebSocketPolicy policy; - - public FrameGenerator(WebSocketPolicy policy) - { - this.policy = policy; - } - - public void assertFrameValid(WebSocketFrame frame) - { - /* - * RFC 6455 Section 5.2 - * - * MUST be 0 unless an extension is negotiated that defines meanings for non-zero values. If a nonzero value is received and none of the negotiated - * extensions defines the meaning of such a nonzero value, the receiving endpoint MUST _Fail the WebSocket Connection_. - */ - if (frame.isRsv1()) - { - // TODO: extensions can negotiate this (somehow) - throw new ProtocolException("RSV1 not allowed to be set"); - } - - if (frame.isRsv2()) - { - // TODO: extensions can negotiate this (somehow) - throw new ProtocolException("RSV2 not allowed to be set"); - } - - if (frame.isRsv3()) - { - // TODO: extensions can negotiate this (somehow) - throw new ProtocolException("RSV3 not allowed to be set"); - } - - if (frame.getOpCode().isControlFrame()) - { - /* - * RFC 6455 Section 5.5 - * - * All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented. - */ - if (frame.getPayloadLength() > 125) - { - throw new ProtocolException("Invalid control frame payload length"); - } - - if (!frame.isFin()) - { - throw new ProtocolException("Control Frames must be FIN=true"); - } - - /* - * RFC 6455 Section 5.5.1 - * - * close frame payload is specially formatted which is checked in CloseInfo - */ - if (frame.getOpCode() == OpCode.CLOSE) - { - new CloseInfo(frame.getPayloadData(),true); - } - } - - } - - public ByteBuffer generate(ByteBuffer buffer, WebSocketFrame frame) - { - LOG.debug(String.format("Generate.Frame[opcode=%s,fin=%b,cont=%b,rsv1=%b,rsv2=%b,rsv3=%b,mask=%b,plength=%d]",frame.getOpCode().toString(), - frame.isFin(),frame.isContinuation(),frame.isRsv1(),frame.isRsv2(),frame.isRsv3(),frame.isMasked(),frame.getPayloadLength())); - - assertFrameValid(frame); - - 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; - } - - byte opcode = frame.getOpCode().getCode(); - - if (frame.isContinuation()) - { - // Continuations are not the same OPCODE - opcode = OpCode.CONTINUATION.getCode(); - } - - b |= opcode & 0x0F; - - buffer.put(b); - - // is masked - b = 0x00; - b |= (frame.isMasked()?0x80:0x00); - - // payload lengths - int payloadLength = frame.getPayloadLength(); - - - /* - * 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); - } - - // masking key - if (frame.isMasked()) - { - buffer.put(frame.getMask()); - } - - // remember the position - int positionPrePayload = buffer.position(); - - // copy payload - if (frame.hasPayload()) - { - buffer.put(frame.getPayloadData()); - } - - int positionPostPayload = buffer.position(); - - // mask it if needed - if ( frame.isMasked() ) - { - // move back to remembered position. - int size = positionPostPayload - positionPrePayload; - byte[] mask = frame.getMask(); - int pos; - for (int i=0;i 125) + { + throw new ProtocolException("Invalid control frame payload length"); + } + + if (!frame.isFin()) + { + throw new ProtocolException("Control Frames must be FIN=true"); + } + + /* + * RFC 6455 Section 5.5.1 + * + * close frame payload is specially formatted which is checked in CloseInfo + */ + if (frame.getOpCode() == OpCode.CLOSE) + { + new CloseInfo(frame.getPayloadData(),true); + } + } + } - public ByteBuffer generate(int size, WebSocketFrame frame) - { - // NEW ONE - allocate and fill only to param size - // note: size is the buffer size to generate into, not related to the payload size - // note: size cannot be less than framing overhead - // TODO: update frame.setAvailable() to indicate how much of payload is left to be generated - return basicGenerator.generate(frame); - } public ByteBuffer generate(WebSocketFrame frame) { - // NEW ONE - allocate as much as needed - return basicGenerator.generate(frame); + LOG.debug(String.format("Generate.Frame[opcode=%s,fin=%b,cont=%b,rsv1=%b,rsv2=%b,rsv3=%b,mask=%b,plength=%d]",frame.getOpCode().toString(), + frame.isFin(),frame.isContinuation(),frame.isRsv1(),frame.isRsv2(),frame.isRsv3(),frame.isMasked(),frame.getPayloadLength())); + + assertFrameValid(frame); + + /* + * prepare the byte buffer to put frame into + */ + ByteBuffer buffer = bufferPool.acquire(frame.getPayloadLength() + OVERHEAD,true); + BufferUtil.clearToFill(buffer); + + /* + * 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; + } + + byte opcode = frame.getOpCode().getCode(); + + if (frame.isContinuation()) + { + // Continuations are not the same OPCODE + opcode = OpCode.CONTINUATION.getCode(); + } + + b |= opcode & 0x0F; + + buffer.put(b); + + // is masked + b = 0x00; + b |= (frame.isMasked()?0x80:0x00); + + // payload lengths + int payloadLength = frame.getPayloadLength(); + + + /* + * 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); + } + + // masking key + if (frame.isMasked()) + { + buffer.put(frame.getMask()); + } + + // remember the position + int positionPrePayload = buffer.position(); + + // copy payload + if (frame.hasPayload()) + { + buffer.put(frame.getPayloadData()); + } + + int positionPostPayload = buffer.position(); + + // mask it if needed + if ( frame.isMasked() ) + { + // move back to remembered position. + int size = positionPostPayload - positionPrePayload; + byte[] mask = frame.getMask(); + int pos; + for (int i=0;i