1 #ifndef AWS_HTTP_H2_FRAMES_H
2 #define AWS_HTTP_H2_FRAMES_H
3 
4 /**
5  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
6  * SPDX-License-Identifier: Apache-2.0.
7  */
8 
9 #include <aws/http/connection.h>
10 #include <aws/http/request_response.h>
11 
12 #include <aws/common/byte_buf.h>
13 
14 /* Ids for each frame type (RFC-7540 6) */
15 enum aws_h2_frame_type {
16     AWS_H2_FRAME_T_DATA = 0x00,
17     AWS_H2_FRAME_T_HEADERS = 0x01,
18     AWS_H2_FRAME_T_PRIORITY = 0x02,
19     AWS_H2_FRAME_T_RST_STREAM = 0x03,
20     AWS_H2_FRAME_T_SETTINGS = 0x04,
21     AWS_H2_FRAME_T_PUSH_PROMISE = 0x05,
22     AWS_H2_FRAME_T_PING = 0x06,
23     AWS_H2_FRAME_T_GOAWAY = 0x07,
24     AWS_H2_FRAME_T_WINDOW_UPDATE = 0x08,
25     AWS_H2_FRAME_T_CONTINUATION = 0x09,
26     AWS_H2_FRAME_T_UNKNOWN,
27     AWS_H2_FRAME_TYPE_COUNT,
28 };
29 
30 /* Represents flags that may be set on a frame (RFC-7540 6) */
31 enum aws_h2_frame_flag {
32     AWS_H2_FRAME_F_ACK = 0x01,
33     AWS_H2_FRAME_F_END_STREAM = 0x01,
34     AWS_H2_FRAME_F_END_HEADERS = 0x04,
35     AWS_H2_FRAME_F_PADDED = 0x08,
36     AWS_H2_FRAME_F_PRIORITY = 0x20,
37 };
38 
39 /* Pairs the AWS_ERROR_* to show our API user,
40  * along with the AWS_HTTP2_ERR_* that should
41  * be sent to the peer via RST_STREAM or GOAWAY.
42  *
43  * Used in place of normal error handling in functions that may result
44  * in an HTTP/2 Connection Error or Stream Error.
45  */
46 struct aws_h2err {
47     enum aws_http2_error_code h2_code;
48     int aws_code;
49 };
50 
51 #define AWS_H2ERR_SUCCESS                                                                                              \
52     (struct aws_h2err) { .h2_code = 0, .aws_code = 0 }
53 
54 #define AWS_H2_PAYLOAD_MAX (0x00FFFFFF)       /* must fit in 3 bytes */
55 #define AWS_H2_WINDOW_UPDATE_MAX (0x7FFFFFFF) /* cannot use high bit */
56 #define AWS_H2_STREAM_ID_MAX (0x7FFFFFFF)     /* cannot use high bit */
57 #define AWS_H2_FRAME_PREFIX_SIZE (9)
58 
59 /* Legal min(inclusive) and max(inclusive) for each setting */
60 extern const uint32_t aws_h2_settings_bounds[AWS_HTTP2_SETTINGS_END_RANGE][2];
61 
62 /* Initial values for settings RFC-7540 6.5.2 */
63 AWS_HTTP_API
64 extern const uint32_t aws_h2_settings_initial[AWS_HTTP2_SETTINGS_END_RANGE];
65 
66 /* This magic string must be the very first thing a client sends to the server.
67  * See RFC-7540 3.5 - HTTP/2 Connection Preface.
68  * Exported for tests */
69 AWS_HTTP_API
70 extern const struct aws_byte_cursor aws_h2_connection_preface_client_string;
71 
72 /**
73  * Present in all frames that may have set AWS_H2_FRAME_F_PRIORITY
74  *
75  * Encoded as:
76  * +-+-------------------------------------------------------------+
77  * |E|                  Stream Dependency (31)                     |
78  * +-+-------------+-----------------------------------------------+
79  * |   Weight (8)  |
80  * +-+-------------+
81  */
82 struct aws_h2_frame_priority_settings {
83     uint32_t stream_dependency;
84     bool stream_dependency_exclusive;
85     uint8_t weight;
86 };
87 
88 /**
89  * A frame to be encoded.
90  * (in the case of HEADERS and PUSH_PROMISE, it might turn into multiple frames due to CONTINUATION)
91  */
92 struct aws_h2_frame {
93     const struct aws_h2_frame_vtable *vtable;
94     struct aws_allocator *alloc;
95     struct aws_linked_list_node node;
96     enum aws_h2_frame_type type;
97     uint32_t stream_id;
98 
99     /* If true, frame will be sent before those with normal priority.
100      * Useful for frames like PING ACK where low latency is important. */
101     bool high_priority;
102 };
103 
104 /* Used to encode a frame */
105 struct aws_h2_frame_encoder {
106     struct aws_allocator *allocator;
107     const void *logging_id;
108     struct aws_hpack_context *hpack;
109     struct aws_h2_frame *current_frame;
110 
111     /* Settings for frame encoder, which is based on the settings received from peer */
112     struct {
113         /*  the size of the largest frame payload */
114         uint32_t max_frame_size;
115     } settings;
116 
117     bool has_errored;
118 };
119 
120 typedef void aws_h2_frame_destroy_fn(struct aws_h2_frame *frame_base);
121 typedef int aws_h2_frame_encode_fn(
122     struct aws_h2_frame *frame_base,
123     struct aws_h2_frame_encoder *encoder,
124     struct aws_byte_buf *output,
125     bool *complete);
126 
127 struct aws_h2_frame_vtable {
128     aws_h2_frame_destroy_fn *destroy;
129     aws_h2_frame_encode_fn *encode;
130 };
131 
132 AWS_EXTERN_C_BEGIN
133 
134 AWS_HTTP_API
135 const char *aws_h2_frame_type_to_str(enum aws_h2_frame_type type);
136 
137 AWS_HTTP_API
138 const char *aws_http2_error_code_to_str(enum aws_http2_error_code h2_error_code);
139 
140 /**
141  * Specify which HTTP/2 error-code will be sent to the peer in a GOAWAY or RST_STREAM frame.
142  *
143  * The AWS_ERROR reported to the API user will be AWS_ERROR_HTTP_PROTOCOL_ERROR.
144  */
145 AWS_HTTP_API
146 struct aws_h2err aws_h2err_from_h2_code(enum aws_http2_error_code h2_error_code);
147 
148 /**
149  * Specify which AWS_ERROR will be reported to the API user.
150  *
151  * The peer will be sent a GOAWAY or RST_STREAM with the INTERNAL_ERROR HTTP/2 error-code.
152  */
153 AWS_HTTP_API
154 struct aws_h2err aws_h2err_from_aws_code(int aws_error_code);
155 
156 AWS_HTTP_API
157 struct aws_h2err aws_h2err_from_last_error(void);
158 
159 AWS_HTTP_API
160 bool aws_h2err_success(struct aws_h2err err);
161 
162 AWS_HTTP_API
163 bool aws_h2err_failed(struct aws_h2err err);
164 
165 /* Raises AWS_ERROR_INVALID_ARGUMENT if stream_id is 0 or exceeds AWS_H2_MAX_STREAM_ID */
166 AWS_HTTP_API
167 int aws_h2_validate_stream_id(uint32_t stream_id);
168 
169 /**
170  * The process of encoding a frame looks like:
171  * 1. Create a encoder object on the stack and initialize with aws_h2_frame_encoder_init
172  * 2. Encode the frame using aws_h2_encode_frame()
173  */
174 AWS_HTTP_API
175 int aws_h2_frame_encoder_init(
176     struct aws_h2_frame_encoder *encoder,
177     struct aws_allocator *allocator,
178     const void *logging_id);
179 
180 AWS_HTTP_API
181 void aws_h2_frame_encoder_clean_up(struct aws_h2_frame_encoder *encoder);
182 
183 /**
184  * Attempt to encode frame into output buffer.
185  * AWS_OP_ERR is returned if encoder encounters an unrecoverable error.
186  * frame_complete will be set true if the frame finished encoding.
187  *
188  * If frame_complete is false then we MUST call aws_h2_encode_frame() again
189  * with all the same inputs, when we have a fresh buffer (it would be illegal
190  * to encode a different frame).
191  */
192 AWS_HTTP_API
193 int aws_h2_encode_frame(
194     struct aws_h2_frame_encoder *encoder,
195     struct aws_h2_frame *frame,
196     struct aws_byte_buf *output,
197     bool *frame_complete);
198 
199 /**
200  * Attempt to encode a DATA frame into the output buffer.
201  * The body_stream will be read into the available space (up to MAX_FRAME_SIZE).
202  * AWS_OP_ERR is returned if encoder encounters an unrecoverable error.
203  * body_complete will be set true if encoder reaches the end of the body_stream.
204  * body_stalled will be true if aws_input_stream_read() stopped early (didn't
205  * complete, though more space was available).
206  *
207  * Each call to this function encodes a complete DATA frame, or nothing at all,
208  * so it's always safe to encode a different frame type or the body of a different stream
209  * after calling this.
210  */
211 AWS_HTTP_API
212 int aws_h2_encode_data_frame(
213     struct aws_h2_frame_encoder *encoder,
214     uint32_t stream_id,
215     struct aws_input_stream *body_stream,
216     bool body_ends_stream,
217     uint8_t pad_length,
218     int32_t *stream_window_size_peer,
219     size_t *connection_window_size_peer,
220     struct aws_byte_buf *output,
221     bool *body_complete,
222     bool *body_stalled);
223 
224 AWS_HTTP_API
225 void aws_h2_frame_destroy(struct aws_h2_frame *frame);
226 
227 /**
228  * This frame type may actually end up encoding multiple frames
229  * (HEADERS followed by 0 or more CONTINUATION frames).
230  */
231 AWS_HTTP_API
232 struct aws_h2_frame *aws_h2_frame_new_headers(
233     struct aws_allocator *allocator,
234     uint32_t stream_id,
235     const struct aws_http_headers *headers,
236     bool end_stream,
237     uint8_t pad_length,
238     const struct aws_h2_frame_priority_settings *optional_priority);
239 
240 AWS_HTTP_API
241 struct aws_h2_frame *aws_h2_frame_new_priority(
242     struct aws_allocator *allocator,
243     uint32_t stream_id,
244     const struct aws_h2_frame_priority_settings *priority);
245 
246 AWS_HTTP_API
247 struct aws_h2_frame *aws_h2_frame_new_rst_stream(
248     struct aws_allocator *allocator,
249     uint32_t stream_id,
250     uint32_t error_code);
251 
252 AWS_HTTP_API
253 struct aws_h2_frame *aws_h2_frame_new_settings(
254     struct aws_allocator *allocator,
255     const struct aws_http2_setting *settings_array,
256     size_t num_settings,
257     bool ack);
258 
259 /**
260  * This frame type may actually end up encoding multiple frames
261  * (PUSH_PROMISE followed 0 or more CONTINUATION frames).
262  */
263 AWS_HTTP_API
264 struct aws_h2_frame *aws_h2_frame_new_push_promise(
265     struct aws_allocator *allocator,
266     uint32_t stream_id,
267     uint32_t promised_stream_id,
268     const struct aws_http_headers *headers,
269     uint8_t pad_length);
270 
271 AWS_HTTP_API
272 struct aws_h2_frame *aws_h2_frame_new_ping(
273     struct aws_allocator *allocator,
274     bool ack,
275     const uint8_t opaque_data[AWS_HTTP2_PING_DATA_SIZE]);
276 
277 AWS_HTTP_API
278 struct aws_h2_frame *aws_h2_frame_new_goaway(
279     struct aws_allocator *allocator,
280     uint32_t last_stream_id,
281     uint32_t error_code,
282     struct aws_byte_cursor debug_data);
283 
284 AWS_HTTP_API
285 struct aws_h2_frame *aws_h2_frame_new_window_update(
286     struct aws_allocator *allocator,
287     uint32_t stream_id,
288     uint32_t window_size_increment);
289 
290 AWS_HTTP_API void aws_h2_frame_encoder_set_setting_header_table_size(
291     struct aws_h2_frame_encoder *encoder,
292     uint32_t data);
293 AWS_HTTP_API void aws_h2_frame_encoder_set_setting_max_frame_size(struct aws_h2_frame_encoder *encoder, uint32_t data);
294 
295 AWS_EXTERN_C_END
296 
297 #endif /* AWS_HTTP_H2_FRAMES_H */
298