1 /*
2 * Copyright (C) Nginx, Inc.
3 * Copyright (C) Valentin V. Bartenev
4 */
5
6
7 #ifndef _NGX_HTTP_V2_H_INCLUDED_
8 #define _NGX_HTTP_V2_H_INCLUDED_
9
10
11 #include <ngx_config.h>
12 #include <ngx_core.h>
13 #include <ngx_http.h>
14
15
16 #define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2"
17 #define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE
18
19 #define NGX_HTTP_V2_STATE_BUFFER_SIZE 16
20
21 #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14)
22 #define NGX_HTTP_V2_MAX_FRAME_SIZE ((1 << 24) - 1)
23
24 #define NGX_HTTP_V2_INT_OCTETS 4
25 #define NGX_HTTP_V2_MAX_FIELD \
26 (127 + (1 << (NGX_HTTP_V2_INT_OCTETS - 1) * 7) - 1)
27
28 #define NGX_HTTP_V2_STREAM_ID_SIZE 4
29
30 #define NGX_HTTP_V2_FRAME_HEADER_SIZE 9
31
32 /* frame types */
33 #define NGX_HTTP_V2_DATA_FRAME 0x0
34 #define NGX_HTTP_V2_HEADERS_FRAME 0x1
35 #define NGX_HTTP_V2_PRIORITY_FRAME 0x2
36 #define NGX_HTTP_V2_RST_STREAM_FRAME 0x3
37 #define NGX_HTTP_V2_SETTINGS_FRAME 0x4
38 #define NGX_HTTP_V2_PUSH_PROMISE_FRAME 0x5
39 #define NGX_HTTP_V2_PING_FRAME 0x6
40 #define NGX_HTTP_V2_GOAWAY_FRAME 0x7
41 #define NGX_HTTP_V2_WINDOW_UPDATE_FRAME 0x8
42 #define NGX_HTTP_V2_CONTINUATION_FRAME 0x9
43
44 /* frame flags */
45 #define NGX_HTTP_V2_NO_FLAG 0x00
46 #define NGX_HTTP_V2_ACK_FLAG 0x01
47 #define NGX_HTTP_V2_END_STREAM_FLAG 0x01
48 #define NGX_HTTP_V2_END_HEADERS_FLAG 0x04
49 #define NGX_HTTP_V2_PADDED_FLAG 0x08
50 #define NGX_HTTP_V2_PRIORITY_FLAG 0x20
51
52 #define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1)
53 #define NGX_HTTP_V2_DEFAULT_WINDOW 65535
54
55 #define NGX_HTTP_V2_DEFAULT_WEIGHT 16
56
57
58 typedef struct ngx_http_v2_connection_s ngx_http_v2_connection_t;
59 typedef struct ngx_http_v2_node_s ngx_http_v2_node_t;
60 typedef struct ngx_http_v2_out_frame_s ngx_http_v2_out_frame_t;
61
62
63 typedef u_char *(*ngx_http_v2_handler_pt) (ngx_http_v2_connection_t *h2c,
64 u_char *pos, u_char *end);
65
66
67 typedef struct {
68 ngx_str_t name;
69 ngx_str_t value;
70 } ngx_http_v2_header_t;
71
72
73 typedef struct {
74 ngx_uint_t sid;
75 size_t length;
76 size_t padding;
77 unsigned flags:8;
78
79 unsigned incomplete:1;
80 unsigned keep_pool:1;
81
82 /* HPACK */
83 unsigned parse_name:1;
84 unsigned parse_value:1;
85 unsigned index:1;
86 ngx_http_v2_header_t header;
87 size_t header_limit;
88 u_char field_state;
89 u_char *field_start;
90 u_char *field_end;
91 size_t field_rest;
92 ngx_pool_t *pool;
93
94 ngx_http_v2_stream_t *stream;
95
96 u_char buffer[NGX_HTTP_V2_STATE_BUFFER_SIZE];
97 size_t buffer_used;
98 ngx_http_v2_handler_pt handler;
99 } ngx_http_v2_state_t;
100
101
102
103 typedef struct {
104 ngx_http_v2_header_t **entries;
105
106 ngx_uint_t added;
107 ngx_uint_t deleted;
108 ngx_uint_t reused;
109 ngx_uint_t allocated;
110
111 size_t size;
112 size_t free;
113 u_char *storage;
114 u_char *pos;
115 } ngx_http_v2_hpack_t;
116
117
118 struct ngx_http_v2_connection_s {
119 ngx_connection_t *connection;
120 ngx_http_connection_t *http_connection;
121
122 ngx_uint_t processing;
123 ngx_uint_t frames;
124 ngx_uint_t idle;
125 ngx_uint_t priority_limit;
126
127 ngx_uint_t pushing;
128 ngx_uint_t concurrent_pushes;
129
130 size_t send_window;
131 size_t recv_window;
132 size_t init_window;
133
134 size_t frame_size;
135
136 ngx_queue_t waiting;
137
138 ngx_http_v2_state_t state;
139
140 ngx_http_v2_hpack_t hpack;
141
142 ngx_pool_t *pool;
143
144 ngx_http_v2_out_frame_t *free_frames;
145 ngx_connection_t *free_fake_connections;
146
147 ngx_http_v2_node_t **streams_index;
148
149 ngx_http_v2_out_frame_t *last_out;
150
151 ngx_queue_t dependencies;
152 ngx_queue_t closed;
153
154 ngx_uint_t last_sid;
155 ngx_uint_t last_push;
156
157 unsigned closed_nodes:8;
158 unsigned settings_ack:1;
159 unsigned table_update:1;
160 unsigned blocked:1;
161 unsigned goaway:1;
162 unsigned push_disabled:1;
163 };
164
165
166 struct ngx_http_v2_node_s {
167 ngx_uint_t id;
168 ngx_http_v2_node_t *index;
169 ngx_http_v2_node_t *parent;
170 ngx_queue_t queue;
171 ngx_queue_t children;
172 ngx_queue_t reuse;
173 ngx_uint_t rank;
174 ngx_uint_t weight;
175 double rel_weight;
176 ngx_http_v2_stream_t *stream;
177 };
178
179
180 struct ngx_http_v2_stream_s {
181 ngx_http_request_t *request;
182 ngx_http_v2_connection_t *connection;
183 ngx_http_v2_node_t *node;
184
185 ngx_uint_t queued;
186
187 /*
188 * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the
189 * send_window to become negative, hence it's signed.
190 */
191 ssize_t send_window;
192 size_t recv_window;
193
194 ngx_buf_t *preread;
195
196 ngx_uint_t frames;
197
198 ngx_http_v2_out_frame_t *free_frames;
199 ngx_chain_t *free_frame_headers;
200 ngx_chain_t *free_bufs;
201
202 ngx_queue_t queue;
203
204 ngx_array_t *cookies;
205
206 ngx_pool_t *pool;
207
208 unsigned waiting:1;
209 unsigned blocked:1;
210 unsigned exhausted:1;
211 unsigned in_closed:1;
212 unsigned out_closed:1;
213 unsigned rst_sent:1;
214 unsigned no_flow_control:1;
215 unsigned skip_data:1;
216 };
217
218
219 struct ngx_http_v2_out_frame_s {
220 ngx_http_v2_out_frame_t *next;
221 ngx_chain_t *first;
222 ngx_chain_t *last;
223 ngx_int_t (*handler)(ngx_http_v2_connection_t *h2c,
224 ngx_http_v2_out_frame_t *frame);
225
226 ngx_http_v2_stream_t *stream;
227 size_t length;
228
229 unsigned blocked:1;
230 unsigned fin:1;
231 };
232
233
234 static ngx_inline void
ngx_http_v2_queue_frame(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)235 ngx_http_v2_queue_frame(ngx_http_v2_connection_t *h2c,
236 ngx_http_v2_out_frame_t *frame)
237 {
238 ngx_http_v2_out_frame_t **out;
239
240 for (out = &h2c->last_out; *out; out = &(*out)->next) {
241
242 if ((*out)->blocked || (*out)->stream == NULL) {
243 break;
244 }
245
246 if ((*out)->stream->node->rank < frame->stream->node->rank
247 || ((*out)->stream->node->rank == frame->stream->node->rank
248 && (*out)->stream->node->rel_weight
249 >= frame->stream->node->rel_weight))
250 {
251 break;
252 }
253 }
254
255 frame->next = *out;
256 *out = frame;
257 }
258
259
260 static ngx_inline void
ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)261 ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t *h2c,
262 ngx_http_v2_out_frame_t *frame)
263 {
264 ngx_http_v2_out_frame_t **out;
265
266 for (out = &h2c->last_out; *out; out = &(*out)->next) {
267
268 if ((*out)->blocked || (*out)->stream == NULL) {
269 break;
270 }
271 }
272
273 frame->next = *out;
274 *out = frame;
275 }
276
277
278 static ngx_inline void
ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)279 ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t *h2c,
280 ngx_http_v2_out_frame_t *frame)
281 {
282 frame->next = h2c->last_out;
283 h2c->last_out = frame;
284 }
285
286
287 void ngx_http_v2_init(ngx_event_t *rev);
288
289 ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r);
290 ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r);
291
292 ngx_http_v2_stream_t *ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent,
293 ngx_str_t *path);
294
295 void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
296
297 ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c);
298
299
300 ngx_str_t *ngx_http_v2_get_static_name(ngx_uint_t index);
301 ngx_str_t *ngx_http_v2_get_static_value(ngx_uint_t index);
302
303 ngx_int_t ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c,
304 ngx_uint_t index, ngx_uint_t name_only);
305 ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c,
306 ngx_http_v2_header_t *header);
307 ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size);
308
309
310 ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len,
311 u_char **dst, ngx_uint_t last, ngx_log_t *log);
312 size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst,
313 ngx_uint_t lower);
314
315
316 #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1)
317
318
319 #if (NGX_HAVE_NONALIGNED)
320
321 #define ngx_http_v2_parse_uint16(p) ntohs(*(uint16_t *) (p))
322 #define ngx_http_v2_parse_uint32(p) ntohl(*(uint32_t *) (p))
323
324 #else
325
326 #define ngx_http_v2_parse_uint16(p) ((p)[0] << 8 | (p)[1])
327 #define ngx_http_v2_parse_uint32(p) \
328 ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])
329
330 #endif
331
332 #define ngx_http_v2_parse_length(p) ((p) >> 8)
333 #define ngx_http_v2_parse_type(p) ((p) & 0xff)
334 #define ngx_http_v2_parse_sid(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff)
335 #define ngx_http_v2_parse_window(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff)
336
337
338 #define ngx_http_v2_write_uint16_aligned(p, s) \
339 (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
340 #define ngx_http_v2_write_uint32_aligned(p, s) \
341 (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))
342
343 #if (NGX_HAVE_NONALIGNED)
344
345 #define ngx_http_v2_write_uint16 ngx_http_v2_write_uint16_aligned
346 #define ngx_http_v2_write_uint32 ngx_http_v2_write_uint32_aligned
347
348 #else
349
350 #define ngx_http_v2_write_uint16(p, s) \
351 ((p)[0] = (u_char) ((s) >> 8), \
352 (p)[1] = (u_char) (s), \
353 (p) + sizeof(uint16_t))
354
355 #define ngx_http_v2_write_uint32(p, s) \
356 ((p)[0] = (u_char) ((s) >> 24), \
357 (p)[1] = (u_char) ((s) >> 16), \
358 (p)[2] = (u_char) ((s) >> 8), \
359 (p)[3] = (u_char) (s), \
360 (p) + sizeof(uint32_t))
361
362 #endif
363
364 #define ngx_http_v2_write_len_and_type(p, l, t) \
365 ngx_http_v2_write_uint32_aligned(p, (l) << 8 | (t))
366
367 #define ngx_http_v2_write_sid ngx_http_v2_write_uint32
368
369
370 #define ngx_http_v2_indexed(i) (128 + (i))
371 #define ngx_http_v2_inc_indexed(i) (64 + (i))
372
373 #define ngx_http_v2_write_name(dst, src, len, tmp) \
374 ngx_http_v2_string_encode(dst, src, len, tmp, 1)
375 #define ngx_http_v2_write_value(dst, src, len, tmp) \
376 ngx_http_v2_string_encode(dst, src, len, tmp, 0)
377
378 #define NGX_HTTP_V2_ENCODE_RAW 0
379 #define NGX_HTTP_V2_ENCODE_HUFF 0x80
380
381 #define NGX_HTTP_V2_AUTHORITY_INDEX 1
382
383 #define NGX_HTTP_V2_METHOD_INDEX 2
384 #define NGX_HTTP_V2_METHOD_GET_INDEX 2
385 #define NGX_HTTP_V2_METHOD_POST_INDEX 3
386
387 #define NGX_HTTP_V2_PATH_INDEX 4
388 #define NGX_HTTP_V2_PATH_ROOT_INDEX 4
389
390 #define NGX_HTTP_V2_SCHEME_HTTP_INDEX 6
391 #define NGX_HTTP_V2_SCHEME_HTTPS_INDEX 7
392
393 #define NGX_HTTP_V2_STATUS_INDEX 8
394 #define NGX_HTTP_V2_STATUS_200_INDEX 8
395 #define NGX_HTTP_V2_STATUS_204_INDEX 9
396 #define NGX_HTTP_V2_STATUS_206_INDEX 10
397 #define NGX_HTTP_V2_STATUS_304_INDEX 11
398 #define NGX_HTTP_V2_STATUS_400_INDEX 12
399 #define NGX_HTTP_V2_STATUS_404_INDEX 13
400 #define NGX_HTTP_V2_STATUS_500_INDEX 14
401
402 #define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16
403 #define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17
404 #define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28
405 #define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31
406 #define NGX_HTTP_V2_DATE_INDEX 33
407 #define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44
408 #define NGX_HTTP_V2_LOCATION_INDEX 46
409 #define NGX_HTTP_V2_SERVER_INDEX 54
410 #define NGX_HTTP_V2_USER_AGENT_INDEX 58
411 #define NGX_HTTP_V2_VARY_INDEX 59
412
413
414 u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
415 u_char *tmp, ngx_uint_t lower);
416
417
418 #endif /* _NGX_HTTP_V2_H_INCLUDED_ */
419