Skip to content

Commit 5e33ddf

Browse files
authored
Remove whole-frame h2 decoder (#179)
We use the streaming decoder now. Most changes are rewriting tests that assumed the encoder/decoder were mirrors of each other. **REMOVE** - `aws_h2_frame_decoder_***()` functions - `fuzz_h2_frames.c` which just tested the old decoder. **ALTER** - Rewrite encoder tests (delete `test_h2_frames.c`, add `test_h2_encoder.c`). Old tests relied on whole-frame decoder. - Alter `test_h2_headers.c` to use new streaming decoder. - Add `aws_h2_encode_frame()` function that accepts all frames types, instead of needing to call the appropriate aws_h2_frame_XYZ_encode() function per frame type. **FIX** - Fix encoder bug with padding in DATA frame. - Fix decoder bug where header-value-string overwrote header-name-string.
1 parent 4abad0d commit 5e33ddf

13 files changed

+650
-1986
lines changed

include/aws/http/private/h2_connection.h

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include <aws/common/atomics.h>
20+
#include <aws/common/hash_table.h>
2021
#include <aws/common/mutex.h>
2122

2223
#include <aws/http/private/connection_impl.h>

include/aws/http/private/h2_frames.h

+17-59
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include <aws/http/request_response.h>
2020

2121
#include <aws/common/byte_buf.h>
22-
#include <aws/common/hash_table.h>
2322

2423
/* Ids for each frame type (RFC-7540 6) */
2524
enum aws_h2_frame_type {
@@ -159,6 +158,12 @@ struct aws_h2_frame_rst_stream {
159158
enum aws_h2_error_codes error_code;
160159
};
161160

161+
/* A h2 setting and its value, used in SETTINGS frame */
162+
struct aws_h2_frame_setting {
163+
uint16_t id; /* aws_h2_settings */
164+
uint32_t value;
165+
};
166+
162167
/* Represents a SETTINGS frame */
163168
struct aws_h2_frame_settings {
164169
/* Header */
@@ -168,8 +173,8 @@ struct aws_h2_frame_settings {
168173
bool ack; /* AWS_H2_FRAME_F_ACK */
169174

170175
/* Payload */
171-
/* uint16_t -> uint32_t */
172-
struct aws_hash_table settings;
176+
struct aws_h2_frame_setting *settings_array;
177+
size_t settings_count;
173178
};
174179

175180
/* Represents a PUSH_PROMISE frame */
@@ -186,6 +191,8 @@ struct aws_h2_frame_push_promise {
186191
struct aws_h2_frame_header_block header_block;
187192
};
188193

194+
#define AWS_H2_PING_DATA_SIZE (8)
195+
189196
/* Represents a PING frame */
190197
struct aws_h2_frame_ping {
191198
/* Header */
@@ -195,7 +202,7 @@ struct aws_h2_frame_ping {
195202
bool ack; /* AWS_H2_FRAME_F_ACK */
196203

197204
/* Payload */
198-
struct aws_byte_cursor opaque_data;
205+
uint8_t opaque_data[AWS_H2_PING_DATA_SIZE];
199206
};
200207

201208
/* Represents a GOAWAY frame */
@@ -238,19 +245,6 @@ struct aws_h2_frame_encoder {
238245
bool use_huffman;
239246
};
240247

241-
/* Used to decode a frame */
242-
struct aws_h2_frame_decoder {
243-
/* Larger state */
244-
struct aws_allocator *allocator;
245-
struct aws_byte_buf header_scratch;
246-
struct aws_hpack_context *hpack;
247-
248-
/* Packet-in-progress */
249-
struct aws_h2_frame_header header;
250-
uint8_t flags;
251-
struct aws_byte_cursor payload;
252-
};
253-
254248
AWS_EXTERN_C_BEGIN
255249

256250
AWS_HTTP_API
@@ -271,48 +265,34 @@ int aws_h2_frame_header_block_encode(
271265
const struct aws_h2_frame_header_block *header_block,
272266
struct aws_h2_frame_encoder *encoder,
273267
struct aws_byte_buf *output);
274-
AWS_HTTP_API
275-
int aws_h2_frame_header_block_decode(
276-
struct aws_h2_frame_header_block *header_block,
277-
struct aws_h2_frame_decoder *decoder);
278268

279269
/**
280270
* The process of encoding a frame looks like:
281271
* 1. Create a encoder object on the stack and initialize with aws_h2_frame_encoder_init
282272
* 2. Encode the header using aws_h2_frame_*_encode
283273
*/
284-
285274
AWS_HTTP_API
286275
int aws_h2_frame_encoder_init(struct aws_h2_frame_encoder *encoder, struct aws_allocator *allocator);
287276
AWS_HTTP_API
288277
void aws_h2_frame_encoder_clean_up(struct aws_h2_frame_encoder *encoder);
289278

290-
/**
291-
* The process of decoding a frame looks like:
292-
* 1. Create a decoder object on the stack and initialize with aws_h2_frame_decoder_init
293-
* 2. Decode the header using aws_h2_frame_decoder_begin
294-
* 3. Switch on header->type, and create a new instance of the appropriate frame type
295-
* 4. Call aws_h2_frame_*_decode to decode the rest of the frame
296-
*/
297-
298-
AWS_HTTP_API
299-
int aws_h2_frame_decoder_init(struct aws_h2_frame_decoder *decoder, struct aws_allocator *allocator);
279+
/* #TODO: remove each frame type's specific encode() function from API */
300280
AWS_HTTP_API
301-
void aws_h2_frame_decoder_clean_up(struct aws_h2_frame_decoder *decoder);
302-
AWS_HTTP_API
303-
int aws_h2_frame_decoder_begin(struct aws_h2_frame_decoder *decoder, struct aws_byte_cursor *data);
281+
int aws_h2_encode_frame(
282+
struct aws_h2_frame_encoder *encoder,
283+
struct aws_h2_frame_header *frame_header,
284+
struct aws_byte_buf *output);
304285

305286
AWS_HTTP_API
306287
int aws_h2_frame_data_init(struct aws_h2_frame_data *frame, struct aws_allocator *allocator);
307288
AWS_HTTP_API
308289
void aws_h2_frame_data_clean_up(struct aws_h2_frame_data *frame);
290+
309291
AWS_HTTP_API
310292
int aws_h2_frame_data_encode(
311293
struct aws_h2_frame_data *frame,
312294
struct aws_h2_frame_encoder *encoder,
313295
struct aws_byte_buf *output);
314-
AWS_HTTP_API
315-
int aws_h2_frame_data_decode(struct aws_h2_frame_data *frame, struct aws_h2_frame_decoder *decoder);
316296

317297
AWS_HTTP_API
318298
int aws_h2_frame_headers_init(struct aws_h2_frame_headers *frame, struct aws_allocator *allocator);
@@ -323,8 +303,6 @@ int aws_h2_frame_headers_encode(
323303
struct aws_h2_frame_headers *frame,
324304
struct aws_h2_frame_encoder *encoder,
325305
struct aws_byte_buf *output);
326-
AWS_HTTP_API
327-
int aws_h2_frame_headers_decode(struct aws_h2_frame_headers *frame, struct aws_h2_frame_decoder *decoder);
328306

329307
AWS_HTTP_API
330308
int aws_h2_frame_priority_init(struct aws_h2_frame_priority *frame, struct aws_allocator *allocator);
@@ -335,8 +313,6 @@ int aws_h2_frame_priority_encode(
335313
struct aws_h2_frame_priority *frame,
336314
struct aws_h2_frame_encoder *encoder,
337315
struct aws_byte_buf *output);
338-
AWS_HTTP_API
339-
int aws_h2_frame_priority_decode(struct aws_h2_frame_priority *frame, struct aws_h2_frame_decoder *decoder);
340316

341317
AWS_HTTP_API
342318
int aws_h2_frame_rst_stream_init(struct aws_h2_frame_rst_stream *frame, struct aws_allocator *allocator);
@@ -347,24 +323,16 @@ int aws_h2_frame_rst_stream_encode(
347323
struct aws_h2_frame_rst_stream *frame,
348324
struct aws_h2_frame_encoder *encoder,
349325
struct aws_byte_buf *output);
350-
AWS_HTTP_API
351-
int aws_h2_frame_rst_stream_decode(struct aws_h2_frame_rst_stream *frame, struct aws_h2_frame_decoder *decoder);
352326

353327
AWS_HTTP_API
354328
int aws_h2_frame_settings_init(struct aws_h2_frame_settings *frame, struct aws_allocator *allocator);
355329
AWS_HTTP_API
356330
void aws_h2_frame_settings_clean_up(struct aws_h2_frame_settings *frame);
357331
AWS_HTTP_API
358-
int aws_h2_frame_settings_set(struct aws_h2_frame_settings *frame, uint16_t identifier, uint32_t value);
359-
AWS_HTTP_API
360-
int aws_h2_frame_settings_remove(struct aws_h2_frame_settings *frame, uint16_t identifier);
361-
AWS_HTTP_API
362332
int aws_h2_frame_settings_encode(
363333
struct aws_h2_frame_settings *frame,
364334
struct aws_h2_frame_encoder *encoder,
365335
struct aws_byte_buf *output);
366-
AWS_HTTP_API
367-
int aws_h2_frame_settings_decode(struct aws_h2_frame_settings *frame, struct aws_h2_frame_decoder *decoder);
368336

369337
AWS_HTTP_API
370338
int aws_h2_frame_push_promise_init(struct aws_h2_frame_push_promise *frame, struct aws_allocator *allocator);
@@ -375,8 +343,6 @@ int aws_h2_frame_push_promise_encode(
375343
struct aws_h2_frame_push_promise *frame,
376344
struct aws_h2_frame_encoder *encoder,
377345
struct aws_byte_buf *output);
378-
AWS_HTTP_API
379-
int aws_h2_frame_push_promise_decode(struct aws_h2_frame_push_promise *frame, struct aws_h2_frame_decoder *decoder);
380346

381347
AWS_HTTP_API
382348
int aws_h2_frame_ping_init(struct aws_h2_frame_ping *frame, struct aws_allocator *allocator);
@@ -387,8 +353,6 @@ int aws_h2_frame_ping_encode(
387353
struct aws_h2_frame_ping *frame,
388354
struct aws_h2_frame_encoder *encoder,
389355
struct aws_byte_buf *output);
390-
AWS_HTTP_API
391-
int aws_h2_frame_ping_decode(struct aws_h2_frame_ping *frame, struct aws_h2_frame_decoder *decoder);
392356

393357
AWS_HTTP_API
394358
int aws_h2_frame_goaway_init(struct aws_h2_frame_goaway *frame, struct aws_allocator *allocator);
@@ -399,8 +363,6 @@ int aws_h2_frame_goaway_encode(
399363
struct aws_h2_frame_goaway *frame,
400364
struct aws_h2_frame_encoder *encoder,
401365
struct aws_byte_buf *output);
402-
AWS_HTTP_API
403-
int aws_h2_frame_goaway_decode(struct aws_h2_frame_goaway *frame, struct aws_h2_frame_decoder *decoder);
404366

405367
AWS_HTTP_API
406368
int aws_h2_frame_window_update_init(struct aws_h2_frame_window_update *frame, struct aws_allocator *allocator);
@@ -411,8 +373,6 @@ int aws_h2_frame_window_update_encode(
411373
struct aws_h2_frame_window_update *frame,
412374
struct aws_h2_frame_encoder *encoder,
413375
struct aws_byte_buf *output);
414-
AWS_HTTP_API
415-
int aws_h2_frame_window_update_decode(struct aws_h2_frame_window_update *frame, struct aws_h2_frame_decoder *decoder);
416376

417377
AWS_HTTP_API
418378
int aws_h2_frame_continuation_init(struct aws_h2_frame_continuation *frame, struct aws_allocator *allocator);
@@ -423,8 +383,6 @@ int aws_h2_frame_continuation_encode(
423383
struct aws_h2_frame_continuation *frame,
424384
struct aws_h2_frame_encoder *encoder,
425385
struct aws_byte_buf *output);
426-
AWS_HTTP_API
427-
int aws_h2_frame_continuation_decode(struct aws_h2_frame_continuation *frame, struct aws_h2_frame_decoder *decoder);
428386

429387
AWS_EXTERN_C_END
430388

include/aws/http/private/h2_stream.h

-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ struct aws_h2_stream *aws_h2_stream_new_request(
7878
struct aws_http_connection *client_connection,
7979
const struct aws_http_make_request_options *options);
8080

81-
AWS_HTTP_API
82-
int aws_h2_stream_handle_frame(struct aws_h2_stream *stream, struct aws_h2_frame_decoder *decoder);
83-
8481
AWS_EXTERN_C_END
8582

8683
#endif /* AWS_HTTP_H2_STREAM_H */

source/h2_decoder.c

+27-16
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,16 @@ static enum aws_hpack_decode_status s_decode_string(
368368
* State functions
369369
**********************************************************************************************************************/
370370

371-
static void s_decoder_run_state(
371+
static void s_decoder_run_state_ex(
372372
struct aws_h2_decoder *decoder,
373373
const struct decoder_state *state,
374-
struct aws_byte_cursor *input) {
374+
struct aws_byte_cursor *input,
375+
bool preserve_scratch) {
375376

376377
DECODER_LOGF(TRACE, decoder, "Moving from state %s to %s", decoder->state.name, state->name);
377-
decoder->scratch.len = 0;
378+
if (!preserve_scratch) {
379+
decoder->scratch.len = 0;
380+
}
378381

379382
/* Special case for 0 length frames, otherwise frames could sit in incomplete until more data arrives */
380383
if (state->bytes_required == 0) {
@@ -384,6 +387,21 @@ static void s_decoder_run_state(
384387
}
385388
}
386389

390+
static void s_decoder_run_state(
391+
struct aws_h2_decoder *decoder,
392+
const struct decoder_state *state,
393+
struct aws_byte_cursor *input) {
394+
395+
s_decoder_run_state_ex(decoder, state, input, false /*preserve_scratch*/);
396+
}
397+
static void s_decoder_run_state_preserve_scratch(
398+
struct aws_h2_decoder *decoder,
399+
const struct decoder_state *state,
400+
struct aws_byte_cursor *input) {
401+
402+
s_decoder_run_state_ex(decoder, state, input, true /*preserve_scratch*/);
403+
}
404+
387405
static void s_decoder_run_frame_state(struct aws_h2_decoder *decoder, struct aws_byte_cursor *input) {
388406
AWS_ASSERT(decoder->frame_in_progress.type <= AWS_H2_FRAME_T_UNKNOWN);
389407
s_decoder_run_state(decoder, s_state_frames[decoder->frame_in_progress.type], input);
@@ -431,19 +449,12 @@ static int s_state_fn_header(struct aws_h2_decoder *decoder, struct aws_byte_cur
431449

432450
AWS_ASSERT(input->len >= 9);
433451

434-
uint32_t payload_len = 0;
435-
uint8_t *length_ptr = ((uint8_t *)&payload_len);
436-
437452
/* Read the first 3 bytes */
438-
bool succ = aws_byte_cursor_read(input, length_ptr, 3);
453+
uint32_t payload_len = 0;
454+
bool succ = aws_byte_cursor_read_be24(input, &payload_len);
439455
AWS_ASSERT(succ);
440456
(void)succ;
441457

442-
/* Reverse from network order */
443-
payload_len = aws_ntoh24(payload_len);
444-
/* Assert top byte isn't set */
445-
AWS_ASSERT((payload_len & 0xFF000000) == 0);
446-
447458
/* #TODO handle the SETTINGS_MAX_FRAME_SIZE setting */
448459
static const uint32_t MAX_FRAME_SIZE = 16384;
449460
if (payload_len > MAX_FRAME_SIZE) {
@@ -831,8 +842,8 @@ static int s_state_fn_frame_ping(struct aws_h2_decoder *decoder, struct aws_byte
831842

832843
AWS_ASSERT(input->len >= 8);
833844

834-
uint8_t opaque_data[8] = {0};
835-
bool succ = aws_byte_cursor_read(input, &opaque_data, AWS_ARRAY_SIZE(opaque_data));
845+
uint8_t opaque_data[AWS_H2_PING_DATA_SIZE] = {0};
846+
bool succ = aws_byte_cursor_read(input, &opaque_data, AWS_H2_PING_DATA_SIZE);
836847
AWS_ASSERT(succ);
837848
(void)succ;
838849

@@ -1139,8 +1150,8 @@ static int s_state_fn_headers_literal_name(struct aws_h2_decoder *decoder, struc
11391150
/* The value will start after the name, so save how long it is */
11401151
progress->value_offset = decoder->scratch.len;
11411152

1142-
/* Name gotten, go to value */
1143-
s_decoder_run_state(decoder, &s_state_headers_literal_value, input);
1153+
/* Name is in scratch, preserve it and go to value */
1154+
s_decoder_run_state_preserve_scratch(decoder, &s_state_headers_literal_value, input);
11441155

11451156
return AWS_OP_SUCCESS;
11461157
}

0 commit comments

Comments
 (0)