Hello community, here is the log from the commit of package qpid-proton for openSUSE:Factory checked in at 2016-05-04 08:20:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qpid-proton (Old) and /work/SRC/openSUSE:Factory/.qpid-proton.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "qpid-proton" Changes: -------- --- /work/SRC/openSUSE:Factory/qpid-proton/qpid-proton.changes 2016-04-14 13:07:21.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.qpid-proton.new/qpid-proton.changes 2016-05-04 08:20:22.000000000 +0200 @@ -1,0 +2,8 @@ +Tue May 3 10:26:01 UTC 2016 - fstrba@suse.com + +- Upgrade to version 0.12.2 + * Bugs fixed + - PROTON-1171 - [proton-j] transport SSL wrapper does not flush + all decoded bytes to the underlying input + +------------------------------------------------------------------- Old: ---- qpid-proton-0.12.1.tar.gz New: ---- qpid-proton-0.12.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qpid-proton.spec ++++++ --- /var/tmp/diff_new_pack.d6O30X/_old 2016-05-04 08:20:23.000000000 +0200 +++ /var/tmp/diff_new_pack.d6O30X/_new 2016-05-04 08:20:23.000000000 +0200 @@ -18,7 +18,7 @@ %global qpid_proton_soversion 6 Name: qpid-proton -Version: 0.12.1 +Version: 0.12.2 Release: 0 Summary: A high performance, lightweight messaging library License: Apache-2.0 ++++++ qpid-proton-0.12.1.tar.gz -> qpid-proton-0.12.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/contrib/proton-hawtdispatch/pom.xml new/qpid-proton-0.12.2/contrib/proton-hawtdispatch/pom.xml --- old/qpid-proton-0.12.1/contrib/proton-hawtdispatch/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/contrib/proton-hawtdispatch/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -19,7 +19,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> <relativePath>../..</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/contrib/proton-jms/pom.xml new/qpid-proton-0.12.2/contrib/proton-jms/pom.xml --- old/qpid-proton-0.12.1/contrib/proton-jms/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/contrib/proton-jms/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -19,7 +19,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> <relativePath>../..</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/examples/engine/java/pom.xml new/qpid-proton-0.12.2/examples/engine/java/pom.xml --- old/qpid-proton-0.12.1/examples/engine/java/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/examples/engine/java/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -19,7 +19,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> <relativePath>../../../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/examples/java/messenger/pom.xml new/qpid-proton-0.12.2/examples/java/messenger/pom.xml --- old/qpid-proton-0.12.1/examples/java/messenger/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/examples/java/messenger/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -19,7 +19,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> <relativePath>../../..</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/examples/java/reactor/pom.xml new/qpid-proton-0.12.2/examples/java/reactor/pom.xml --- old/qpid-proton-0.12.1/examples/java/reactor/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/examples/java/reactor/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -19,7 +19,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> <relativePath>../../..</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/pom.xml new/qpid-proton-0.12.2/pom.xml --- old/qpid-proton-0.12.1/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -26,7 +26,7 @@ <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> <packaging>pom</packaging> <properties> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-c/bindings/python/setuputils/bundle.py new/qpid-proton-0.12.2/proton-c/bindings/python/setuputils/bundle.py --- old/qpid-proton-0.12.1/proton-c/bindings/python/setuputils/bundle.py 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-c/bindings/python/setuputils/bundle.py 2016-04-14 17:50:53.000000000 +0200 @@ -35,7 +35,7 @@ min_qpid_proton = (0, 12, 0) min_qpid_proton_str = "%i.%i.%i" % min_qpid_proton -bundled_version = (0, 12, 1) +bundled_version = (0, 12, 2) bundled_version_str = "%i.%i.%i" % bundled_version libqpid_proton = "qpid-proton-%s.tar.gz" % bundled_version_str libqpid_proton_url = ("http://www.apache.org/dist/qpid/proton/%s/%s" % diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-j/pom.xml new/qpid-proton-0.12.2/proton-j/pom.xml --- old/qpid-proton-0.12.1/proton-j/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-j/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -19,7 +19,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> </parent> <modelVersion>4.0.0</modelVersion> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java new/qpid-proton-0.12.2/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java --- old/qpid-proton-0.12.1/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java 2016-04-14 17:50:53.000000000 +0200 @@ -115,27 +115,35 @@ HandshakeStatus hstatus = result.getHandshakeStatus(); int capacity = _underlyingInput.capacity(); - if (capacity == Transport.END_OF_STREAM) { + if (capacity == Transport.END_OF_STREAM || capacity <= 0) { _tail_closed = true; if (_decodedInputBuffer.position() > 0) { throw new TransportException("bytes left unconsumed"); } } else { - ByteBuffer tail = _underlyingInput.tail(); _decodedInputBuffer.flip(); - int limit = _decodedInputBuffer.limit(); - int overflow = _decodedInputBuffer.remaining() - capacity; - if (overflow > 0) { - _decodedInputBuffer.limit(limit - overflow); + + while (_decodedInputBuffer.hasRemaining() && capacity > 0) { + ByteBuffer tail = _underlyingInput.tail(); + int limit = _decodedInputBuffer.limit(); + int overflow = _decodedInputBuffer.remaining() - capacity; + if (overflow > 0) { + _decodedInputBuffer.limit(limit - overflow); + } + tail.put(_decodedInputBuffer); + _decodedInputBuffer.limit(limit); + _underlyingInput.process(); + capacity = _underlyingInput.capacity(); } - tail.put(_decodedInputBuffer); - _decodedInputBuffer.limit(limit); - _decodedInputBuffer.compact(); - _underlyingInput.process(); - capacity = _underlyingInput.capacity(); - if (capacity == Transport.END_OF_STREAM) { + + if (capacity == Transport.END_OF_STREAM || capacity <= 0) { _tail_closed = true; + if (_decodedInputBuffer.hasRemaining()) { + throw new TransportException("bytes left unconsumed"); + } } + + _decodedInputBuffer.compact(); } switch (status) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportTestHelper.java new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportTestHelper.java --- old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportTestHelper.java 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/TransportTestHelper.java 2016-04-14 17:50:53.000000000 +0200 @@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; public class TransportTestHelper { @@ -47,7 +48,7 @@ { byte[] buf = new byte[sizeRequested]; int numberRead = ByteBufferUtils.pourBufferToArray(source, buf, 0, sizeRequested); - return new String(buf, 0, numberRead); + return new String(buf, 0, numberRead, StandardCharsets.UTF_8); } public static String stringOfLength(String value, int repeat) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java --- old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java 2016-04-14 17:50:53.000000000 +0200 @@ -41,7 +41,7 @@ public class CapitalisingDummySslEngine implements ProtonSslEngine { static final int SHORT_ENCODED_CHUNK_SIZE = 2; - private static final int MAX_ENCODED_CHUNK_SIZE = 5; + static final int MAX_ENCODED_CHUNK_SIZE = 5; private static final char ENCODED_TEXT_BEGIN = '<'; private static final char ENCODED_TEXT_END = '>'; private static final char ENCODED_TEXT_INNER_CHAR = '-'; @@ -49,6 +49,9 @@ private static final int CLEAR_CHUNK_SIZE = 2; private static final char CLEARTEXT_PADDING = '_'; private SSLException _nextException; + private int _applicationBufferSize = CLEAR_CHUNK_SIZE; + private int _packetBufferSize = MAX_ENCODED_CHUNK_SIZE; + private int _unwrapCount; /** * Converts a_ to <-A->. z_ is special and encodes as <> (to give us packets of different lengths). @@ -116,6 +119,8 @@ public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { + _unwrapCount++; + if(_nextException != null) { throw _nextException; @@ -185,13 +190,23 @@ private int getApplicationBufferSize() { - return CLEAR_CHUNK_SIZE; + return _applicationBufferSize; } @Override public int getPacketBufferSize() { - return MAX_ENCODED_CHUNK_SIZE; + return _packetBufferSize; + } + + public void setApplicationBufferSize(int value) + { + _applicationBufferSize = value; + } + + public void setPacketBufferSize(int value) + { + _packetBufferSize = value; } @Override @@ -244,4 +259,8 @@ { _nextException = nextException; } + + int getUnwrapCount() { + return _unwrapCount; + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/RememberingTransportInput.java new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/RememberingTransportInput.java --- old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/RememberingTransportInput.java 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/RememberingTransportInput.java 2016-04-14 17:50:53.000000000 +0200 @@ -30,7 +30,10 @@ private StringBuilder _receivedInput = new StringBuilder(); private String _nextError; private int _inputBufferSize = 1024; - private ByteBuffer _buffer = ByteBuffer.allocate(_inputBufferSize); + private ByteBuffer _buffer; + private int _processCount = 0; + private Integer _zeroCapacityAtCount = null; + private int _capacityCount = 0; String getAcceptedInput() { @@ -46,24 +49,37 @@ @Override public int capacity() { + initIntermediateBuffer(); + + _capacityCount++; + if(_zeroCapacityAtCount != null && _capacityCount >= _zeroCapacityAtCount) { + return 0; + } + return _buffer.remaining(); } @Override public int position() { + initIntermediateBuffer(); return _buffer.position(); } @Override public ByteBuffer tail() { + initIntermediateBuffer(); return _buffer; } @Override public void process() throws TransportException { + _processCount++; + + initIntermediateBuffer(); + if(_nextError != null) { throw new TransportException(_nextError); @@ -87,8 +103,51 @@ _nextError = nextError; } - public void setInputBufferSize(int inputBufferSize) + /** + * If called before the object is otherwise used, the intermediate input buffer will be + * initiated to the given size. If called after use, an ISE will be thrown. + * + * @param inputBufferSize size of the intermediate input buffer + * @throws IllegalStateException if the buffer was already initialised + */ + public void setInputBufferSize(int inputBufferSize) throws IllegalStateException { + if (_buffer != null) + { + throw new IllegalStateException("Intermediate input buffer already initialised"); + } + _inputBufferSize = inputBufferSize; } + + private void initIntermediateBuffer() + { + if (_buffer == null) + { + _buffer = ByteBuffer.allocate(_inputBufferSize); + } + } + + int getProcessCount() + { + return _processCount; + } + + int getCapacityCount() + { + return _capacityCount; + } + + /** + * Sets a point at which calls to capacity will return 0 regardless of the actual buffer state. + * + * @param zeroCapacityAtCount number of calls to capacity at which zero starts being returned. + */ + void setZeroCapacityAtCount(Integer zeroCapacityAtCount) + { + if(zeroCapacityAtCount != null && zeroCapacityAtCount < 1) { + throw new IllegalArgumentException("Value must be null, or at least 1"); + } + _zeroCapacityAtCount = zeroCapacityAtCount; + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java --- old/qpid-proton-0.12.1/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java 2016-04-14 17:50:53.000000000 +0200 @@ -29,6 +29,7 @@ import static org.junit.Assert.fail; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import javax.net.ssl.SSLException; @@ -46,12 +47,10 @@ */ public class SimpleSslTransportWrapperTest { - private RememberingTransportInput _underlyingInput = new RememberingTransportInput(); - private CannedTransportOutput _underlyingOutput = new CannedTransportOutput(); - + private RememberingTransportInput _underlyingInput; + private CannedTransportOutput _underlyingOutput; private SimpleSslTransportWrapper _sslWrapper; - - private CapitalisingDummySslEngine _dummySslEngine = new CapitalisingDummySslEngine(); + private CapitalisingDummySslEngine _dummySslEngine; @Rule public ExpectedException _expectedException = ExpectedException.none(); @@ -59,6 +58,9 @@ @Before public void setUp() { + _underlyingInput = new RememberingTransportInput(); + _underlyingOutput = new CannedTransportOutput(); + _dummySslEngine = new CapitalisingDummySslEngine(); _sslWrapper = new SimpleSslTransportWrapper(_dummySslEngine, _underlyingInput, _underlyingOutput); } @@ -70,8 +72,16 @@ putBytesIntoTransport(encodedBytes); assertEquals("a_", _underlyingInput.getAcceptedInput()); + assertEquals(CapitalisingDummySslEngine.MAX_ENCODED_CHUNK_SIZE, _sslWrapper.capacity()); + assertEquals(2, _dummySslEngine.getUnwrapCount());// 1 packet, 1 underflow + assertEquals(1, _underlyingInput.getProcessCount()); } + /** + * Note that this only feeds 1 encoded packet in at a time due to default settings of the dummy engine, + * See {@link #testUnderlyingInputUsingSmallBuffer_receivesAllDecodedInputRequiringMultipleUnwraps} + * for a related test that passes multiple encoded packets into the ssl wrapper at once. + */ @Test public void testInputWithMultiplePackets() { @@ -80,6 +90,9 @@ putBytesIntoTransport(encodedBytes); assertEquals("a_b_c_z_", _underlyingInput.getAcceptedInput()); + assertEquals(CapitalisingDummySslEngine.MAX_ENCODED_CHUNK_SIZE, _sslWrapper.capacity()); + assertEquals(8, _dummySslEngine.getUnwrapCount()); // (1 decode + 1 underflow) * 4 packets + assertEquals(4, _underlyingInput.getProcessCount()); // 1 process per decoded packet } @Test @@ -90,9 +103,15 @@ putBytesIntoTransport(incompleteEncodedBytes); assertEquals("a_b_", _underlyingInput.getAcceptedInput()); + assertEquals(5, _dummySslEngine.getUnwrapCount()); // 2 * (1 decode + 1 underflow) + 1 underflow + assertEquals(2, _underlyingInput.getProcessCount()); // 1 process per decoded packet putBytesIntoTransport(remainingEncodedBytes); assertEquals("a_b_c_d_", _underlyingInput.getAcceptedInput()); + assertEquals(4, _underlyingInput.getProcessCount()); // earlier + 2 + assertEquals(9, _dummySslEngine.getUnwrapCount()); // Earlier + 2 * (1 decode + 1 underflow) + // due to way the bytes are fed in across + // boundary of encoded packets } /** @@ -108,22 +127,221 @@ putBytesIntoTransport(firstEncodedBytes); assertEquals("a_b_", _underlyingInput.getAcceptedInput()); + assertEquals(5, _dummySslEngine.getUnwrapCount()); // 2 * (1 decode + 1 underflow) + 1 underflow + assertEquals(2, _underlyingInput.getProcessCount()); // 1 process per decoded packet putBytesIntoTransport(secondEncodedBytes); assertEquals("a_b_", _underlyingInput.getAcceptedInput()); + assertEquals(6, _dummySslEngine.getUnwrapCount()); // earlier + 1 underflow + assertEquals(2, _underlyingInput.getProcessCount()); // as earlier putBytesIntoTransport(thirdEncodedBytes); assertEquals("a_b_c_d_", _underlyingInput.getAcceptedInput()); + assertEquals(4, _underlyingInput.getProcessCount()); // 1 process per decoded packet + assertEquals(10, _dummySslEngine.getUnwrapCount()); // Earlier + (decode + underflow) * 2 + // due to way the bytes are fed in across + // boundary of encoded packets } + /** + * Tests that when a small underlying input buffer (1 byte here) is used, all of the encoded + * data packet (5 bytes each here) can be processed despite multiple attempts being required to + * pass the decoded bytes (2 bytes here) to the underlying input layer for processing. + */ @Test - public void testUnderlyingInputUsingSmallBuffer_receivesAllDecodedInput() throws Exception + public void testUnderlyingInputUsingSmallBuffer_receivesAllDecodedInputRequiringMultipleUnderlyingProcesses() { - _underlyingInput.setInputBufferSize(1); + int underlyingInputBufferSize = 1; + int encodedPacketSize = 5; - putBytesIntoTransport("<-A->"); + _underlyingInput.setInputBufferSize(underlyingInputBufferSize); + assertEquals("Unexpected underlying input capacity", underlyingInputBufferSize, _underlyingInput.capacity()); - assertEquals("a_", _underlyingInput.getAcceptedInput()); + assertEquals("Unexpected max encoded chunk size", encodedPacketSize, CapitalisingDummySslEngine.MAX_ENCODED_CHUNK_SIZE); + + byte[] bytes = "<-A-><-B->".getBytes(StandardCharsets.UTF_8); + ByteBuffer encodedByteSource = ByteBuffer.wrap(bytes); + + assertEquals("Unexpected initial capacity", encodedPacketSize, _sslWrapper.capacity()); + + // Process the first 'encoded packet' (<-A->) + int numberPoured = pour(encodedByteSource, _sslWrapper.tail()); + assertEquals("Unexpected number of bytes poured into the wrapper input buffer", encodedPacketSize, numberPoured); + assertEquals("Unexpected position in encoded source byte buffer", encodedPacketSize * 1, encodedByteSource.position()); + assertEquals("Unexpected capacity", 0, _sslWrapper.capacity()); + _sslWrapper.process(); + assertEquals("Unexpected capacity", encodedPacketSize, _sslWrapper.capacity()); + + assertEquals("unexpected underlying output after first wrapper process", "a_", _underlyingInput.getAcceptedInput()); + assertEquals("unexpected underlying process count after first wrapper process", 2 , _underlyingInput.getProcessCount()); + + // Process the second 'encoded packet' (<-B->) + numberPoured = pour(encodedByteSource, _sslWrapper.tail()); + assertEquals("Unexpected number of bytes poured into the wrapper input buffer", encodedPacketSize, numberPoured); + assertEquals("Unexpected position in encoded source byte buffer", encodedPacketSize * 2, encodedByteSource.position()); + assertEquals("Unexpected capacity", 0, _sslWrapper.capacity()); + _sslWrapper.process(); + assertEquals("Unexpected capacity", encodedPacketSize, _sslWrapper.capacity()); + + assertEquals("unexpected underlying output after second wrapper process", "a_b_", _underlyingInput.getAcceptedInput()); + assertEquals("unexpected underlying process count after second wrapper process", 4 , _underlyingInput.getProcessCount()); + } + + /** + * Tests that when a small underlying input buffer (1 byte here) is used, all of the encoded + * data packets (20 bytes total here) can be processed despite multiple unwraps being required + * to process a given set of input (3 packets, 15 bytes here) and then as a result also multiple + * attempts to pass the decoded packet (2 bytes here) to the underlying input layer for processing. + */ + @Test + public void testUnderlyingInputUsingSmallBuffer_receivesAllDecodedInputRequiringMultipleUnwraps() + { + int underlyingInputBufferSize = 1; + int encodedPacketSize = 5; + int sslEngineBufferSize = 15; + + assertEquals("Unexpected max encoded chunk size", encodedPacketSize, CapitalisingDummySslEngine.MAX_ENCODED_CHUNK_SIZE); + + _underlyingOutput = new CannedTransportOutput(); + _underlyingInput = new RememberingTransportInput(); + _underlyingInput.setInputBufferSize(underlyingInputBufferSize); + assertEquals("Unexpected underlying input capacity", underlyingInputBufferSize, _underlyingInput.capacity()); + + // Create a dummy ssl engine that has buffers that holds multiple encoded/decoded + // packets, but still can't fit all of the input + _dummySslEngine = new CapitalisingDummySslEngine(); + _dummySslEngine.setApplicationBufferSize(sslEngineBufferSize); + _dummySslEngine.setPacketBufferSize(sslEngineBufferSize); + + _sslWrapper = new SimpleSslTransportWrapper(_dummySslEngine, _underlyingInput, _underlyingOutput); + + byte[] bytes = "<-A-><-B-><-C-><-D->".getBytes(StandardCharsets.UTF_8); + ByteBuffer encodedByteSource = ByteBuffer.wrap(bytes); + + assertEquals("Unexpected initial capacity", sslEngineBufferSize, _sslWrapper.capacity()); + + // Process the first three 'encoded packets' (<-A-><-B-><-C->). This will require 3 'proper' unwraps, and + // as each decoded packet is 2 bytes, each of those will require 2 underlying input processes. + int numberPoured = pour(encodedByteSource, _sslWrapper.tail()); + assertEquals("Unexpected number of bytes poured into the wrapper input buffer", sslEngineBufferSize, numberPoured); + assertEquals("Unexpected position in encoded source byte buffer", encodedPacketSize * 3, encodedByteSource.position()); + assertEquals("Unexpected capacity", 0, _sslWrapper.capacity()); + + _sslWrapper.process(); + + assertEquals("a_b_c_", _underlyingInput.getAcceptedInput()); + assertEquals("Unexpected capacity", sslEngineBufferSize, _sslWrapper.capacity()); + assertEquals("unexpected underlying process count after wrapper process", 6 , _underlyingInput.getProcessCount()); + assertEquals(4, _dummySslEngine.getUnwrapCount()); // 3 decodes + 1 underflow + + // Process the fourth 'encoded packet' (<-D->) + numberPoured = pour(encodedByteSource, _sslWrapper.tail()); + assertEquals("Unexpected number of bytes poured into the wrapper input buffer", encodedPacketSize, numberPoured); + assertEquals("Unexpected position in encoded source byte buffer", encodedPacketSize * 4, encodedByteSource.position()); + assertEquals("Unexpected capacity", sslEngineBufferSize - encodedPacketSize, _sslWrapper.capacity()); + + _sslWrapper.process(); + + assertEquals("a_b_c_d_", _underlyingInput.getAcceptedInput()); + assertEquals("Unexpected capacity", sslEngineBufferSize, _sslWrapper.capacity()); + assertEquals("unexpected underlying process count after second wrapper process", 8 , _underlyingInput.getProcessCount()); + assertEquals(6, _dummySslEngine.getUnwrapCount()); // earlier + 1 decode + 1 underflow + } + + /** + * Tests that an exception is thrown when the underlying input has zero capacity when the call + * with newly decoded input is initially made. + */ + @Test (timeout = 5000) + public void testUnderlyingInputHasZeroCapacityInitially() + { + int underlyingInputBufferSize = 1; + int encodedPacketSize = 5; + + assertEquals("Unexpected max encoded chunk size", encodedPacketSize, CapitalisingDummySslEngine.MAX_ENCODED_CHUNK_SIZE); + + // Set the input to have a small buffer, but then return 0 from the 2nd capacity call onward. + _underlyingInput.setInputBufferSize(underlyingInputBufferSize); + _underlyingInput.setZeroCapacityAtCount(2); + assertEquals("Unexpected initial underlying input capacity", underlyingInputBufferSize, _underlyingInput.capacity()); + assertEquals("Unexpected underlying input capacity", 0, _underlyingInput.capacity()); + + // Now try decoding the input, should fail + byte[] bytes = "<-A->".getBytes(StandardCharsets.UTF_8); + ByteBuffer encodedByteSource = ByteBuffer.wrap(bytes); + + assertEquals("Unexpected initial wrapper capacity", encodedPacketSize, _sslWrapper.capacity()); + + int numberPoured = pour(encodedByteSource, _sslWrapper.tail()); + assertEquals("Unexpected number of bytes poured into the wrapper input buffer", encodedPacketSize, numberPoured); + assertEquals("Unexpected position in encoded source byte buffer", encodedPacketSize, encodedByteSource.position()); + assertEquals("Unexpected wrapper capacity", 0, _sslWrapper.capacity()); + + try + { + _sslWrapper.process(); + fail("Expected an exception"); + } + catch (TransportException te) + { + // expected. + } + + //Check we got no chars of decoded output. + assertEquals("", _underlyingInput.getAcceptedInput()); + assertEquals("Unexpected wrapper capacity", -1, _sslWrapper.capacity()); + assertEquals("unexpected underlying process count after wrapper process", 0 , _underlyingInput.getProcessCount()); + assertEquals("unexpected underlying capacity count after wrapper process", 3, _underlyingInput.getCapacityCount()); + assertEquals("unexpected underlying capacity after wrapper process", 0 , _underlyingInput.capacity()); + assertEquals(1, _dummySslEngine.getUnwrapCount()); // 1 decode (then exception) + } + + /** + * Tests that an exception is thrown when the underlying input has no capacity (but isn't closed) + * during the process of incrementally passing the decoded bytes to its smaller input buffer + * for processing. + */ + @Test (timeout = 5000) + public void testUnderlyingInputHasZeroCapacityMidProcessing() + { + int underlyingInputBufferSize = 1; + int encodedPacketSize = 5; + + assertEquals("Unexpected max encoded chunk size", encodedPacketSize, CapitalisingDummySslEngine.MAX_ENCODED_CHUNK_SIZE); + + // Set the input to have a small buffer, but then return 0 from the 3rd capacity call onward. + _underlyingInput.setInputBufferSize(underlyingInputBufferSize); + _underlyingInput.setZeroCapacityAtCount(3); + assertEquals("Unexpected initial underlying input capacity", underlyingInputBufferSize, _underlyingInput.capacity()); + + // Now try decoding the input, should fail + byte[] bytes = "<-A->".getBytes(StandardCharsets.UTF_8); + ByteBuffer encodedByteSource = ByteBuffer.wrap(bytes); + + assertEquals("Unexpected initial wrapper capacity", encodedPacketSize, _sslWrapper.capacity()); + + int numberPoured = pour(encodedByteSource, _sslWrapper.tail()); + assertEquals("Unexpected number of bytes poured into the wrapper input buffer", encodedPacketSize, numberPoured); + assertEquals("Unexpected position in encoded source byte buffer", encodedPacketSize, encodedByteSource.position()); + assertEquals("Unexpected wrapper capacity", 0, _sslWrapper.capacity()); + + try + { + _sslWrapper.process(); + fail("Expected an exception"); + } + catch (TransportException te) + { + // expected. + } + + //Check we got the first char (a) of decoded output, but not the second (_). + assertEquals("a", _underlyingInput.getAcceptedInput()); + assertEquals("Unexpected wrapper capacity", -1, _sslWrapper.capacity()); + assertEquals("unexpected underlying process count after wrapper process", 1 , _underlyingInput.getProcessCount()); + assertEquals("unexpected underlying capacity count after wrapper process", 3, _underlyingInput.getCapacityCount()); + assertEquals("unexpected underlying capacity after wrapper process", 0 , _underlyingInput.capacity()); + assertEquals(1, _dummySslEngine.getUnwrapCount()); // 1 decode (then exception) } @Test @@ -132,7 +350,7 @@ SSLException sslException = new SSLException("unwrap exception"); _dummySslEngine.rejectNextEncodedPacket(sslException); - _sslWrapper.tail().put("<-A->".getBytes()); + _sslWrapper.tail().put("<-A->".getBytes(StandardCharsets.UTF_8)); _sslWrapper.process(); assertEquals(_sslWrapper.capacity(), Transport.END_OF_STREAM); } @@ -143,7 +361,7 @@ String underlyingErrorDescription = "dummy underlying error"; _underlyingInput.rejectNextInput(underlyingErrorDescription); - _sslWrapper.tail().put("<-A->".getBytes()); + _sslWrapper.tail().put("<-A->".getBytes(StandardCharsets.UTF_8)); try { _sslWrapper.process(); @@ -167,7 +385,7 @@ ByteBuffer outputBuffer = _sslWrapper.head(); - assertByteBufferContentEquals("<-A->".getBytes(), outputBuffer); + assertByteBufferContentEquals("<-A->".getBytes(StandardCharsets.UTF_8), outputBuffer); } @Test @@ -218,7 +436,7 @@ private void putBytesIntoTransport(String encodedBytes) { - ByteBuffer byteBuffer = ByteBuffer.wrap(encodedBytes.getBytes()); + ByteBuffer byteBuffer = ByteBuffer.wrap(encodedBytes.getBytes(StandardCharsets.UTF_8)); while(byteBuffer.hasRemaining()) { int numberPoured = pour(byteBuffer, _sslWrapper.tail()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/tests/pom.xml new/qpid-proton-0.12.2/tests/pom.xml --- old/qpid-proton-0.12.1/tests/pom.xml 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/tests/pom.xml 2016-04-14 17:50:53.000000000 +0200 @@ -27,7 +27,7 @@ <parent> <groupId>org.apache.qpid</groupId> <artifactId>proton-project</artifactId> - <version>0.12.1</version> + <version>0.12.2</version> </parent> <description>The Proton python system tests execute against the Java or C implementation, using Maven (via this pom) and CMake/CTest respectively. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qpid-proton-0.12.1/version.txt new/qpid-proton-0.12.2/version.txt --- old/qpid-proton-0.12.1/version.txt 2016-03-17 17:27:04.000000000 +0100 +++ new/qpid-proton-0.12.2/version.txt 2016-04-14 17:50:53.000000000 +0200 @@ -1 +1 @@ -0.12.1 +0.12.2