1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.http2.impl.nio;
29
30 import java.nio.ByteBuffer;
31
32 import org.apache.hc.core5.http.ConnectionClosedException;
33 import org.apache.hc.core5.http2.H2ConnectionException;
34 import org.apache.hc.core5.http2.H2CorruptFrameException;
35 import org.apache.hc.core5.http2.ReadableByteChannelMock;
36 import org.apache.hc.core5.http2.WritableByteChannelMock;
37 import org.apache.hc.core5.http2.frame.FrameConsts;
38 import org.apache.hc.core5.http2.frame.FrameFlag;
39 import org.apache.hc.core5.http2.frame.FrameType;
40 import org.apache.hc.core5.http2.frame.RawFrame;
41 import org.apache.hc.core5.http2.impl.BasicH2TransportMetrics;
42 import org.junit.jupiter.api.Assertions;
43 import org.junit.jupiter.api.Test;
44
45 public class TestFrameInOutBuffers {
46
47 @Test
48 public void testReadWriteFrame() throws Exception {
49 final WritableByteChannelMock writableChannel = new WritableByteChannelMock(1024);
50 final FrameOutputBuffer outbuffer = new FrameOutputBuffer(16 * 1024);
51
52 final RawFrame frame = new RawFrame(FrameType.DATA.getValue(), 0, 1,
53 ByteBuffer.wrap(new byte[]{1,2,3,4,5}));
54 outbuffer.write(frame, writableChannel);
55
56 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
57 final byte[] bytes = writableChannel.toByteArray();
58 Assertions.assertEquals(FrameConsts.HEAD_LEN + 5, bytes.length);
59
60 Assertions.assertEquals(1, outbuffer.getMetrics().getFramesTransferred());
61 Assertions.assertEquals(bytes.length, outbuffer.getMetrics().getBytesTransferred());
62
63 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(bytes);
64 final RawFrame frame2 = inBuffer.read(readableChannel);
65 Assertions.assertEquals(FrameType.DATA.getValue(), frame2.getType());
66 Assertions.assertEquals(0, frame2.getFlags());
67 Assertions.assertEquals(1L, frame2.getStreamId());
68 final ByteBuffer payload2 = frame2.getPayloadContent();
69 Assertions.assertNotNull(payload2);
70 Assertions.assertEquals(5, payload2.remaining());
71 Assertions.assertEquals(1, payload2.get());
72 Assertions.assertEquals(2, payload2.get());
73 Assertions.assertEquals(3, payload2.get());
74 Assertions.assertEquals(4, payload2.get());
75 Assertions.assertEquals(5, payload2.get());
76 Assertions.assertEquals(-1, readableChannel.read(ByteBuffer.allocate(1024)));
77
78 Assertions.assertEquals(1, inBuffer.getMetrics().getFramesTransferred());
79 Assertions.assertEquals(bytes.length, inBuffer.getMetrics().getBytesTransferred());
80
81 final RawFrame frame3 = inBuffer.read(ByteBuffer.wrap(bytes), readableChannel);
82 Assertions.assertEquals(FrameType.DATA.getValue(), frame3.getType());
83 Assertions.assertEquals(0, frame3.getFlags());
84 Assertions.assertEquals(1L, frame3.getStreamId());
85 final ByteBuffer payload3 = frame3.getPayloadContent();
86 Assertions.assertNotNull(payload3);
87 Assertions.assertEquals(5, payload3.remaining());
88 Assertions.assertEquals(1, payload3.get());
89 Assertions.assertEquals(2, payload3.get());
90 Assertions.assertEquals(3, payload3.get());
91 Assertions.assertEquals(4, payload3.get());
92 Assertions.assertEquals(5, payload3.get());
93
94 Assertions.assertEquals(2, inBuffer.getMetrics().getFramesTransferred());
95 Assertions.assertEquals(bytes.length * 2, inBuffer.getMetrics().getBytesTransferred());
96 }
97
98 @Test
99 public void testPartialFrameWrite() throws Exception {
100 final WritableByteChannelMock writableChannel = new WritableByteChannelMock(1024, FrameConsts.HEAD_LEN + 10);
101 final FrameOutputBuffer outbuffer = new FrameOutputBuffer(16 * 1024);
102 final RawFrame frame = new RawFrame(FrameType.DATA.getValue(), FrameFlag.END_STREAM.getValue(), 5,
103 ByteBuffer.wrap(new byte[]{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}));
104
105 outbuffer.write(frame, writableChannel);
106 Assertions.assertArrayEquals(new byte[] {0,0,16,0,1,0,0,0,5,48,49,50,51,52,53,54,55,56,57},
107 writableChannel.toByteArray());
108
109 Assertions.assertFalse(outbuffer.isEmpty());
110 outbuffer.flush(writableChannel);
111 Assertions.assertArrayEquals(new byte[] {0,0,16,0,1,0,0,0,5,48,49,50,51,52,53,54,55,56,57},
112 writableChannel.toByteArray());
113
114 writableChannel.flush();
115 outbuffer.flush(writableChannel);
116 Assertions.assertArrayEquals(new byte[] {0,0,16,0,1,0,0,0,5,48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102},
117 writableChannel.toByteArray());
118 }
119
120 @Test
121 public void testReadFrameMultiple() throws Exception {
122 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
123 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(
124 new byte[] {
125 0,0,10,0,8,0,0,0,8,4,0,1,2,3,4,0,0,0,0,
126 0,0,10,0,9,0,0,0,8,4,5,6,7,8,9,0,0,0,0
127 });
128
129 final RawFrame frame1 = inBuffer.read(readableChannel);
130 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame1.getType()));
131 Assertions.assertEquals(8, frame1.getFlags());
132 Assertions.assertEquals(8, frame1.getStreamId());
133 final ByteBuffer payload1 = frame1.getPayloadContent();
134 Assertions.assertNotNull(payload1);
135 Assertions.assertEquals(5, payload1.remaining());
136 Assertions.assertEquals(0, payload1.get());
137 Assertions.assertEquals(1, payload1.get());
138 Assertions.assertEquals(2, payload1.get());
139 Assertions.assertEquals(3, payload1.get());
140 Assertions.assertEquals(4, payload1.get());
141
142 final RawFrame frame2 = inBuffer.read(readableChannel);
143 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame2.getType()));
144 Assertions.assertEquals(FrameFlag.of(FrameFlag.END_STREAM, FrameFlag.PADDED), frame2.getFlags());
145 Assertions.assertEquals(8, frame2.getStreamId());
146 final ByteBuffer payload2 = frame2.getPayloadContent();
147 Assertions.assertNotNull(payload2);
148 Assertions.assertEquals(5, payload2.remaining());
149 Assertions.assertEquals(5, payload2.get());
150 Assertions.assertEquals(6, payload2.get());
151 Assertions.assertEquals(7, payload2.get());
152 Assertions.assertEquals(8, payload2.get());
153 Assertions.assertEquals(9, payload2.get());
154
155 Assertions.assertEquals(-1, readableChannel.read(ByteBuffer.allocate(1024)));
156 }
157
158 @Test
159 public void testReadFrameMultipleSmallBuffer() throws Exception {
160 final FrameInputBuffer inBuffer = new FrameInputBuffer(new BasicH2TransportMetrics(), 20, 10);
161 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(
162 new byte[] {
163 0,0,10,0,8,0,0,0,8,4,1,1,1,1,1,0,0,0,0,
164 0,0,5,0,0,0,0,0,8,2,2,2,2,2,
165 0,0,10,0,9,0,0,0,8,4,3,3,3,3,3,0,0,0,0
166 });
167
168 final RawFrame frame1 = inBuffer.read(readableChannel);
169 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame1.getType()));
170 Assertions.assertEquals(8, frame1.getFlags());
171 Assertions.assertEquals(8, frame1.getStreamId());
172 final ByteBuffer payload1 = frame1.getPayloadContent();
173 Assertions.assertNotNull(payload1);
174 Assertions.assertEquals(5, payload1.remaining());
175 Assertions.assertEquals(1, payload1.get());
176 Assertions.assertEquals(1, payload1.get());
177 Assertions.assertEquals(1, payload1.get());
178 Assertions.assertEquals(1, payload1.get());
179 Assertions.assertEquals(1, payload1.get());
180
181 final RawFrame frame2 = inBuffer.read(readableChannel);
182 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame2.getType()));
183 Assertions.assertEquals(0, frame2.getFlags());
184 Assertions.assertEquals(8, frame2.getStreamId());
185 final ByteBuffer payload2 = frame2.getPayloadContent();
186 Assertions.assertNotNull(payload2);
187 Assertions.assertEquals(5, payload2.remaining());
188 Assertions.assertEquals(2, payload2.get());
189 Assertions.assertEquals(2, payload2.get());
190 Assertions.assertEquals(2, payload2.get());
191 Assertions.assertEquals(2, payload2.get());
192 Assertions.assertEquals(2, payload2.get());
193
194 final RawFrame frame3 = inBuffer.read(readableChannel);
195 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame3.getType()));
196 Assertions.assertEquals(FrameFlag.of(FrameFlag.END_STREAM, FrameFlag.PADDED), frame3.getFlags());
197 Assertions.assertEquals(8, frame3.getStreamId());
198 final ByteBuffer payload3 = frame3.getPayloadContent();
199 Assertions.assertNotNull(payload3);
200 Assertions.assertEquals(5, payload3.remaining());
201 Assertions.assertEquals(3, payload3.get());
202 Assertions.assertEquals(3, payload3.get());
203 Assertions.assertEquals(3, payload3.get());
204 Assertions.assertEquals(3, payload3.get());
205 Assertions.assertEquals(3, payload3.get());
206
207 Assertions.assertEquals(-1, readableChannel.read(ByteBuffer.allocate(1024)));
208 }
209
210 @Test
211 public void testReadFramePartialReads() throws Exception {
212 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
213 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(
214 new byte[] {0,0},
215 new byte[] {10,0,9,0},
216 new byte[] {0,0,8},
217 new byte[] {4},
218 new byte[] {1,2,3,4},
219 new byte[] {5,0},
220 new byte[] {0,0,0});
221
222 final RawFrame frame = inBuffer.read(readableChannel);
223 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame.getType()));
224 Assertions.assertEquals(FrameFlag.of(FrameFlag.END_STREAM, FrameFlag.PADDED), frame.getFlags());
225 Assertions.assertEquals(8, frame.getStreamId());
226 final ByteBuffer payload = frame.getPayloadContent();
227 Assertions.assertNotNull(payload);
228 Assertions.assertEquals(5, payload.remaining());
229 Assertions.assertEquals(1, payload.get());
230 Assertions.assertEquals(2, payload.get());
231 Assertions.assertEquals(3, payload.get());
232 Assertions.assertEquals(4, payload.get());
233 Assertions.assertEquals(5, payload.get());
234
235 Assertions.assertEquals(-1, readableChannel.read(ByteBuffer.allocate(1024)));
236 }
237
238 @Test
239 public void testReadEmptyFrame() throws Exception {
240 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
241 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(
242 new byte[] {0,0,0,0,0,0,0,0,0});
243
244 final RawFrame frame = inBuffer.read(readableChannel);
245 Assertions.assertEquals(FrameType.DATA, FrameType.valueOf(frame.getType()));
246 Assertions.assertEquals(0, frame.getFlags());
247 Assertions.assertEquals(0, frame.getStreamId());
248 final ByteBuffer payload = frame.getPayloadContent();
249 Assertions.assertNull(payload);
250 }
251
252 @Test
253 public void testReadFrameConnectionClosed() throws Exception {
254 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
255 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(new byte[] {});
256
257 Assertions.assertNull(inBuffer.read(readableChannel));
258 Assertions.assertThrows(ConnectionClosedException.class, () ->
259 inBuffer.read(readableChannel));
260 }
261
262 @Test
263 public void testReadFrameCorruptFrame() throws Exception {
264 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
265 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(new byte[] {0,0});
266
267 Assertions.assertThrows(H2CorruptFrameException.class, () ->
268 inBuffer.read(readableChannel));
269 }
270
271 @Test
272 public void testWriteFrameExceedingLimit() throws Exception {
273 final WritableByteChannelMock writableChannel = new WritableByteChannelMock(1024);
274 final FrameOutputBuffer outbuffer = new FrameOutputBuffer(1024);
275
276 final RawFrame frame = new RawFrame(FrameType.DATA.getValue(), 0, 1,
277 ByteBuffer.wrap(new byte[2048]));
278 Assertions.assertThrows(IllegalArgumentException.class, () ->
279 outbuffer.write(frame, writableChannel));
280 }
281
282 @Test
283 public void testReadFrameExceedingLimit() throws Exception {
284 final FrameInputBuffer inBuffer = new FrameInputBuffer(16 * 1024);
285 final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(
286 new byte[] {0,-128,-128,0,0,0,0,0,1});
287
288 Assertions.assertThrows(H2ConnectionException.class, () ->
289 inBuffer.read(readableChannel));
290 }
291
292 }
293