1 /*
2 * Copyright (c) 2018 Fastly Inc, Ichito Nagata
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #ifndef h2o__http2_common_h
23 #define h2o__http2_common_h
24
25 #include "h2o/string_.h"
26 #include "h2o/header.h"
27 #include "h2o/url.h"
28 #include "h2o/memory.h"
29 #include "h2o/cache_digests.h"
30
31 #define H2O_HTTP2_SETTINGS_HEADER_TABLE_SIZE 1
32 #define H2O_HTTP2_SETTINGS_ENABLE_PUSH 2
33 #define H2O_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS 3
34 #define H2O_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE 4
35 #define H2O_HTTP2_SETTINGS_MAX_FRAME_SIZE 5
36 #define H2O_HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE 6
37
38 /* defined as negated form of the error codes defined in HTTP2-spec section 7 */
39 #define H2O_HTTP2_ERROR_NONE 0
40 #define H2O_HTTP2_ERROR_PROTOCOL -1
41 #define H2O_HTTP2_ERROR_INTERNAL -2
42 #define H2O_HTTP2_ERROR_FLOW_CONTROL -3
43 #define H2O_HTTP2_ERROR_SETTINGS_TIMEOUT -4
44 #define H2O_HTTP2_ERROR_STREAM_CLOSED -5
45 #define H2O_HTTP2_ERROR_FRAME_SIZE -6
46 #define H2O_HTTP2_ERROR_REFUSED_STREAM -7
47 #define H2O_HTTP2_ERROR_CANCEL -8
48 #define H2O_HTTP2_ERROR_COMPRESSION -9
49 #define H2O_HTTP2_ERROR_CONNECT -10
50 #define H2O_HTTP2_ERROR_ENHANCE_YOUR_CALM -11
51 #define H2O_HTTP2_ERROR_INADEQUATE_SECURITY -12
52 #define H2O_HTTP2_ERROR_MAX 13
53 /* end of the HTTP2-spec defined errors */
54 #define H2O_HTTP2_ERROR_INVALID_HEADER_CHAR \
55 -254 /* an internal value indicating that invalid characters were found in the header name or value */
56 #define H2O_HTTP2_ERROR_INCOMPLETE -255 /* an internal value indicating that all data is not ready */
57 #define H2O_HTTP2_ERROR_PROTOCOL_CLOSE_IMMEDIATELY -256
58
59 typedef struct st_h2o_http2_settings_t {
60 uint32_t header_table_size;
61 uint32_t enable_push;
62 uint32_t max_concurrent_streams;
63 uint32_t initial_window_size;
64 uint32_t max_frame_size;
65 } h2o_http2_settings_t;
66
67 extern const h2o_http2_settings_t H2O_HTTP2_SETTINGS_DEFAULT;
68
69 int h2o_http2_update_peer_settings(h2o_http2_settings_t *settings, const uint8_t *src, size_t len, const char **err_desc);
70
71 typedef struct st_h2o_http2_priority_t {
72 int exclusive;
73 uint32_t dependency;
74 uint16_t weight;
75 } h2o_http2_priority_t;
76
77 extern const h2o_http2_priority_t h2o_http2_default_priority;
78
79 #define H2O_HTTP2_DEFAULT_OUTBUF_SIZE 81920 /* the target size of each write call; connection flow control window + alpha */
80 #define H2O_HTTP2_DEFAULT_OUTBUF_SOFT_MAX_SIZE 524288 /* 512KB; stops reading if size exceeds this value */
81 #define H2O_HTTP2_DEFAULT_OUTBUF_WRITE_TIMEOUT 60000 /* 60 seconds; close if write does not complete within the period */
82
83 /* hpack */
84
85 typedef struct st_h2o_hpack_header_table_t {
86 /* ring buffer */
87 struct st_h2o_hpack_header_table_entry_t *entries;
88 size_t num_entries, entry_capacity, entry_start_index;
89 /* size and capacities are 32+name_len+value_len (as defined by hpack spec.) */
90 size_t hpack_size;
91 size_t hpack_capacity; /* the value set by SETTINGS_HEADER_TABLE_SIZE _and_ dynamic table size update */
92 size_t hpack_max_capacity; /* the value set by SETTINGS_HEADER_TABLE_SIZE */
93 } h2o_hpack_header_table_t;
94
95 typedef struct st_h2o_hpack_header_table_entry_t {
96 h2o_iovec_t *name;
97 h2o_iovec_t *value;
98 unsigned soft_errors;
99 } h2o_hpack_header_table_entry_t;
100
101 void h2o_hpack_dispose_header_table(h2o_hpack_header_table_t *header_table);
102
103 size_t h2o_hpack_encode_string(uint8_t *dst, const char *s, size_t len);
104 void h2o_hpack_flatten_push_promise(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
105 uint32_t stream_id, size_t max_frame_size, const h2o_url_scheme_t *scheme,
106 h2o_iovec_t authority, h2o_iovec_t method, h2o_iovec_t path, const h2o_header_t *headers,
107 size_t num_headers, uint32_t parent_stream_id);
108 void h2o_hpack_flatten_response(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
109 uint32_t stream_id, size_t max_frame_size, int status, const h2o_header_t *headers,
110 size_t num_headers, const h2o_iovec_t *server_name, size_t content_length);
111 void h2o_hpack_flatten_request(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
112 uint32_t stream_id, size_t max_frame_size, h2o_iovec_t method, h2o_url_t *url,
113 const h2o_header_t *headers, size_t num_headers, int is_end_stream);
114 void h2o_hpack_flatten_trailers(h2o_buffer_t **buf, h2o_hpack_header_table_t *header_table, uint32_t hpack_capacity,
115 uint32_t stream_id, size_t max_frame_size, const h2o_header_t *headers, size_t num_headers);
116
117 extern h2o_buffer_prototype_t h2o_http2_wbuf_buffer_prototype;
118
119 /* frames */
120
121 #define H2O_HTTP2_FRAME_HEADER_SIZE 9
122
123 #define H2O_HTTP2_FRAME_TYPE_DATA 0
124 #define H2O_HTTP2_FRAME_TYPE_HEADERS 1
125 #define H2O_HTTP2_FRAME_TYPE_PRIORITY 2
126 #define H2O_HTTP2_FRAME_TYPE_RST_STREAM 3
127 #define H2O_HTTP2_FRAME_TYPE_SETTINGS 4
128 #define H2O_HTTP2_FRAME_TYPE_PUSH_PROMISE 5
129 #define H2O_HTTP2_FRAME_TYPE_PING 6
130 #define H2O_HTTP2_FRAME_TYPE_GOAWAY 7
131 #define H2O_HTTP2_FRAME_TYPE_WINDOW_UPDATE 8
132 #define H2O_HTTP2_FRAME_TYPE_CONTINUATION 9
133 #define H2O_HTTP2_FRAME_TYPE_ORIGIN 12
134
135 #define H2O_HTTP2_FRAME_FLAG_END_STREAM 0x1
136 #define H2O_HTTP2_FRAME_FLAG_ACK 0x1
137 #define H2O_HTTP2_FRAME_FLAG_END_HEADERS 0x4
138 #define H2O_HTTP2_FRAME_FLAG_PADDED 0x8
139 #define H2O_HTTP2_FRAME_FLAG_PRIORITY 0x20
140
141 typedef struct st_h2o_http2_frame_t {
142 uint32_t length;
143 uint8_t type;
144 uint8_t flags;
145 uint32_t stream_id;
146 const uint8_t *payload;
147 } h2o_http2_frame_t;
148
149 typedef struct st_h2o_http2_data_payload_t {
150 const uint8_t *data;
151 size_t length;
152 } h2o_http2_data_payload_t;
153
154 typedef struct st_h2o_http2_headers_payload_t {
155 h2o_http2_priority_t priority;
156 const uint8_t *headers;
157 size_t headers_len;
158 } h2o_http2_headers_payload_t;
159
160 typedef struct st_h2o_http2_rst_stream_payload_t {
161 uint32_t error_code;
162 } h2o_http2_rst_stream_payload_t;
163
164 typedef struct st_h2o_http2_ping_payload_t {
165 uint8_t data[8];
166 } h2o_http2_ping_payload_t;
167
168 typedef struct st_h2o_http2_goaway_payload_t {
169 uint32_t last_stream_id;
170 uint32_t error_code;
171 h2o_iovec_t debug_data;
172 } h2o_http2_goaway_payload_t;
173
174 typedef struct st_h2o_http2_window_update_payload_t {
175 uint32_t window_size_increment;
176 } h2o_http2_window_update_payload_t;
177
178 uint8_t *h2o_http2_encode_frame_header(uint8_t *dst, size_t length, uint8_t type, uint8_t flags, int32_t stream_id);
179
180 #define h2o_http2_encode_rst_stream_frame(buf, stream_id, errnum) \
181 h2o_http2__encode_rst_stream_frame(buf, stream_id, (H2O_BUILD_ASSERT((errnum) > 0), errnum))
182
183 void h2o_http2__encode_rst_stream_frame(h2o_buffer_t **buf, uint32_t stream_id, int errnum);
184 void h2o_http2_encode_ping_frame(h2o_buffer_t **buf, int is_ack, const uint8_t *data);
185 void h2o_http2_encode_goaway_frame(h2o_buffer_t **buf, uint32_t last_stream_id, int errnum, h2o_iovec_t additional_data);
186 void h2o_http2_encode_window_update_frame(h2o_buffer_t **buf, uint32_t stream_id, int32_t window_size_increment);
187 void h2o_http2_encode_origin_frame(h2o_buffer_t **buf, h2o_iovec_t payload);
188 ssize_t h2o_http2_decode_frame(h2o_http2_frame_t *frame, const uint8_t *src, size_t len, size_t max_frame_size,
189 const char **err_desc);
190 int h2o_http2_decode_data_payload(h2o_http2_data_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc);
191 int h2o_http2_decode_headers_payload(h2o_http2_headers_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc);
192 int h2o_http2_decode_priority_payload(h2o_http2_priority_t *payload, const h2o_http2_frame_t *frame, const char **err_desc);
193 int h2o_http2_decode_rst_stream_payload(h2o_http2_rst_stream_payload_t *payload, const h2o_http2_frame_t *frame,
194 const char **err_desc);
195 int h2o_http2_decode_ping_payload(h2o_http2_ping_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc);
196 int h2o_http2_decode_goaway_payload(h2o_http2_goaway_payload_t *payload, const h2o_http2_frame_t *frame, const char **err_desc);
197 int h2o_http2_decode_window_update_payload(h2o_http2_window_update_payload_t *paylaod, const h2o_http2_frame_t *frame,
198 const char **err_desc, int *err_is_stream_level);
199
200 typedef struct st_h2o_http2_window_t {
201 ssize_t _avail;
202 } h2o_http2_window_t;
203
204 static void h2o_http2_window_init(h2o_http2_window_t *window, uint32_t initial_window_size);
205 static int h2o_http2_window_update(h2o_http2_window_t *window, ssize_t delta);
206 static ssize_t h2o_http2_window_get_avail(h2o_http2_window_t *window);
207 static void h2o_http2_window_consume_window(h2o_http2_window_t *window, size_t bytes);
208
209 static h2o_hpack_header_table_entry_t *h2o_hpack_header_table_get(h2o_hpack_header_table_t *table, size_t index);
210
211 /* misc */
212
213 static uint16_t h2o_http2_decode16u(const uint8_t *src);
214 static uint32_t h2o_http2_decode24u(const uint8_t *src);
215 static uint32_t h2o_http2_decode32u(const uint8_t *src);
216 static uint8_t *h2o_http2_encode24u(uint8_t *dst, uint32_t value);
217 static uint8_t *h2o_http2_encode32u(uint8_t *dst, uint32_t value);
218
219 /* inline definitions */
220
h2o_http2_window_init(h2o_http2_window_t * window,uint32_t initial_window_size)221 inline void h2o_http2_window_init(h2o_http2_window_t *window, uint32_t initial_window_size)
222 {
223 window->_avail = initial_window_size;
224 }
225
h2o_http2_window_update(h2o_http2_window_t * window,ssize_t delta)226 inline int h2o_http2_window_update(h2o_http2_window_t *window, ssize_t delta)
227 {
228 ssize_t v = window->_avail + delta;
229 if (v > INT32_MAX)
230 return -1;
231 window->_avail = v;
232 return 0;
233 }
234
h2o_http2_window_get_avail(h2o_http2_window_t * window)235 inline ssize_t h2o_http2_window_get_avail(h2o_http2_window_t *window)
236 {
237 return window->_avail;
238 }
239
h2o_http2_window_consume_window(h2o_http2_window_t * window,size_t bytes)240 inline void h2o_http2_window_consume_window(h2o_http2_window_t *window, size_t bytes)
241 {
242 window->_avail -= bytes;
243 }
244
h2o_http2_decode16u(const uint8_t * src)245 inline uint16_t h2o_http2_decode16u(const uint8_t *src)
246 {
247 return (uint16_t)src[0] << 8 | src[1];
248 }
249
h2o_http2_decode24u(const uint8_t * src)250 inline uint32_t h2o_http2_decode24u(const uint8_t *src)
251 {
252 return (uint32_t)src[0] << 16 | (uint32_t)src[1] << 8 | src[2];
253 }
254
h2o_http2_decode32u(const uint8_t * src)255 inline uint32_t h2o_http2_decode32u(const uint8_t *src)
256 {
257 return (uint32_t)src[0] << 24 | (uint32_t)src[1] << 16 | (uint32_t)src[2] << 8 | src[3];
258 }
259
h2o_http2_encode24u(uint8_t * dst,uint32_t value)260 inline uint8_t *h2o_http2_encode24u(uint8_t *dst, uint32_t value)
261 {
262 *dst++ = value >> 16;
263 *dst++ = value >> 8;
264 *dst++ = value;
265 return dst;
266 }
267
h2o_http2_encode32u(uint8_t * dst,uint32_t value)268 inline uint8_t *h2o_http2_encode32u(uint8_t *dst, uint32_t value)
269 {
270 *dst++ = value >> 24;
271 *dst++ = value >> 16;
272 *dst++ = value >> 8;
273 *dst++ = value;
274 return dst;
275 }
276
h2o_hpack_header_table_get(h2o_hpack_header_table_t * table,size_t index)277 inline h2o_hpack_header_table_entry_t *h2o_hpack_header_table_get(h2o_hpack_header_table_t *table, size_t index)
278 {
279 size_t entry_index = (index + table->entry_start_index) % table->entry_capacity;
280 struct st_h2o_hpack_header_table_entry_t *entry = table->entries + entry_index;
281 assert(entry->name != NULL);
282 return entry;
283 }
284
285 #endif
286