Skip to content

Commit 4ac13c3

Browse files
committed
Revamp HEADERS/PUSH_PROMISE/DATA frames
1 parent d65ed7b commit 4ac13c3

File tree

5 files changed

+543
-430
lines changed

5 files changed

+543
-430
lines changed

include/aws/http/private/h2_frames.h

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
* permissions and limitations under the License.
1717
*/
1818

19-
#include <aws/http/request_response.h>
2019
#include <aws/http/private/hpack.h>
20+
#include <aws/http/request_response.h>
2121

2222
#include <aws/common/byte_buf.h>
2323

@@ -79,6 +79,7 @@ enum aws_h2_settings {
7979
#define AWS_H2_PAYLOAD_MAX (0x00FFFFFF)
8080

8181
#define AWS_H2_WINDOW_UPDATE_MAX (0x7FFFFFFF)
82+
#define AWS_H2_STREAM_ID_MAX (0x7FFFFFFF)
8283

8384
/* This magic string must be the very first thing a client sends to the server.
8485
* See RFC-7540 3.5 - HTTP/2 Connection Preface */
@@ -101,8 +102,20 @@ struct aws_h2_frame_priority_settings {
101102
};
102103

103104
struct aws_h2_frame_header_block {
104-
/* array_list of aws_http_header */
105-
struct aws_array_list header_fields;
105+
const struct aws_http_headers *headers;
106+
107+
/* state */
108+
109+
enum {
110+
AWS_H2_HEADER_BLOCK_STATE_INIT,
111+
AWS_H2_HEADER_BLOCK_STATE_FIRST_FRAME,
112+
AWS_H2_HEADER_BLOCK_STATE_CONTINUATION,
113+
AWS_H2_HEADER_BLOCK_STATE_COMPLETE,
114+
AWS_H2_HEADER_BLOCK_STATE_ERROR,
115+
} state;
116+
117+
struct aws_byte_buf whole_encoded_block; /* entire header block is encoded here */
118+
struct aws_byte_cursor encoded_block_cursor; /* tracks progress sending encoded header-block in fragments */
106119
};
107120

108121
/**
@@ -117,13 +130,13 @@ struct aws_h2_frame {
117130
struct aws_linked_list_node node;
118131
};
119132

120-
/* Represents a HEADERS frame */
133+
/* Represents a HEADERS header-block.
134+
* (HEADERS frame followed 0 or more CONTINUATION frames) */
121135
struct aws_h2_frame_headers {
122136
struct aws_h2_frame base;
123137

124138
/* Flags */
125139
bool end_stream; /* AWS_H2_FRAME_F_END_STREAM */
126-
bool end_headers; /* AWS_H2_FRAME_F_END_HEADERS */
127140
bool has_priority; /* AWS_H2_FRAME_F_PRIORITY */
128141

129142
/* Payload */
@@ -166,13 +179,11 @@ struct aws_h2_frame_settings {
166179
size_t settings_count;
167180
};
168181

169-
/* Represents a PUSH_PROMISE frame */
182+
/* Represents a PUSH_PROMISE header-block.
183+
* (PUSH_PROMISE frame followed by 0 or more CONTINUATION frames) */
170184
struct aws_h2_frame_push_promise {
171185
struct aws_h2_frame base;
172186

173-
/* Flags */
174-
bool end_headers; /* AWS_H2_FRAME_F_END_HEADERS */
175-
176187
/* Payload */
177188
uint8_t pad_length; /* Set to 0 to disable AWS_H2_FRAME_F_PADDED */
178189
uint32_t promised_stream_id;
@@ -237,6 +248,10 @@ AWS_EXTERN_C_BEGIN
237248
AWS_HTTP_API
238249
const char *aws_h2_frame_type_to_str(enum aws_h2_frame_type type);
239250

251+
/* Raises AWS_ERROR_INVALID_ARGUMENT if stream_id is 0 or exceeds AWS_H2_MAX_STREAM_ID */
252+
AWS_HTTP_API
253+
int aws_h2_validate_stream_id(uint32_t stream_id);
254+
240255
/**
241256
* The process of encoding a frame looks like:
242257
* 1. Create a encoder object on the stack and initialize with aws_h2_frame_encoder_init
@@ -277,8 +292,8 @@ int aws_h2_encode_data_frame(
277292
struct aws_h2_frame_encoder *encoder,
278293
uint32_t stream_id,
279294
struct aws_input_stream *body_stream,
280-
bool end_stream,
281-
uint8_t padding,
295+
bool body_ends_stream,
296+
uint8_t pad_length,
282297
struct aws_byte_buf *output,
283298
bool *body_complete);
284299

@@ -295,7 +310,7 @@ struct aws_h2_frame *aws_h2_frame_new_headers(
295310
uint32_t stream_id,
296311
const struct aws_http_headers *headers,
297312
bool end_stream,
298-
uint8_t padding,
313+
uint8_t pad_length,
299314
const struct aws_h2_frame_priority_settings *optional_priority);
300315

301316
AWS_HTTP_API
@@ -327,7 +342,7 @@ struct aws_h2_frame *aws_h2_frame_new_push_promise(
327342
uint32_t stream_id,
328343
uint32_t promised_stream_id,
329344
const struct aws_http_headers *headers,
330-
uint8_t padding);
345+
uint8_t pad_length);
331346

332347
AWS_HTTP_API
333348
struct aws_h2_frame *aws_h2_frame_new_ping(

include/aws/http/private/hpack.h

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* express or implied. See the License for the specific language governing
1616
* permissions and limitations under the License.
1717
*/
18-
#include <aws/http/private/h2_frames.h>
18+
#include <aws/http/request_response.h>
1919

2020
struct aws_byte_buf;
2121
struct aws_byte_cursor;
@@ -90,25 +90,24 @@ int aws_hpack_decode(
9090
struct aws_hpack_decode_result *result);
9191

9292
/**
93-
* Encode a header-field into the output.
94-
* This function will mutate the hpack context, so any error is unrecoverable.
93+
* Must be called at start of header-block.
94+
* If the table has been resized, then a Dynamic Table Size Update (RFC-7541 6.3) is encoded.
95+
* This behavior is described in RFC-7541 4.2.
9596
* Note that output will be dynamically resized if it's too short.
9697
*/
9798
AWS_HTTP_API
98-
int aws_hpack_encode_header(
99-
struct aws_hpack_context *context,
100-
const struct aws_http_header *header,
101-
enum aws_hpack_huffman_mode huffman_mode,
102-
struct aws_byte_buf *output);
99+
int aws_hpack_encode_header_block_start(struct aws_hpack_context *context, struct aws_byte_buf *output);
103100

104101
/**
105-
* Encode a Dynamic Table Size Update (RFC-7541 6.3) into the output.
102+
* Encode a header-field into the output.
103+
* This function will mutate the hpack context, so any error is unrecoverable.
106104
* Note that output will be dynamically resized if it's too short.
107105
*/
108106
AWS_HTTP_API
109-
int aws_hpack_encode_dynamic_table_resize(
107+
int aws_hpack_encode_header(
110108
struct aws_hpack_context *context,
111-
size_t size,
109+
const struct aws_http_header *header,
110+
enum aws_hpack_huffman_mode huffman_mode,
112111
struct aws_byte_buf *output);
113112

114113
/* Returns the hpack size of a header (name.len + value.len + 32) [4.1] */

source/h2_connection.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ static void s_outgoing_frames_task(struct aws_channel_task *task, void *arg, enu
430430
* - Stream is complete if it is also done receiving (weird edge case, but theoretically possible)
431431
* Else stream has not sent all data:
432432
* - Move stream to back of outgoing_streams_list ("round-robin" DATA frames from available streams)
433+
* - Beware getting into a loop, don't read from the same stream twice
433434
*/
434435
CONNECTION_LOG(ERROR, connection, "DATA frames not supported yet");
435436
aws_raise_error(AWS_ERROR_UNIMPLEMENTED);

0 commit comments

Comments
 (0)