public static IoBufferEx doCloseEncode(IoBufferAllocatorEx<?> allocator, int flags) { // Draft Hixie has no notion of status or reason ByteBuffer close = allocator.allocate(2, flags); int offset = close.position(); close.put(CLOSE_TYPE_BYTE); close.put(CLOSE_TERMINATOR_BYTE); close.flip(); close.position(offset); return allocator.wrap(close, flags); }
@Override protected Object doFilterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest, Object message) throws Exception { if (message instanceof IoBufferEx) { IoBufferEx buf = (IoBufferEx) message; message = allocator.wrap(buf.buf(), buf.flags()); } return message; } }
@Override public ByteBuffer allocate(int capacity, int flags) { boolean offset = (flags & IoBufferEx.FLAG_ZERO_COPY) != IoBufferEx.FLAG_NONE; if (offset) { ByteBuffer buf = parent.allocate(FRAME_OFFSET + capacity + FRAME_PADDING, flags); buf.position(buf.position() + FRAME_OFFSET); buf.limit(buf.position() + capacity); return buf; } else { // no offset return parent.allocate(capacity, flags); } }
private IoBufferEx escapeZeroAndNewLineWithHeap(IoBufferAllocatorEx<?> allocator, int flags, IoBufferEx decoded, ByteBuffer prefix) { byte[] decodedArray = decoded.array(); final int decodedArrayOffset = decoded.arrayOffset(); int decodedArrayPosition = decodedArrayOffset + decoded.position(); final int decodedArrayInitialPosition = decodedArrayPosition; final int decodedArrayLimit = decodedArrayOffset + decoded.limit(); int[] encodedArrayInsertionCount = new int[1]; byte[] encodedArray = null; encodedArray = doEscapeZeroAndNewline(decodedArray, decodedArrayInitialPosition, decodedArrayInitialPosition, decodedArrayLimit, encodedArray, encodedArrayInsertionCount, prefix); if (encodedArray != null) { return allocator.wrap(ByteBuffer.wrap(encodedArray, decodedArrayInitialPosition, prefix.remaining() + decoded.remaining() + encodedArrayInsertionCount[0])); } else { encodedArray = Arrays.copyOf(prefix.array(), prefix.remaining() + decoded.remaining()); System.arraycopy(decodedArray, decodedArrayInitialPosition, encodedArray, prefix.remaining(), decoded.remaining()); return allocator.wrap(ByteBuffer.wrap(encodedArray)); } }
@Override public ByteBuffer allocate(int capacity, int flags) { boolean offset = (flags & IoBufferEx.FLAG_ZERO_COPY) != IoBufferEx.FLAG_NONE; if (offset) { // HEX(remaining) CRLF data CRLF // 0 CRLF CRLF int frameOffset = 10 + HttpGzipEncoder.GZIP_PREFIX_SIZE; // maximum 8 hex digits for 31-bit positive integer + 2 (CRLF) + 5 bytes for potential gzip frame prefix int framePadding = 2 + 5; // CRLF, 0 CRLF CRLF ByteBuffer buf = parent.allocate(frameOffset + capacity + framePadding, flags); buf.position(buf.position() + frameOffset); buf.limit(buf.position() + capacity); assert (buf.remaining() == capacity); return buf; } else { // no offset return parent.allocate(capacity, flags); } }
private WsTextMessage createTextMessage(IoBufferAllocatorEx<?> allocator, byte[] content) { // Use FLAG_SHARED so the same message instance can be written safely multiple times ByteBuffer payload = allocator.allocate(content.length, IoBufferEx.FLAG_SHARED); int offset = payload.position(); payload.put(content); payload.flip(); payload.position(offset); WsTextMessage result = new WsTextMessage(allocator.wrap(payload, IoBufferEx.FLAG_SHARED)); return result; }
protected WriteFuture flushNow(T session, IoSessionEx parent, IoBufferEx buf, IoFilterChain filterChain, WriteRequest request) { IoBufferAllocatorEx<?> parentAllocator = parent.getBufferAllocator(); IoBufferEx parentBuf = parentAllocator.wrap(buf.buf(), buf.flags()); return flushNowInternal(parent, parentBuf, buf, filterChain, request); }
@Override public ByteBuffer allocate(int capacity, int flags) { boolean offset = (flags & IoBufferEx.FLAG_ZERO_COPY) != IoBufferEx.FLAG_NONE; if (offset) { // data: [data] 0x0a // 0x0a // Note: each newline in [data] is replaced by 6 bytes of meta data // so zero-copy requires no newlines in data int frameOffset = 5; int framePadding = 2; ByteBuffer buf = parent.allocate(frameOffset + capacity + framePadding, flags); buf.position(buf.position() + frameOffset); buf.limit(buf.position() + capacity); return buf; } else { // no offset return parent.allocate(capacity, flags); } }
@Override protected IoBufferEx doPingEncode(IoBufferAllocatorEx<?> allocator, int flags, WsMessage message) { WsPingMessage ping = (WsPingMessage)message; assert ping.getBytes().remaining() == 0 : "PING with payload not supported"; ByteBuffer text = allocator.allocate(EMPTY_PING_BYTES.length, flags); int offset = text.position(); text.put(EMPTY_PING_BYTES); text.flip(); text.position(offset); return allocator.wrap(text, flags); } @Override
@Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object message = e.getMessage(); if (message instanceof ChannelBuffer) { ChannelBuffer buf = (ChannelBuffer) message; // note: read as unshared buffer // can convert via IoBufferEx.asSharedBuffer() if necessary later message = allocator.wrap(buf.toByteBuffer()); buf.skipBytes(buf.readableBytes()); } // filter chain can change if session is re-aligned IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageReceived(message); }
@Override public ByteBuffer allocate(int capacity, int flags) { boolean offset = (flags & FLAG_ZERO_COPY) != FLAG_NONE; if (offset) { int frameOffset = this.frameOffset; if (capacity < 126) { // no additional offset needed } else if (capacity < 65535) { frameOffset += 2; } else { frameOffset += 8; } ByteBuffer buf = parent.allocate(frameOffset + capacity, flags); buf.position(buf.position() + frameOffset); buf.limit(buf.position() + capacity); return buf; } else { // no offset return parent.allocate(capacity, flags); } }
protected IoBufferEx doPongEncode(IoBufferAllocatorEx<?> allocator, int flags, WsMessage message) { WsPongMessage ping = (WsPongMessage)message; assert ping.getBytes().remaining() == 0 : "PONG with payload not supported"; ByteBuffer text = allocator.allocate(EMPTY_PONG_BYTES.length, flags); int offset = text.position(); text.put(EMPTY_PONG_BYTES); text.flip(); text.position(offset); return allocator.wrap(text, flags); }
@Override protected Object doFilterWriteWsBinary(NextFilter nextFilter, IoSession session, WriteRequest writeRequest, WsBinaryMessage wsBinary) throws Exception { IoBufferEx binaryEx = wsBinary.getBytes(); ByteBuffer binary = binaryEx.buf(); ByteBuffer encoded = base64.encode(binary); IoSessionEx sessionEx = (IoSessionEx) session; IoBufferAllocatorEx<?> allocator = sessionEx.getBufferAllocator(); IoBufferEx encodedEx = allocator.wrap(encoded, binaryEx.flags()); return new WsTextMessage(encodedEx); }
@Override public ByteBuffer allocate(int capacity, int flags) { boolean offset = (flags & IoBufferEx.FLAG_ZERO_COPY) != IoBufferEx.FLAG_NONE; if (offset) { // 3.5 clients receive TEXT messages as BINARY messages with UTF-8 payload // 4.0 clients receive TEXT messages in BINARY message syntax, but opcode 0x81 // 4.0 clients receive BINARY messages in BINARY message syntax, with opcode 0x80 // [0x80 | 0x81] [length] [binary] // Note: 7 bits per byte to represent length int shiftedCapacity = capacity; int sizeOfLength = 0; do { sizeOfLength ++; } while ((shiftedCapacity >>= 7) > 0); int frameOffset = 1 + sizeOfLength; ByteBuffer buf = parent.allocate(frameOffset + capacity, flags); buf.position(buf.position() + frameOffset); buf.limit(buf.position() + capacity); return buf; } else { // no offset return parent.allocate(capacity, flags); } }
@Override protected IoBufferEx doPongEncode(IoBufferAllocatorEx<?> allocator, int flags, WsMessage message) { WsPongMessage ping = (WsPongMessage)message; assert ping.getBytes().remaining() == 0 : "PONG with payload not supported"; ByteBuffer text = allocator.allocate(EMPTY_PONG_BYTES.length, flags); int offset = text.position(); text.put(EMPTY_PONG_BYTES); text.flip(); text.position(offset); return allocator.wrap(text, flags); }
@Override protected Object doFilterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest, Object message) throws Exception { IoBufferEx decodedEx = (IoBufferEx) message; // encoded messages cause a subsequent call to filterWrite // with original Object but empty IoBuffer as message // so detect empty IoBuffer to avoid unnecessary processing if (!decodedEx.hasRemaining()) { return null; } ByteBuffer decoded = decodedEx.buf(); ByteBuffer encoded = encoding.encode(decoded); IoSessionEx sessionEx = (IoSessionEx) session; IoBufferAllocatorEx<?> allocator = sessionEx.getBufferAllocator(); IoBufferEx encodedEx = allocator.wrap(encoded, decodedEx.flags()); return encodedEx; }
@Override public ByteBuffer allocate(int capacity, int flags) { boolean offset = (flags & IoBufferEx.FLAG_ZERO_COPY) != IoBufferEx.FLAG_NONE; if (offset) { // chunk prefix: // 1 (chunk stream id) // 3 timestamp // 3 stream message length // 1 stream message kind // 4 (message stream id) // stream message prefix: // 1 + 2 + 1 ( AMF0 string type marker + unsigned short length + utf8('d') ) // 1 (AMF0->AMF3 type marker + AMF3 ByteArray type marker // 1 (0x0 mystery byte) // 4 maximum bytes for AMF3 U29B (length with low flag) int frameOffset = 1 + 3 + 3 + 1 + 4 + 1 + 1 + 4; ByteBuffer buf = parent.allocate(frameOffset + capacity, flags); buf.position(buf.position() + frameOffset); buf.limit(buf.position() + capacity); return buf; } else { // no offset return parent.allocate(capacity, flags); } }
private void createOutNetBuffer(int expectedRemaining) { // SSLEngine requires us to allocate unnecessarily big buffer // even for small data. *Shrug* int capacity = Math.max( expectedRemaining, sslEngine.getSession().getPacketBufferSize()); if (outNetBuffer != null) { outNetBuffer.capacity(capacity, allocator); } else { outNetBuffer = allocator.wrap(allocator.allocate(capacity)).minimumCapacity(0); } }
@Override public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception { IoBufferEx encodedEx = (IoBufferEx) message; ByteBuffer encoded = encodedEx.buf(); ByteBuffer decoded = encoding.decode(encoded, new SessionDecodingState(session)); IoSessionEx sessionEx = (IoSessionEx) session; IoBufferAllocatorEx<?> allocator = sessionEx.getBufferAllocator(); IoBufferEx decodedEx = allocator.wrap(decoded, encodedEx.flags()); super.messageReceived(nextFilter, session, decodedEx); }
ByteBuffer newBuf = reallocator.allocate(newCapacity, flags()); oldBuf.clear(); newBuf.put(oldBuf);