Author: violetagg Date: Tue Sep 16 20:15:51 2014 New Revision: 1625372 URL: http://svn.apache.org/r1625372 Log: Merged revision 1605054 from tomcat/trunk: Refactor transformations to enable the handing of overflow (the previous code ignored this possibility).
Added: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/TransformationResult.java - copied unchanged from r1605054, tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Transformation.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1605054 Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java?rev=1625372&r1=1625371&r2=1625372&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java Tue Sep 16 20:15:51 2014 @@ -89,41 +89,51 @@ public class PerMessageDeflate implement } @Override - public boolean getMoreData(byte opCode, int rsv, ByteBuffer dest) throws IOException { + public TransformationResult getMoreData(byte opCode, int rsv, ByteBuffer dest) throws IOException { - // Control frames are never compressed + // Control frames are never compressed. Pass control frames and + // uncompressed frames straight through. if (Util.isControl(opCode) || (rsv & RSV_BITMASK) == 0) { return next.getMoreData(opCode, rsv, dest); } - boolean endOfInputFrame = false; + int written; + boolean usedEomBytes = false; - if (inflator.needsInput()) { - readBuffer.clear(); - endOfInputFrame = next.getMoreData(opCode, (rsv ^ RSV_BITMASK), readBuffer); - inflator.setInput(readBuffer.array(), readBuffer.arrayOffset(), readBuffer.position()); - } - - int written = 0; - try { - written = inflator.inflate(dest.array(), dest.arrayOffset() + dest.position(), dest.remaining()); - if (endOfInputFrame && !inflator.finished()) { - inflator.setInput(EOM_BYTES); - inflator.inflate(dest.array(), dest.arrayOffset() + dest.position(), dest.remaining()); + while (dest.remaining() > 0) { + // Space available in destination. Try and fill it. + try { + written = inflator.inflate( + dest.array(), dest.arrayOffset() + dest.position(), dest.remaining()); + } catch (DataFormatException e) { + throw new IOException(sm.getString("perMessageDeflate.deflateFailed"), e); } - } catch (DataFormatException e) { - throw new IOException(sm.getString("perMessageDeflate.deflateFailed"), e); - } - dest.position(dest.position() + written); - + dest.position(dest.position() + written); - if (endOfInputFrame && !clientContextTakeover) { - inflator.reset(); + if (inflator.needsInput() && !usedEomBytes ) { + if (dest.hasRemaining()) { + readBuffer.clear(); + TransformationResult nextResult = + next.getMoreData(opCode, (rsv ^ RSV_BITMASK), readBuffer); + inflator.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) { + inflator.setInput(EOM_BYTES); + usedEomBytes = true; + } + } + } else if (written == 0) { + return TransformationResult.END_OF_FRAME; + } } - return endOfInputFrame; + return TransformationResult.OVERFLOW; } + @Override public boolean validateRsv(int rsv, byte opCode) { if (Util.isControl(opCode)) { Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Transformation.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Transformation.java?rev=1625372&r1=1625371&r2=1625372&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Transformation.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Transformation.java Tue Sep 16 20:15:51 2014 @@ -36,11 +36,8 @@ public interface Transformation { * @param rsv The reserved bits for the frame currently being * processed * @param dest The buffer in which the data is to be written - * - * @return <code>true</code> if the data source has been fully read - * otherwise <code>false</code> */ - boolean getMoreData(byte opCode, int rsv, ByteBuffer dest) throws IOException; + TransformationResult getMoreData(byte opCode, int rsv, ByteBuffer dest) throws IOException; /** * Validates the RSV and opcode combination (assumed to have been extracted Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java?rev=1625372&r1=1625371&r2=1625372&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java Tue Sep 16 20:15:51 2014 @@ -300,9 +300,13 @@ public abstract class WsFrameBase { private boolean processDataControl() throws IOException { - if (!transformation.getMoreData(opCode, rsv, controlBufferBinary)) { + TransformationResult tr = transformation.getMoreData(opCode, rsv, messageBufferBinary); + if (TransformationResult.UNDERFLOW.equals(tr)) { return false; } + // Control messages have fixed message size so + // TransformationResult.OVERFLOW is not possible here + controlBufferBinary.flip(); if (opCode == Constants.OPCODE_CLOSE) { open = false; @@ -398,7 +402,8 @@ public abstract class WsFrameBase { private boolean processDataText() throws IOException { // Copy the available data to the buffer - while (!transformation.getMoreData(opCode, rsv, messageBufferBinary)) { + TransformationResult tr = transformation.getMoreData(opCode, rsv, messageBufferBinary); + while (!TransformationResult.END_OF_FRAME.equals(tr)) { // Frame not complete - we ran out of something // Convert bytes to UTF-8 messageBufferBinary.flip(); @@ -421,21 +426,24 @@ public abstract class WsFrameBase { sm.getString("wsFrame.textMessageTooBig"))); } } else if (cr.isUnderflow()) { - // Need more input // Compact what we have to create as much space as possible messageBufferBinary.compact(); + // Need more input // What did we run out of? - if (readPos == writePos) { - // Ran out of input data - get some more - return false; - } else { + 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, rsv, messageBufferBinary); } messageBufferBinary.flip(); @@ -493,29 +501,32 @@ public abstract class WsFrameBase { private boolean processDataBinary() throws IOException { // Copy the available data to the buffer - while (!transformation.getMoreData(opCode, rsv, messageBufferBinary)) { + TransformationResult tr = transformation.getMoreData(opCode, rsv, messageBufferBinary); + while (!TransformationResult.END_OF_FRAME.equals(tr)) { // Frame not complete - what did we run out of? - if (readPos == writePos) { + if (TransformationResult.UNDERFLOW.equals(tr)) { // Ran out of input data - get some more return false; - } else { - // 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(); } + + // 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, rsv, messageBufferBinary); } // Frame is fully received @@ -724,7 +735,7 @@ public abstract class WsFrameBase { private final class NoopTransformation extends TerminalTransformation { @Override - public boolean getMoreData(byte opCode, int rsv, ByteBuffer dest) { + public TransformationResult getMoreData(byte opCode, int rsv, ByteBuffer dest) { // opCode is ignored as the transformation is the same for all // opCodes // rsv is ignored as it known to be zero at this point @@ -735,7 +746,15 @@ public abstract class WsFrameBase { dest.put(inputBuffer, readPos, (int) toWrite); readPos += toWrite; payloadWritten += toWrite; - return (payloadWritten == payloadLength); + + if (payloadWritten == payloadLength) { + return TransformationResult.END_OF_FRAME; + } else if (readPos == writePos) { + return TransformationResult.UNDERFLOW; + } else { + // !dest.hasRemaining() + return TransformationResult.OVERFLOW; + } } } @@ -747,7 +766,7 @@ public abstract class WsFrameBase { private final class UnmaskTransformation extends TerminalTransformation { @Override - public boolean getMoreData(byte opCode, int rsv, ByteBuffer dest) { + public TransformationResult getMoreData(byte opCode, int rsv, ByteBuffer dest) { // opCode is ignored as the transformation is the same for all // opCodes // rsv is ignored as it known to be zero at this point @@ -762,7 +781,14 @@ public abstract class WsFrameBase { payloadWritten++; dest.put(b); } - return (payloadWritten == payloadLength); + if (payloadWritten == payloadLength) { + return TransformationResult.END_OF_FRAME; + } else if (readPos == writePos) { + return TransformationResult.UNDERFLOW; + } else { + // !dest.hasRemaining() + return TransformationResult.OVERFLOW; + } } } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org