@Override public TransformationResult getMoreData(byte opCode, boolean fin, int rsv, ByteBuffer dest) throws IOException { // Control frames are never compressed and may appear in the middle of // a WebSocket method. Pass them straight through. if (Util.isControl(opCode)) { return next.getMoreData(opCode, fin, rsv, dest); } if (!Util.isContinuation(opCode)) { // First frame in new message skipDecompression = (rsv & RSV_BITMASK) == 0; } // Pass uncompressed frames straight through. if (skipDecompression) { return next.getMoreData(opCode, fin, rsv, dest); } int written; boolean usedEomBytes = false; while (dest.remaining() > 0) { // Space available in destination. Try and fill it. try { written = inflater.inflate(dest.array(), dest.arrayOffset() + dest.position(), dest.remaining()); } catch (DataFormatException e) { throw new IOException(sm.getString("perMessageDeflate.deflateFailed"), e); } dest.position(dest.position() + written); if (inflater.needsInput() && !usedEomBytes) { if (dest.hasRemaining()) { readBuffer.clear(); TransformationResult nextResult = next.getMoreData(opCode, fin, (rsv ^ RSV_BITMASK), readBuffer); inflater.setInput(readBuffer.array(), readBuffer.arrayOffset(), readBuffer.position()); if (TransformationResult.UNDERFLOW.equals(nextResult)) { return nextResult; } else if (TransformationResult.END_OF_FRAME.equals(nextResult) && readBuffer.position() == 0) { if (fin) { inflater.setInput(EOM_BYTES); usedEomBytes = true; } else { return TransformationResult.END_OF_FRAME; } } } } else if (written == 0) { if (fin && (isServer && !clientContextTakeover || !isServer && !serverContextTakeover)) { inflater.reset(); } return TransformationResult.END_OF_FRAME; } } return TransformationResult.OVERFLOW; }
private boolean processDataBinary() throws IOException { // Copy the available data to the buffer TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); while (!TransformationResult.END_OF_FRAME.equals(tr)) { // Frame not complete - what did we run out of? if (TransformationResult.UNDERFLOW.equals(tr)) { // Ran out of input data - get some more return false; } // Ran out of message buffer - flush it if (!usePartial()) { CloseReason cr = new CloseReason( CloseCodes.TOO_BIG, sm.getString( "wsFrame.bufferTooSmall", Integer.valueOf(messageBufferBinary.capacity()), Long.valueOf(payloadLength))); throw new WsIOException(cr); } messageBufferBinary.flip(); ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit()); copy.put(messageBufferBinary); copy.flip(); sendMessageBinary(copy, false); messageBufferBinary.clear(); // Read more data tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); } // Frame is fully received // Send the message if either: // - partial messages are supported // - the message is complete if (usePartial() || !continuationExpected) { messageBufferBinary.flip(); ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit()); copy.put(messageBufferBinary); copy.flip(); sendMessageBinary(copy, !continuationExpected); messageBufferBinary.clear(); } if (continuationExpected) { // More data for this message expected, start a new frame newFrame(); } else { // Message is complete, start a new message newMessage(); } return true; }
private boolean processDataText() throws IOException { // Copy the available data to the buffer TransformationResult tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); while (!TransformationResult.END_OF_FRAME.equals(tr)) { // Frame not complete - we ran out of something // Convert bytes to UTF-8 messageBufferBinary.flip(); while (true) { CoderResult cr = utf8DecoderMessage.decode(messageBufferBinary, messageBufferText, false); if (cr.isError()) { throw new WsIOException( new CloseReason(CloseCodes.NOT_CONSISTENT, sm.getString("wsFrame.invalidUtf8"))); } else if (cr.isOverflow()) { // Ran out of space in text buffer - flush it if (usePartial()) { messageBufferText.flip(); sendMessageText(false); messageBufferText.clear(); } else { throw new WsIOException( new CloseReason(CloseCodes.TOO_BIG, sm.getString("wsFrame.textMessageTooBig"))); } } else if (cr.isUnderflow()) { // Compact what we have to create as much space as possible messageBufferBinary.compact(); // Need more input // What did we run out of? if (TransformationResult.OVERFLOW.equals(tr)) { // Ran out of message buffer - exit inner loop and // refill break; } else { // TransformationResult.UNDERFLOW // Ran out of input data - get some more return false; } } } // Read more input data tr = transformation.getMoreData(opCode, fin, rsv, messageBufferBinary); } messageBufferBinary.flip(); boolean last = false; // Frame is fully received // Convert bytes to UTF-8 while (true) { CoderResult cr = utf8DecoderMessage.decode(messageBufferBinary, messageBufferText, last); if (cr.isError()) { throw new WsIOException( new CloseReason(CloseCodes.NOT_CONSISTENT, sm.getString("wsFrame.invalidUtf8"))); } else if (cr.isOverflow()) { // Ran out of space in text buffer - flush it if (usePartial()) { messageBufferText.flip(); sendMessageText(false); messageBufferText.clear(); } else { throw new WsIOException( new CloseReason(CloseCodes.TOO_BIG, sm.getString("wsFrame.textMessageTooBig"))); } } else if (cr.isUnderflow() & !last) { // End of frame and possible message as well. if (continuationExpected) { // If partial messages are supported, send what we have // managed to decode if (usePartial()) { messageBufferText.flip(); sendMessageText(false); messageBufferText.clear(); } messageBufferBinary.compact(); newFrame(); // Process next frame return true; } else { // Make sure coder has flushed all output last = true; } } else { // End of message messageBufferText.flip(); sendMessageText(true); newMessage(); return true; } } }