View Javadoc
1   /*
2    * Copyright 2020 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http3;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.util.AsciiString;
20  import io.netty.util.internal.ConstantTimeUtils;
21  import io.netty.util.internal.PlatformDependent;
22  
23  import static io.netty.util.internal.ObjectUtil.checkInRange;
24  import static java.lang.Math.floorDiv;
25  
26  final class QpackUtil {
27      private static final QpackException PREFIXED_INTEGER_TOO_LONG =
28              QpackException.newStatic(QpackDecoder.class, "toIntOrThrow(...)",
29                      "QPACK - invalid prefixed integer");
30      private static final QpackException PREFIXED_INTEGER_ENCODING_TOO_LONG =
31          QpackException.newStatic(QpackUtil.class, "decodePrefixedInteger(...)",
32              "QPACK - prefixed integer encoding too long");
33      /**
34       * Encode integer according to
35       * <a href="https://tools.ietf.org/html/rfc7541#section-5.1">Section 5.1</a>.
36       */
37      static void encodePrefixedInteger(ByteBuf out, byte mask, int prefixLength, long toEncode) {
38          checkInRange(toEncode, 0, MAX_UNSIGNED_INT, "toEncode");
39          int nbits = (1 << prefixLength) - 1;
40          if (toEncode < nbits) {
41              out.writeByte((byte) (mask | toEncode));
42          } else {
43              out.writeByte((byte) (mask | nbits));
44              long remainder = toEncode - nbits;
45              // A remainder of exactly 128 does not fit in the final (non-continuation) byte, which can only
46              // represent 0-127; it must still go through the continuation-byte branch below.
47              while (remainder >= 128) {
48                  byte next = (byte) ((remainder % 128) | 0x80);
49                  out.writeByte(next);
50                  remainder = remainder / 128;
51              }
52              out.writeByte((byte) remainder);
53          }
54      }
55  
56      /**
57       * Decode the integer or return {@code -1} if not enough bytes are readable.
58       * This method increases the readerIndex when the integer could be decoded.
59       *
60       * @param in the input {@link ByteBuf}
61       * @param prefixLength the prefix length
62       * @return the integer or {@code -1} if not enough readable bytes are in the {@link ByteBuf).
63       */
64      static int decodePrefixedIntegerAsInt(ByteBuf in, int prefixLength) throws QpackException {
65          return toIntOrThrow(decodePrefixedInteger(in, prefixLength));
66      }
67  
68      /**
69       * Converts the passed {@code aLong} to an {@code int} if the value can fit an {@code int}, otherwise throws a
70       * {@link QpackException}.
71       *
72       * @param aLong to convert.
73       * @throws QpackException If the value does not fit an {@code int}.
74       */
75      static int toIntOrThrow(long aLong) throws QpackException {
76          if ((int) aLong != aLong) {
77              throw PREFIXED_INTEGER_TOO_LONG;
78          }
79          return (int) aLong;
80      }
81  
82      /**
83       * Decode the integer or return {@code -1} if not enough bytes are readable.
84       * This method increases the readerIndex when the integer could be decoded.
85       *
86       * @param in the input {@link ByteBuf}
87       * @param prefixLength the prefix length
88       * @return the integer or {@code -1} if not enough readable bytes are in the {@link ByteBuf).
89       */
90      static long decodePrefixedInteger(ByteBuf in, int prefixLength) throws QpackException {
91          int readerIndex = in.readerIndex();
92          int writerIndex = in.writerIndex();
93          if (readerIndex == writerIndex) {
94              return -1;
95          }
96  
97          int nbits = (1 << prefixLength) - 1;
98          int first = in.readByte() & nbits;
99          if (first < nbits) {
100             return first;
101         }
102 
103         int idx = readerIndex + 1;
104         long i = first;
105         int factor = 0;
106         byte next;
107         do {
108             if (factor == 56) {
109                 // Same overflow guard as HpackDecoder.decodeULE128(...): shifting a further 7-bit group in
110                 // would overflow the long accumulator. Treat this as an invalid, over-long encoding rather
111                 // than continuing to scan an unbounded run of continuation bytes.
112                 throw PREFIXED_INTEGER_ENCODING_TOO_LONG;
113             }
114             if (idx == writerIndex) {
115                 in.readerIndex(readerIndex);
116                 return -1;
117             }
118             next = in.getByte(idx++);
119             i += (next & 0x7fL) << factor;
120             factor += 7;
121         } while ((next & 0x80) == 0x80);
122         in.readerIndex(idx);
123         return i;
124     }
125 
126     static boolean firstByteEquals(ByteBuf in, byte mask) {
127         return byteEquals(in, in.readerIndex(), mask);
128     }
129 
130     static boolean byteEquals(ByteBuf in, int offset, byte mask) {
131         return (in.getByte(offset) & mask) == mask;
132     }
133 
134     /**
135      * Compare two {@link CharSequence} objects without leaking timing information.
136      * <p>
137      * The {@code int} return type is intentional and is designed to allow cascading of constant time operations:
138      * <pre>
139      *     String s1 = "foo";
140      *     String s2 = "foo";
141      *     String s3 = "foo";
142      *     String s4 = "goo";
143      *     boolean equals = (equalsConstantTime(s1, s2) & equalsConstantTime(s3, s4)) != 0;
144      * </pre>
145      * @param s1 the first value.
146      * @param s2 the second value.
147      * @return {@code 0} if not equal. {@code 1} if equal.
148      */
149     static int equalsConstantTime(CharSequence s1, CharSequence s2) {
150         if (s1 instanceof AsciiString && s2 instanceof AsciiString) {
151             if (s1.length() != s2.length()) {
152                 return 0;
153             }
154             AsciiString s1Ascii = (AsciiString) s1;
155             AsciiString s2Ascii = (AsciiString) s2;
156             return PlatformDependent.equalsConstantTime(s1Ascii.array(), s1Ascii.arrayOffset(),
157                                                         s2Ascii.array(), s2Ascii.arrayOffset(), s1.length());
158         }
159 
160         return ConstantTimeUtils.equalsConstantTime(s1, s2);
161     }
162 
163     /**
164      * Compare two {@link CharSequence}s.
165      * @param s1 the first value.
166      * @param s2 the second value.
167      * @return {@code false} if not equal. {@code true} if equal.
168      */
169     static boolean equalsVariableTime(CharSequence s1, CharSequence s2) {
170         return AsciiString.contentEquals(s1, s2);
171     }
172 
173     /**
174      * Calculate the MaxEntries based on
175      * <a href="https://www.rfc-editor.org/rfc/rfc9204.html#section-4.5.1.1">RFC9204 Section 4.5.1.1</a>.
176      *
177      * @param maxTableCapacity the maximum table capacity.
178      * @return maxEntries.
179      */
180     static long maxEntries(long maxTableCapacity) {
181         // MaxEntries = floor( MaxTableCapacity / 32 )
182         return floorDiv(maxTableCapacity, 32);
183     }
184 
185     // Section 6.2. Literal Header Field Representation
186     enum IndexType {
187         INCREMENTAL, // Section 6.2.1. Literal Header Field with Incremental Indexing
188         NONE,        // Section 6.2.2. Literal Header Field without Indexing
189         NEVER        // Section 6.2.3. Literal Header Field never Indexed
190     }
191 
192     // Appendix B: Huffman Codes
193     // https://tools.ietf.org/html/rfc7541#appendix-B
194     static final int[] HUFFMAN_CODES = {
195         0x1ff8,
196         0x7fffd8,
197         0xfffffe2,
198         0xfffffe3,
199         0xfffffe4,
200         0xfffffe5,
201         0xfffffe6,
202         0xfffffe7,
203         0xfffffe8,
204         0xffffea,
205         0x3ffffffc,
206         0xfffffe9,
207         0xfffffea,
208         0x3ffffffd,
209         0xfffffeb,
210         0xfffffec,
211         0xfffffed,
212         0xfffffee,
213         0xfffffef,
214         0xffffff0,
215         0xffffff1,
216         0xffffff2,
217         0x3ffffffe,
218         0xffffff3,
219         0xffffff4,
220         0xffffff5,
221         0xffffff6,
222         0xffffff7,
223         0xffffff8,
224         0xffffff9,
225         0xffffffa,
226         0xffffffb,
227         0x14,
228         0x3f8,
229         0x3f9,
230         0xffa,
231         0x1ff9,
232         0x15,
233         0xf8,
234         0x7fa,
235         0x3fa,
236         0x3fb,
237         0xf9,
238         0x7fb,
239         0xfa,
240         0x16,
241         0x17,
242         0x18,
243         0x0,
244         0x1,
245         0x2,
246         0x19,
247         0x1a,
248         0x1b,
249         0x1c,
250         0x1d,
251         0x1e,
252         0x1f,
253         0x5c,
254         0xfb,
255         0x7ffc,
256         0x20,
257         0xffb,
258         0x3fc,
259         0x1ffa,
260         0x21,
261         0x5d,
262         0x5e,
263         0x5f,
264         0x60,
265         0x61,
266         0x62,
267         0x63,
268         0x64,
269         0x65,
270         0x66,
271         0x67,
272         0x68,
273         0x69,
274         0x6a,
275         0x6b,
276         0x6c,
277         0x6d,
278         0x6e,
279         0x6f,
280         0x70,
281         0x71,
282         0x72,
283         0xfc,
284         0x73,
285         0xfd,
286         0x1ffb,
287         0x7fff0,
288         0x1ffc,
289         0x3ffc,
290         0x22,
291         0x7ffd,
292         0x3,
293         0x23,
294         0x4,
295         0x24,
296         0x5,
297         0x25,
298         0x26,
299         0x27,
300         0x6,
301         0x74,
302         0x75,
303         0x28,
304         0x29,
305         0x2a,
306         0x7,
307         0x2b,
308         0x76,
309         0x2c,
310         0x8,
311         0x9,
312         0x2d,
313         0x77,
314         0x78,
315         0x79,
316         0x7a,
317         0x7b,
318         0x7ffe,
319         0x7fc,
320         0x3ffd,
321         0x1ffd,
322         0xffffffc,
323         0xfffe6,
324         0x3fffd2,
325         0xfffe7,
326         0xfffe8,
327         0x3fffd3,
328         0x3fffd4,
329         0x3fffd5,
330         0x7fffd9,
331         0x3fffd6,
332         0x7fffda,
333         0x7fffdb,
334         0x7fffdc,
335         0x7fffdd,
336         0x7fffde,
337         0xffffeb,
338         0x7fffdf,
339         0xffffec,
340         0xffffed,
341         0x3fffd7,
342         0x7fffe0,
343         0xffffee,
344         0x7fffe1,
345         0x7fffe2,
346         0x7fffe3,
347         0x7fffe4,
348         0x1fffdc,
349         0x3fffd8,
350         0x7fffe5,
351         0x3fffd9,
352         0x7fffe6,
353         0x7fffe7,
354         0xffffef,
355         0x3fffda,
356         0x1fffdd,
357         0xfffe9,
358         0x3fffdb,
359         0x3fffdc,
360         0x7fffe8,
361         0x7fffe9,
362         0x1fffde,
363         0x7fffea,
364         0x3fffdd,
365         0x3fffde,
366         0xfffff0,
367         0x1fffdf,
368         0x3fffdf,
369         0x7fffeb,
370         0x7fffec,
371         0x1fffe0,
372         0x1fffe1,
373         0x3fffe0,
374         0x1fffe2,
375         0x7fffed,
376         0x3fffe1,
377         0x7fffee,
378         0x7fffef,
379         0xfffea,
380         0x3fffe2,
381         0x3fffe3,
382         0x3fffe4,
383         0x7ffff0,
384         0x3fffe5,
385         0x3fffe6,
386         0x7ffff1,
387         0x3ffffe0,
388         0x3ffffe1,
389         0xfffeb,
390         0x7fff1,
391         0x3fffe7,
392         0x7ffff2,
393         0x3fffe8,
394         0x1ffffec,
395         0x3ffffe2,
396         0x3ffffe3,
397         0x3ffffe4,
398         0x7ffffde,
399         0x7ffffdf,
400         0x3ffffe5,
401         0xfffff1,
402         0x1ffffed,
403         0x7fff2,
404         0x1fffe3,
405         0x3ffffe6,
406         0x7ffffe0,
407         0x7ffffe1,
408         0x3ffffe7,
409         0x7ffffe2,
410         0xfffff2,
411         0x1fffe4,
412         0x1fffe5,
413         0x3ffffe8,
414         0x3ffffe9,
415         0xffffffd,
416         0x7ffffe3,
417         0x7ffffe4,
418         0x7ffffe5,
419         0xfffec,
420         0xfffff3,
421         0xfffed,
422         0x1fffe6,
423         0x3fffe9,
424         0x1fffe7,
425         0x1fffe8,
426         0x7ffff3,
427         0x3fffea,
428         0x3fffeb,
429         0x1ffffee,
430         0x1ffffef,
431         0xfffff4,
432         0xfffff5,
433         0x3ffffea,
434         0x7ffff4,
435         0x3ffffeb,
436         0x7ffffe6,
437         0x3ffffec,
438         0x3ffffed,
439         0x7ffffe7,
440         0x7ffffe8,
441         0x7ffffe9,
442         0x7ffffea,
443         0x7ffffeb,
444         0xffffffe,
445         0x7ffffec,
446         0x7ffffed,
447         0x7ffffee,
448         0x7ffffef,
449         0x7fffff0,
450         0x3ffffee,
451         0x3fffffff // EOS
452     };
453 
454     static final byte[] HUFFMAN_CODE_LENGTHS = {
455         13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
456         28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
457         6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
458         5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
459         13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
460         7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
461         15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
462         6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
463         20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
464         24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
465         22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
466         21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
467         26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
468         19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
469         20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
470         26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
471         30 // EOS
472     };
473 
474     static final int HUFFMAN_EOS = 256;
475 
476     static final long MIN_HEADER_TABLE_SIZE = 0;
477     static final long MAX_UNSIGNED_INT = 0xffffffffL;
478     static final long MAX_HEADER_TABLE_SIZE = MAX_UNSIGNED_INT;
479 
480     private QpackUtil() {
481     }
482 }