Line data Source code
1 : #ifndef HEADER_fd_src_waltz_h2_fd_hpack_h 2 : #define HEADER_fd_src_waltz_h2_fd_hpack_h 3 : 4 : /* fd_hpack.h provides APIs for HPACK compression and decompression. 5 : 6 : Supports the static table and Huffman string coding. Does not use 7 : the dynamic table while encoding. Assumes that the endpoint used 8 : HTTP/2 SETTINGS to force the peer's dynamic table size to zero. */ 9 : 10 : #include "fd_h2_base.h" 11 : 12 : /* fd_h2_hdr_t points to an HTTP/2 header name:value pair. 13 : 14 : {name,value} point to decoded header values stored either in the 15 : hardcoded HPACK static table, the binary frame, or a scratch buffer. 16 : It is not guaranteed that these are valid ASCII. These are NOT 17 : null-terminated. 18 : 19 : (hint&FD_H2_HDR_HINT_INDEXED) indicates that the HPACK coding of the 20 : header referenced a static table entry. The index of the entry is 21 : in the low 6 bits. 22 : 23 : (hint&FD_H2_HDR_HINT_HUFFMAN) is internal and can be safely ignored, 24 : as fd_hpack_rd_next takes care of Huffman coding. */ 25 : 26 : struct fd_h2_hdr { 27 : char const * name; 28 : char const * value; 29 : ushort name_len; 30 : ushort hint; 31 : uint value_len; 32 : }; 33 : 34 : typedef struct fd_h2_hdr fd_h2_hdr_t; 35 : 36 0 : #define FD_H2_HDR_HINT_NAME_HUFFMAN ((ushort)0x8000) /* name is huffman coded */ 37 0 : #define FD_H2_HDR_HINT_VALUE_HUFFMAN ((ushort)0x4000) /* value is huffman coded */ 38 0 : #define FD_H2_HDR_HINT_HUFFMAN ((ushort)(FD_H2_HDR_HINT_NAME_HUFFMAN|FD_H2_HDR_HINT_VALUE_HUFFMAN)) 39 0 : #define FD_H2_HDR_HINT_NAME_INDEXED ((ushort)0x2000) /* name was indexed from table */ 40 0 : #define FD_H2_HDR_HINT_VALUE_INDEXED ((ushort)0x1000) /* value was indexed from table */ 41 : #define FD_H2_HDR_HINT_INDEXED ((ushort)(FD_H2_HDR_HINT_NAME_INDEXED|FD_H2_HDR_HINT_VALUE_INDEXED)) 42 0 : #define FD_H2_HDR_HINT_GET_INDEX(hint) ((uchar)((hint)&0xFF)) 43 : 44 : /* An fd_hpack_rd_t object reads a block of HPACK-encoded HTTP/2 45 : headers. For example usage, see test_hpack. */ 46 : 47 : struct fd_hpack_rd { 48 : uchar const * src; 49 : uchar const * src_end; 50 : }; 51 : 52 : typedef struct fd_hpack_rd fd_hpack_rd_t; 53 : 54 : /* fd_hpack_skip_t incrementally decodes a field block whose fields are 55 : discarded. It retains no input or decoded strings, so both records 56 : and Huffman strings may cross fragment boundaries. Like fd_hpack_rd, 57 : it assumes the peer's dynamic table size has been forced to zero. */ 58 : 59 : struct fd_hpack_skip { 60 : ulong integer; /* current integer, or encoded string bytes remaining */ 61 : ushort huff_state; /* 0 for raw strings, otherwise Huffman decoder state */ 62 : uchar phase; 63 : uchar int_shift; /* 0, or 7 plus the shift of the next continuation octet */ 64 : uchar field_seen; /* table size updates are only allowed before fields */ 65 : }; 66 : 67 : typedef struct fd_hpack_skip fd_hpack_skip_t; 68 : 69 : FD_PROTOTYPES_BEGIN 70 : 71 : /* Start a new field block. */ 72 : 73 : static inline void 74 0 : fd_hpack_skip_init( fd_hpack_skip_t * skip ) { 75 0 : *skip = (fd_hpack_skip_t){0}; 76 0 : } 77 : 78 : /* Decode a fragment without retaining its fields. fin marks the end of 79 : the field block, not the end of a string or an individual frame. 80 : Returns FD_H2_SUCCESS for a valid complete block or an incomplete 81 : prefix when !fin. Returns FD_H2_ERR_COMPRESSION for invalid HPACK, 82 : integers with more than eight continuation octets, or an unfinished 83 : record when fin. Errors remain sticky until fd_hpack_skip_init. */ 84 : 85 : uint 86 : fd_hpack_skip_feed( fd_hpack_skip_t * skip, 87 : uchar const * src, 88 : ulong srcsz, 89 : int fin ); 90 : 91 : /* fd_hpack_rd_init initializes a hpack_rd for reading of the header 92 : block in src. hpack_rd has a read interest in src for its entire 93 : lifetime. */ 94 : 95 : fd_hpack_rd_t * 96 : fd_hpack_rd_init( fd_hpack_rd_t * rd, 97 : uchar const * src, 98 : ulong srcsz ); 99 : 100 : /* fd_hpack_rd_done returns 1 if all header entries were read from 101 : hpack_rd. Returns 0 if fd_hpack_rd_next should be called again. */ 102 : 103 : static inline int 104 0 : fd_hpack_rd_done( fd_hpack_rd_t const * rd ) { 105 0 : return rd->src >= rd->src_end; 106 0 : } 107 : 108 : /* fd_hpack_rd_next reads the next header from hpack_rd. hdr is 109 : populated with pointers to the decoded data. These pointers either 110 : point into hpack_rd->src or *scratch. 111 : 112 : *scratch is assumed to point to the next free byte in a scratch 113 : buffer. scratch_end points one past the last byte of the scratch 114 : buffer. 115 : 116 : Returns FD_H2_SUCCESS, populates header, and updates *scratch on 117 : success. On failure, returns FD_H2_ERR_COMPRESSION and leaves 118 : *scratch intact. Reasons for failure include HPACK parse error, 119 : out-of-bounds table index, use of the dynamic table, Huffman coding 120 : error, or out of scratch space. The caller should assume that *hdr 121 : and **scratch (the free bytes in the scratch buffer, not the pointer 122 : itself) are invalidated/filled with garbage on failure. */ 123 : 124 : uint 125 : fd_hpack_rd_next( fd_hpack_rd_t * hpack_rd, 126 : fd_h2_hdr_t * hdr, 127 : uchar ** scratch, 128 : uchar * scratch_end ); 129 : 130 : FD_PROTOTYPES_END 131 : 132 : #endif /* HEADER_fd_src_waltz_h2_fd_hpack_h */