text: /*
   * JBoss, Home of Professional Open Source.
   *
   * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual
   * contributors as indicated by the @author tags.
   *
   * Licensed 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.xnio.ssl;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertTrue;
  
  import java.io.IOError;
  import java.io.IOException;
  import java.nio.ByteBuffer;
  
  import javax.net.ssl.SSLSession;
  
  import org.jmock.Expectations;
  import org.jmock.Mockery;
  import org.jmock.integration.junit4.JUnit4Mockery;
  import org.jmock.lib.concurrent.Synchroniser;
  import org.junit.Test;
  import org.xnio.BufferAllocator;
  import org.xnio.ByteBufferSlicePool;
  import org.xnio.Pool;
  import org.xnio.channels.AssembledConnectedSslStreamChannel;
  import org.xnio.channels.ConnectedSslStreamChannel;
  import org.xnio.mock.ConnectedStreamChannelMock;
  import org.xnio.ssl.mock.SSLEngineMock;
  import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction;
  
  
  /**
   * Tests {@link AssembledConnectedSslStreamChannel} in buffer overflow scenarios.
   * 
   * @author <a href="mailto:frainone@redhat.com">Flavia Rainone</a>
   *
   */
  public class ConnectedSslStreamChannelBufferOverflowTestCase extends AbstractConnectedSslStreamChannelTest {
  
      // mockery context
      protected Mockery context;
  
      // the underlying channel used by JsseConnectedSslStreamChannel above
      protected ConnectedStreamChannelMock connectedChannelMock;
      // the SSLEngine mock, allows to test different engine behavior with channel
      protected SSLEngineMock engineMock;
  
      @Override
      protected ConnectedSslStreamChannel createSslChannel() {
          context = new JUnit4Mockery() {{
              setThreadingPolicy(new Synchroniser());
          }};
          connectedChannelMock = new ConnectedStreamChannelMock();
          engineMock = new SSLEngineMockSmallPacketSize(context);
          final Pool<ByteBuffer> socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 160);
          final Pool<ByteBuffer> applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 160);
          final SslConnection connection = new JsseSslConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool);
          try {
              connection.startHandshake();
          } catch (IOException e) {
              throw new IOError(e);
          }
          return new AssembledConnectedSslStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel());
      }
  
      @Test
      public void bufferOverflowOnWrite() throws IOException {
          boolean fail = false;
          final ByteBuffer buffer = ByteBuffer.allocate(100);
          buffer.put("12345678901234567890".getBytes("UTF-8")).flip();
          // attempt to write... channel is expected to write to throw an IOException
          // SSLEngine required a bigger send buffer but out buffer was already big enough 
          try {
          sslChannel.write(buffer);
          } catch (IOException e) {
              fail = true;
          }
          assertTrue(fail);
      }
  
      @Test
      public void bufferOverflowOnRead() throws IOException {
          engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH);
          connectedChannelMock.setReadData(SSLEngineMock.HANDSHAKE_MSG);
          connectedChannelMock.enableRead(true);
          // attempt to read... channel is expected to not be able to read the message because HANDSHAKE_MSG does not fit
          // in a 10 byte buffer
          assertEquals(0, sslChannel.read(ByteBuffer.allocate(50)));
      }
  
      private static class SSLEngineMockSmallPacketSize extends SSLEngineMock {
          public SSLEngineMockSmallPacketSize (Mockery mockery) {
              super(mockery);
          }
  
          @Override
          public SSLSession getSession() {
              synchronized (mockery) {
                  final SSLSession sessionMock = mockery.mock(SSLSession.class, "SmallPacketsSession");
                  mockery.checking(new Expectations() {{
                      oneOf(sessionMock).getPacketBufferSize();
                      will(returnValue(10));
                      oneOf(sessionMock).getApplicationBufferSize();
                      will(returnValue(5));
                  }});
                  return sessionMock;
              }
          }
      }
  }
  