1+ /*
2+ * ====================================================================
3+ * Licensed to the Apache Software Foundation (ASF) under one
4+ * or more contributor license agreements. See the NOTICE file
5+ * distributed with this work for additional information
6+ * regarding copyright ownership. The ASF licenses this file
7+ * to you under the Apache License, Version 2.0 (the
8+ * "License"); you may not use this file except in compliance
9+ * with the License. You may obtain a copy of the License at
10+ *
11+ * http://www.apache.org/licenses/LICENSE-2.0
12+ *
13+ * Unless required by applicable law or agreed to in writing,
14+ * software distributed under the License is distributed on an
15+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+ * KIND, either express or implied. See the License for the
17+ * specific language governing permissions and limitations
18+ * under the License.
19+ * ====================================================================
20+ *
21+ * This software consists of voluntary contributions made by many
22+ * individuals on behalf of the Apache Software Foundation. For more
23+ * information on the Apache Software Foundation, please see
24+ * <http://www.apache.org/>.
25+ *
26+ */
27+ package org .apache .hc .core5 .http2 .hpack ;
28+
29+ import static org .junit .jupiter .api .Assertions .assertArrayEquals ;
30+ import static org .junit .jupiter .api .Assertions .assertEquals ;
31+ import static org .junit .jupiter .api .Assertions .assertNotEquals ;
32+
33+ import java .nio .charset .StandardCharsets ;
34+ import java .util .Arrays ;
35+
36+ import org .apache .hc .core5 .util .ByteArrayBuffer ;
37+ import org .junit .jupiter .api .Test ;
38+
39+ class TestHPackEncoder {
40+
41+ @ Test
42+ void testMultipleTableSizeUpdatesSignalMinimumFirstThenFinal () throws Exception {
43+ final OutboundDynamicTable dynamicTable = new OutboundDynamicTable (4096 );
44+ final HPackEncoder encoder = new HPackEncoder (dynamicTable , StandardCharsets .US_ASCII );
45+ final ByteArrayBuffer dst = new ByteArrayBuffer (128 );
46+
47+ encoder .setMaxTableSize (1024 );
48+ encoder .setMaxTableSize (2048 );
49+
50+ // No local resize until the next header block is encoded.
51+ assertEquals (4096 , dynamicTable .getMaxSize ());
52+ assertEquals (2048 , encoder .getMaxTableSize ());
53+
54+ encoder .encodeHeader (dst , "x-test" , "abc" , false , false , false );
55+
56+ // First 6 bytes must be:
57+ // 1024 => 0x3f 0xe1 0x07
58+ // 2048 => 0x3f 0xe1 0x0f
59+ final byte [] actual = Arrays .copyOf (dst .array (), dst .length ());
60+ assertArrayEquals (new byte []{
61+ 0x3f , (byte ) 0xe1 , 0x07 ,
62+ 0x3f , (byte ) 0xe1 , 0x0f
63+ }, Arrays .copyOf (actual , 6 ));
64+
65+ // Local encoder state must also end at the final advertised size.
66+ assertEquals (2048 , dynamicTable .getMaxSize ());
67+ }
68+
69+ @ Test
70+ void testShrinkThenRestoreOriginalStillEmitsTwoUpdates () throws Exception {
71+ final OutboundDynamicTable dynamicTable = new OutboundDynamicTable (4096 );
72+ final HPackEncoder encoder = new HPackEncoder (dynamicTable , StandardCharsets .US_ASCII );
73+ final ByteArrayBuffer dst = new ByteArrayBuffer (128 );
74+
75+ encoder .setMaxTableSize (1024 );
76+ encoder .setMaxTableSize (4096 );
77+
78+ encoder .encodeHeader (dst , "x-test" , "abc" , false , false , false );
79+
80+ final byte [] actual = Arrays .copyOf (dst .array (), dst .length ());
81+ assertArrayEquals (new byte []{
82+ 0x3f , (byte ) 0xe1 , 0x07 ,
83+ 0x3f , (byte ) 0xe1 , 0x1f
84+ }, Arrays .copyOf (actual , 6 ));
85+
86+ assertEquals (4096 , dynamicTable .getMaxSize ());
87+ }
88+
89+ @ Test
90+ void testTableSizeUpdateZeroThenRestore () throws Exception {
91+ final OutboundDynamicTable dynamicTable = new OutboundDynamicTable (4096 );
92+ final HPackEncoder encoder = new HPackEncoder (dynamicTable , StandardCharsets .US_ASCII );
93+ final ByteArrayBuffer dst = new ByteArrayBuffer (128 );
94+
95+ encoder .setMaxTableSize (0 );
96+ encoder .setMaxTableSize (4096 );
97+
98+ encoder .encodeHeader (dst , "x-test" , "abc" , false , false , false );
99+
100+ final byte [] actual = Arrays .copyOf (dst .array (), dst .length ());
101+ assertArrayEquals (new byte []{
102+ 0x20 ,
103+ 0x3f , (byte ) 0xe1 , 0x1f
104+ }, Arrays .copyOf (actual , 4 ));
105+
106+ assertEquals (4096 , dynamicTable .getMaxSize ());
107+ }
108+
109+ @ Test
110+ void testTableSizeUpdateIsNotRepeatedAcrossHeaderBlocks () throws Exception {
111+ final OutboundDynamicTable dynamicTable = new OutboundDynamicTable (4096 );
112+ final HPackEncoder encoder = new HPackEncoder (dynamicTable , StandardCharsets .US_ASCII );
113+
114+ encoder .setMaxTableSize (1024 );
115+
116+ final ByteArrayBuffer dst1 = new ByteArrayBuffer (128 );
117+ encoder .encodeHeader (dst1 , "x-a" , "1" , false , false , false );
118+
119+ final ByteArrayBuffer dst2 = new ByteArrayBuffer (128 );
120+ encoder .encodeHeader (dst2 , "x-b" , "2" , false , false , false );
121+
122+ final byte [] first = Arrays .copyOf (dst1 .array (), dst1 .length ());
123+ assertArrayEquals (new byte []{
124+ 0x3f , (byte ) 0xe1 , 0x07
125+ }, Arrays .copyOf (first , 3 ));
126+
127+ final byte [] second = Arrays .copyOf (dst2 .array (), dst2 .length ());
128+ assertNotEquals (0x20 , second [0 ] & 0xe0 );
129+ }
130+
131+ }
0 commit comments