hpack_decoder.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/http/private/hpack.h>
  6. #define HPACK_LOGF(level, decoder, text, ...) \
  7. AWS_LOGF_##level(AWS_LS_HTTP_DECODER, "id=%p [HPACK]: " text, (decoder)->log_id, __VA_ARGS__)
  8. #define HPACK_LOG(level, decoder, text) HPACK_LOGF(level, decoder, "%s", text)
  9. struct aws_huffman_symbol_coder *hpack_get_coder(void);
  10. /* Used while decoding the header name & value, grows if necessary */
  11. const size_t s_hpack_decoder_scratch_initial_size = 512;
  12. void aws_hpack_decoder_init(struct aws_hpack_decoder *decoder, struct aws_allocator *allocator, const void *log_id) {
  13. AWS_ZERO_STRUCT(*decoder);
  14. decoder->log_id = log_id;
  15. aws_huffman_decoder_init(&decoder->huffman_decoder, hpack_get_coder());
  16. aws_huffman_decoder_allow_growth(&decoder->huffman_decoder, true);
  17. aws_hpack_context_init(&decoder->context, allocator, AWS_LS_HTTP_DECODER, log_id);
  18. aws_byte_buf_init(&decoder->progress_entry.scratch, allocator, s_hpack_decoder_scratch_initial_size);
  19. decoder->dynamic_table_protocol_max_size_setting = aws_hpack_get_dynamic_table_max_size(&decoder->context);
  20. }
  21. void aws_hpack_decoder_clean_up(struct aws_hpack_decoder *decoder) {
  22. aws_hpack_context_clean_up(&decoder->context);
  23. aws_byte_buf_clean_up(&decoder->progress_entry.scratch);
  24. AWS_ZERO_STRUCT(*decoder);
  25. }
  26. static const struct aws_http_header *s_get_header_u64(const struct aws_hpack_decoder *decoder, uint64_t index) {
  27. if (index > SIZE_MAX) {
  28. HPACK_LOG(ERROR, decoder, "Header index is absurdly large");
  29. aws_raise_error(AWS_ERROR_INVALID_INDEX);
  30. return NULL;
  31. }
  32. return aws_hpack_get_header(&decoder->context, (size_t)index);
  33. }
  34. void aws_hpack_decoder_update_max_table_size(struct aws_hpack_decoder *decoder, uint32_t setting_max_size) {
  35. decoder->dynamic_table_protocol_max_size_setting = setting_max_size;
  36. }
  37. /* Return a byte with the N right-most bits masked.
  38. * Ex: 2 -> 00000011 */
  39. static uint8_t s_masked_right_bits_u8(uint8_t num_masked_bits) {
  40. AWS_ASSERT(num_masked_bits <= 8);
  41. const uint8_t cut_bits = 8 - num_masked_bits;
  42. return UINT8_MAX >> cut_bits;
  43. }
  44. int aws_hpack_decode_integer(
  45. struct aws_hpack_decoder *decoder,
  46. struct aws_byte_cursor *to_decode,
  47. uint8_t prefix_size,
  48. uint64_t *integer,
  49. bool *complete) {
  50. AWS_PRECONDITION(decoder);
  51. AWS_PRECONDITION(to_decode);
  52. AWS_PRECONDITION(prefix_size <= 8);
  53. AWS_PRECONDITION(integer);
  54. const uint8_t prefix_mask = s_masked_right_bits_u8(prefix_size);
  55. struct hpack_progress_integer *progress = &decoder->progress_integer;
  56. while (to_decode->len) {
  57. switch (progress->state) {
  58. case HPACK_INTEGER_STATE_INIT: {
  59. /* Read the first byte, and check whether this is it, or we need to continue */
  60. uint8_t byte = 0;
  61. bool succ = aws_byte_cursor_read_u8(to_decode, &byte);
  62. AWS_FATAL_ASSERT(succ);
  63. /* Cut the prefix */
  64. byte &= prefix_mask;
  65. /* No matter what, the first byte's value is always added to the integer */
  66. *integer = byte;
  67. if (byte != prefix_mask) {
  68. goto handle_complete;
  69. }
  70. progress->state = HPACK_INTEGER_STATE_VALUE;
  71. } break;
  72. case HPACK_INTEGER_STATE_VALUE: {
  73. uint8_t byte = 0;
  74. bool succ = aws_byte_cursor_read_u8(to_decode, &byte);
  75. AWS_FATAL_ASSERT(succ);
  76. uint64_t new_byte_value = (uint64_t)(byte & 127) << progress->bit_count;
  77. if (*integer + new_byte_value < *integer) {
  78. return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
  79. }
  80. *integer += new_byte_value;
  81. /* Check if we're done */
  82. if ((byte & 128) == 0) {
  83. goto handle_complete;
  84. }
  85. /* Increment the bit count */
  86. progress->bit_count += 7;
  87. /* 7 Bits are expected to be used, so if we get to the point where any of
  88. * those bits can't be used it's a decoding error */
  89. if (progress->bit_count > 64 - 7) {
  90. return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
  91. }
  92. } break;
  93. }
  94. }
  95. /* Fell out of data loop, must need more data */
  96. *complete = false;
  97. return AWS_OP_SUCCESS;
  98. handle_complete:
  99. AWS_ZERO_STRUCT(decoder->progress_integer);
  100. *complete = true;
  101. return AWS_OP_SUCCESS;
  102. }
  103. int aws_hpack_decode_string(
  104. struct aws_hpack_decoder *decoder,
  105. struct aws_byte_cursor *to_decode,
  106. struct aws_byte_buf *output,
  107. bool *complete) {
  108. AWS_PRECONDITION(decoder);
  109. AWS_PRECONDITION(to_decode);
  110. AWS_PRECONDITION(output);
  111. AWS_PRECONDITION(complete);
  112. struct hpack_progress_string *progress = &decoder->progress_string;
  113. while (to_decode->len) {
  114. switch (progress->state) {
  115. case HPACK_STRING_STATE_INIT: {
  116. /* Do init stuff */
  117. progress->state = HPACK_STRING_STATE_LENGTH;
  118. progress->use_huffman = *to_decode->ptr >> 7;
  119. aws_huffman_decoder_reset(&decoder->huffman_decoder);
  120. /* fallthrough, since we didn't consume any data */
  121. }
  122. /* FALLTHRU */
  123. case HPACK_STRING_STATE_LENGTH: {
  124. bool length_complete = false;
  125. if (aws_hpack_decode_integer(decoder, to_decode, 7, &progress->length, &length_complete)) {
  126. return AWS_OP_ERR;
  127. }
  128. if (!length_complete) {
  129. goto handle_ongoing;
  130. }
  131. if (progress->length == 0) {
  132. goto handle_complete;
  133. }
  134. if (progress->length > SIZE_MAX) {
  135. return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
  136. }
  137. progress->state = HPACK_STRING_STATE_VALUE;
  138. } break;
  139. case HPACK_STRING_STATE_VALUE: {
  140. /* Take either as much data as we need, or as much as we can */
  141. size_t to_process = aws_min_size((size_t)progress->length, to_decode->len);
  142. progress->length -= to_process;
  143. struct aws_byte_cursor chunk = aws_byte_cursor_advance(to_decode, to_process);
  144. if (progress->use_huffman) {
  145. if (aws_huffman_decode(&decoder->huffman_decoder, &chunk, output)) {
  146. HPACK_LOGF(ERROR, decoder, "Error from Huffman decoder: %s", aws_error_name(aws_last_error()));
  147. return AWS_OP_ERR;
  148. }
  149. /* Decoder should consume all bytes we feed it.
  150. * EOS (end-of-string) symbol could stop it early, but HPACK says to treat EOS as error. */
  151. if (chunk.len != 0) {
  152. HPACK_LOG(ERROR, decoder, "Huffman encoded end-of-string symbol is illegal");
  153. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  154. }
  155. } else {
  156. if (aws_byte_buf_append_dynamic(output, &chunk)) {
  157. return AWS_OP_ERR;
  158. }
  159. }
  160. /* If whole length consumed, we're done */
  161. if (progress->length == 0) {
  162. /* #TODO Validate any padding bits left over in final byte of string.
  163. * "A padding not corresponding to the most significant bits of the
  164. * code for the EOS symbol MUST be treated as a decoding error" */
  165. /* #TODO impose limits on string length */
  166. goto handle_complete;
  167. }
  168. } break;
  169. }
  170. }
  171. handle_ongoing:
  172. /* Fell out of to_decode loop, must still be in progress */
  173. AWS_ASSERT(to_decode->len == 0);
  174. *complete = false;
  175. return AWS_OP_SUCCESS;
  176. handle_complete:
  177. AWS_ASSERT(decoder->progress_string.length == 0);
  178. AWS_ZERO_STRUCT(decoder->progress_string);
  179. *complete = true;
  180. return AWS_OP_SUCCESS;
  181. }
  182. /* Implements RFC-7541 Section 6 - Binary Format */
  183. int aws_hpack_decode(
  184. struct aws_hpack_decoder *decoder,
  185. struct aws_byte_cursor *to_decode,
  186. struct aws_hpack_decode_result *result) {
  187. AWS_PRECONDITION(decoder);
  188. AWS_PRECONDITION(to_decode);
  189. AWS_PRECONDITION(result);
  190. /* Run state machine until we decode a complete entry.
  191. * Every state requires data, so we can simply loop until no more data available. */
  192. while (to_decode->len) {
  193. switch (decoder->progress_entry.state) {
  194. case HPACK_ENTRY_STATE_INIT: {
  195. /* Reset entry */
  196. AWS_ZERO_STRUCT(decoder->progress_entry.u);
  197. decoder->progress_entry.scratch.len = 0;
  198. /* Determine next state by looking at first few bits of the next byte:
  199. * 1xxxxxxx: Indexed Header Field Representation
  200. * 01xxxxxx: Literal Header Field with Incremental Indexing
  201. * 001xxxxx: Dynamic Table Size Update
  202. * 0001xxxx: Literal Header Field Never Indexed
  203. * 0000xxxx: Literal Header Field without Indexing */
  204. uint8_t first_byte = to_decode->ptr[0];
  205. if (first_byte & (1 << 7)) {
  206. /* 1xxxxxxx: Indexed Header Field Representation */
  207. decoder->progress_entry.state = HPACK_ENTRY_STATE_INDEXED;
  208. } else if (first_byte & (1 << 6)) {
  209. /* 01xxxxxx: Literal Header Field with Incremental Indexing */
  210. decoder->progress_entry.u.literal.compression = AWS_HTTP_HEADER_COMPRESSION_USE_CACHE;
  211. decoder->progress_entry.u.literal.prefix_size = 6;
  212. decoder->progress_entry.state = HPACK_ENTRY_STATE_LITERAL_BEGIN;
  213. } else if (first_byte & (1 << 5)) {
  214. /* 001xxxxx: Dynamic Table Size Update */
  215. decoder->progress_entry.state = HPACK_ENTRY_STATE_DYNAMIC_TABLE_RESIZE;
  216. } else if (first_byte & (1 << 4)) {
  217. /* 0001xxxx: Literal Header Field Never Indexed */
  218. decoder->progress_entry.u.literal.compression = AWS_HTTP_HEADER_COMPRESSION_NO_FORWARD_CACHE;
  219. decoder->progress_entry.u.literal.prefix_size = 4;
  220. decoder->progress_entry.state = HPACK_ENTRY_STATE_LITERAL_BEGIN;
  221. } else {
  222. /* 0000xxxx: Literal Header Field without Indexing */
  223. decoder->progress_entry.u.literal.compression = AWS_HTTP_HEADER_COMPRESSION_NO_CACHE;
  224. decoder->progress_entry.u.literal.prefix_size = 4;
  225. decoder->progress_entry.state = HPACK_ENTRY_STATE_LITERAL_BEGIN;
  226. }
  227. } break;
  228. /* RFC-7541 6.1. Indexed Header Field Representation.
  229. * Decode one integer, which is an index into the table.
  230. * Result is the header name and value stored there. */
  231. case HPACK_ENTRY_STATE_INDEXED: {
  232. bool complete = false;
  233. uint64_t *index = &decoder->progress_entry.u.indexed.index;
  234. if (aws_hpack_decode_integer(decoder, to_decode, 7, index, &complete)) {
  235. return AWS_OP_ERR;
  236. }
  237. if (!complete) {
  238. break;
  239. }
  240. const struct aws_http_header *header = s_get_header_u64(decoder, *index);
  241. if (!header) {
  242. return AWS_OP_ERR;
  243. }
  244. result->type = AWS_HPACK_DECODE_T_HEADER_FIELD;
  245. result->data.header_field = *header;
  246. goto handle_complete;
  247. } break;
  248. /* RFC-7541 6.2. Literal Header Field Representation.
  249. * We use multiple states to decode a literal...
  250. * The header-name MAY come from the table and MAY be encoded as a string.
  251. * The header-value is ALWAYS encoded as a string.
  252. *
  253. * This BEGIN state decodes one integer.
  254. * If it's non-zero, then it's the index in the table where we'll get the header-name from.
  255. * If it's zero, then we move to the HEADER_NAME state and decode header-name as a string instead */
  256. case HPACK_ENTRY_STATE_LITERAL_BEGIN: {
  257. struct hpack_progress_literal *literal = &decoder->progress_entry.u.literal;
  258. bool index_complete = false;
  259. if (aws_hpack_decode_integer(
  260. decoder, to_decode, literal->prefix_size, &literal->name_index, &index_complete)) {
  261. return AWS_OP_ERR;
  262. }
  263. if (!index_complete) {
  264. break;
  265. }
  266. if (literal->name_index == 0) {
  267. /* Index 0 means header-name is not in table. Need to decode header-name as a string instead */
  268. decoder->progress_entry.state = HPACK_ENTRY_STATE_LITERAL_NAME_STRING;
  269. break;
  270. }
  271. /* Otherwise we found index of header-name in table. */
  272. const struct aws_http_header *header = s_get_header_u64(decoder, literal->name_index);
  273. if (!header) {
  274. return AWS_OP_ERR;
  275. }
  276. /* Store the name in scratch. We don't just keep a pointer to it because it could be
  277. * evicted from the dynamic table later, when we save the literal. */
  278. if (aws_byte_buf_append_dynamic(&decoder->progress_entry.scratch, &header->name)) {
  279. return AWS_OP_ERR;
  280. }
  281. /* Move on to decoding header-value.
  282. * Value will also decode into the scratch, so save where name ends. */
  283. literal->name_length = header->name.len;
  284. decoder->progress_entry.state = HPACK_ENTRY_STATE_LITERAL_VALUE_STRING;
  285. } break;
  286. /* We only end up in this state if header-name is encoded as string. */
  287. case HPACK_ENTRY_STATE_LITERAL_NAME_STRING: {
  288. bool string_complete = false;
  289. if (aws_hpack_decode_string(decoder, to_decode, &decoder->progress_entry.scratch, &string_complete)) {
  290. return AWS_OP_ERR;
  291. }
  292. if (!string_complete) {
  293. break;
  294. }
  295. /* Done decoding name string! Move on to decoding the value string.
  296. * Value will also decode into the scratch, so save where name ends. */
  297. decoder->progress_entry.u.literal.name_length = decoder->progress_entry.scratch.len;
  298. decoder->progress_entry.state = HPACK_ENTRY_STATE_LITERAL_VALUE_STRING;
  299. } break;
  300. /* Final state for "literal" entries.
  301. * Decode the header-value string, then deliver the results. */
  302. case HPACK_ENTRY_STATE_LITERAL_VALUE_STRING: {
  303. bool string_complete = false;
  304. if (aws_hpack_decode_string(decoder, to_decode, &decoder->progress_entry.scratch, &string_complete)) {
  305. return AWS_OP_ERR;
  306. }
  307. if (!string_complete) {
  308. break;
  309. }
  310. /* Done decoding value string. Done decoding entry. */
  311. struct hpack_progress_literal *literal = &decoder->progress_entry.u.literal;
  312. /* Set up a header with name and value (which are packed one after the other in scratch) */
  313. struct aws_http_header header;
  314. header.value = aws_byte_cursor_from_buf(&decoder->progress_entry.scratch);
  315. header.name = aws_byte_cursor_advance(&header.value, literal->name_length);
  316. header.compression = literal->compression;
  317. /* Save to table if necessary */
  318. if (literal->compression == AWS_HTTP_HEADER_COMPRESSION_USE_CACHE) {
  319. if (aws_hpack_insert_header(&decoder->context, &header)) {
  320. return AWS_OP_ERR;
  321. }
  322. }
  323. result->type = AWS_HPACK_DECODE_T_HEADER_FIELD;
  324. result->data.header_field = header;
  325. goto handle_complete;
  326. } break;
  327. /* RFC-7541 6.3. Dynamic Table Size Update
  328. * Read one integer, which is the new maximum size for the dynamic table. */
  329. case HPACK_ENTRY_STATE_DYNAMIC_TABLE_RESIZE: {
  330. uint64_t *size64 = &decoder->progress_entry.u.dynamic_table_resize.size;
  331. bool size_complete = false;
  332. if (aws_hpack_decode_integer(decoder, to_decode, 5, size64, &size_complete)) {
  333. return AWS_OP_ERR;
  334. }
  335. if (!size_complete) {
  336. break;
  337. }
  338. /* The new maximum size MUST be lower than or equal to the limit determined by the protocol using HPACK.
  339. * A value that exceeds this limit MUST be treated as a decoding error. */
  340. if (*size64 > decoder->dynamic_table_protocol_max_size_setting) {
  341. HPACK_LOG(ERROR, decoder, "Dynamic table update size is larger than the protocal setting");
  342. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  343. }
  344. size_t size = (size_t)*size64;
  345. HPACK_LOGF(TRACE, decoder, "Dynamic table size update %zu", size);
  346. if (aws_hpack_resize_dynamic_table(&decoder->context, size)) {
  347. return AWS_OP_ERR;
  348. }
  349. result->type = AWS_HPACK_DECODE_T_DYNAMIC_TABLE_RESIZE;
  350. result->data.dynamic_table_resize = size;
  351. goto handle_complete;
  352. } break;
  353. default: {
  354. AWS_ASSERT(0 && "invalid state");
  355. } break;
  356. }
  357. }
  358. AWS_ASSERT(to_decode->len == 0);
  359. result->type = AWS_HPACK_DECODE_T_ONGOING;
  360. return AWS_OP_SUCCESS;
  361. handle_complete:
  362. AWS_ASSERT(result->type != AWS_HPACK_DECODE_T_ONGOING);
  363. decoder->progress_entry.state = HPACK_ENTRY_STATE_INIT;
  364. return AWS_OP_SUCCESS;
  365. }