1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package io.netty.handler.ssl;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.buffer.CompositeByteBuf;
21  import io.netty.channel.AbstractCoalescingBufferQueue;
22  import io.netty.channel.Channel;
23  import io.netty.util.internal.PlatformDependent;
24  
25  import static io.netty.buffer.ByteBufUtil.ensureWritableSuccess;
26  
27  
28  
29  
30  
31  
32  abstract class SslHandlerCoalescingBufferQueue extends AbstractCoalescingBufferQueue {
33  
34      private final boolean wantsDirectBuffer;
35  
36      SslHandlerCoalescingBufferQueue(Channel channel, int initSize, boolean wantsDirectBuffer) {
37          super(channel, initSize);
38          this.wantsDirectBuffer = wantsDirectBuffer;
39      }
40  
41      protected abstract int wrapDataSize();
42  
43      @Override
44      protected ByteBuf compose(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf next) {
45          return attemptCopyToCumulation(cumulation, next, wrapDataSize()) ? cumulation :
46                  copyAndCompose(alloc, cumulation, next);
47      }
48  
49      @Override
50      protected ByteBuf composeFirst(ByteBufAllocator allocator, ByteBuf first, int bufferSize) {
51          final ByteBuf newFirst;
52          if (wantsDirectBuffer) {
53              newFirst = allocator.directBuffer(bufferSize);
54          } else {
55              newFirst = allocator.heapBuffer(bufferSize);
56          }
57          try {
58              newFirst.writeBytes(first);
59          } catch (Throwable cause) {
60              newFirst.release();
61              PlatformDependent.throwException(cause);
62          }
63          assert !first.isReadable();
64          first.release();
65          return newFirst;
66      }
67  
68      @Override
69      protected ByteBuf removeEmptyValue() {
70          return null;
71      }
72  
73      private static boolean attemptCopyToCumulation(ByteBuf cumulation, ByteBuf next, int wrapDataSize) {
74          final int inReadableBytes = next.readableBytes();
75          
76          if (inReadableBytes == 0) {
77              next.release();
78              return true;
79          }
80          final int cumulationCapacity = cumulation.capacity();
81          if (wrapDataSize - cumulation.readableBytes() >= inReadableBytes &&
82                  
83                  
84                  
85                  (cumulation.isWritable(inReadableBytes) && cumulationCapacity >= wrapDataSize ||
86                          cumulationCapacity < wrapDataSize &&
87                                  ensureWritableSuccess(cumulation.ensureWritable(inReadableBytes, false)))) {
88              cumulation.writeBytes(next);
89              next.release();
90              return true;
91          }
92          return false;
93      }
94  }