You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2014/06/24 12:40:56 UTC
svn commit: r1605054 - in /tomcat/trunk/java/org/apache/tomcat/websocket:
PerMessageDeflate.java Transformation.java TransformationResult.java
WsFrameBase.java
Author: markt
Date: Tue Jun 24 10:40:56 2014
New Revision: 1605054
URL: http://svn.apache.org/r1605054
Log:
Refactor transformations to enable the handing of overflow (the previous code ignored this possibility).
Added:
tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java (with props)
Modified:
tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java
tomcat/trunk/java/org/apache/tomcat/websocket/Transformation.java
tomcat/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java
Modified: tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java?rev=1605054&r1=1605053&r2=1605054&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/PerMessageDeflate.java Tue Jun 24 10:40:56 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/trunk/java/org/apache/tomcat/websocket/Transformation.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/Transformation.java?rev=1605054&r1=1605053&r2=1605054&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/Transformation.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/Transformation.java Tue Jun 24 10:40:56 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
Added: tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java?rev=1605054&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java Tue Jun 24 10:40:56 2014
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.websocket;
+
+public enum TransformationResult {
+ /**
+ * The end of the available data was reached before the WebSocket frame was
+ * completely read.
+ */
+ UNDERFLOW,
+
+ /**
+ * The provided destination buffer was filled before all of the available
+ * data from the WebSocket frame could be processed.
+ */
+ OVERFLOW,
+
+ /**
+ * The end of the WebSocket frame was reached and all the data from that
+ * frame processed into the provided destination buffer.
+ */
+ END_OF_FRAME
+}
Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/TransformationResult.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java?rev=1605054&r1=1605053&r2=1605054&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsFrameBase.java Tue Jun 24 10:40:56 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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org