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