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 off_t total_bytes;
123 off_t payload_bytes;
124
125 ngx_uint_t processing;
126 ngx_uint_t frames;
127 ngx_uint_t idle;
128 ngx_uint_t priority_limit;
129
130 ngx_uint_t pushing;
131 ngx_uint_t concurrent_pushes;
132
133 size_t send_window;
134 size_t recv_window;
135 size_t init_window;
136
137 size_t frame_size;
138
139 ngx_queue_t waiting;
140
141 ngx_http_v2_state_t state;
142
143 ngx_http_v2_hpack_t hpack;
144
145 ngx_pool_t *pool;
146
147 ngx_http_v2_out_frame_t *free_frames;
148 ngx_connection_t *free_fake_connections;
149
150 ngx_http_v2_node_t **streams_index;
151
152 ngx_http_v2_out_frame_t *last_out;
153
154 ngx_queue_t dependencies;
155 ngx_queue_t closed;
156
157 ngx_uint_t last_sid;
158 ngx_uint_t last_push;
159
160 time_t lingering_time;
161
162 unsigned closed_nodes:8;
163 unsigned settings_ack:1;
164 unsigned table_update:1;
165 unsigned blocked:1;
166 unsigned goaway:1;
167 unsigned push_disabled:1;
168 };
169
170
171 struct ngx_http_v2_node_s {
172 ngx_uint_t id;
173 ngx_http_v2_node_t *index;
174 ngx_http_v2_node_t *parent;
175 ngx_queue_t queue;
176 ngx_queue_t children;
177 ngx_queue_t reuse;
178 ngx_uint_t rank;
179 ngx_uint_t weight;
180 double rel_weight;
181 ngx_http_v2_stream_t *stream;
182 };
183
184
185 struct ngx_http_v2_stream_s {
186 ngx_http_request_t *request;
187 ngx_http_v2_connection_t *connection;
188 ngx_http_v2_node_t *node;
189
190 ngx_uint_t queued;
191
192 /*
193 * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the
194 * send_window to become negative, hence it's signed.
195 */
196 ssize_t send_window;
197 size_t recv_window;
198
199 ngx_buf_t *preread;
200
201 ngx_uint_t frames;
202
203 ngx_http_v2_out_frame_t *free_frames;
204 ngx_chain_t *free_frame_headers;
205 ngx_chain_t *free_bufs;
206
207 ngx_queue_t queue;
208
209 ngx_array_t *cookies;
210
211 ngx_pool_t *pool;
212
213 unsigned waiting:1;
214 unsigned blocked:1;
215 unsigned exhausted:1;
216 unsigned in_closed:1;
217 unsigned out_closed:1;
218 unsigned rst_sent:1;
219 unsigned no_flow_control:1;
220 unsigned skip_data:1;
221 };
222
223
224 struct ngx_http_v2_out_frame_s {
225 ngx_http_v2_out_frame_t *next;
226 ngx_chain_t *first;
227 ngx_chain_t *last;
228 ngx_int_t (*handler)(ngx_http_v2_connection_t *h2c,
229 ngx_http_v2_out_frame_t *frame);
230
231 ngx_http_v2_stream_t *stream;
232 size_t length;
233
234 unsigned blocked:1;
235 unsigned fin:1;
236 };
237
238
239 static ngx_inline void
ngx_http_v2_queue_frame(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)240 ngx_http_v2_queue_frame(ngx_http_v2_connection_t *h2c,
241 ngx_http_v2_out_frame_t *frame)
242 {
243 ngx_http_v2_out_frame_t **out;
244
245 for (out = &h2c->last_out; *out; out = &(*out)->next) {
246
247 if ((*out)->blocked || (*out)->stream == NULL) {
248 break;
249 }
250
251 if ((*out)->stream->node->rank < frame->stream->node->rank
252 || ((*out)->stream->node->rank == frame->stream->node->rank
253 && (*out)->stream->node->rel_weight
254 >= frame->stream->node->rel_weight))
255 {
256 break;
257 }
258 }
259
260 frame->next = *out;
261 *out = frame;
262 }
263
264
265 static ngx_inline void
ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)266 ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t *h2c,
267 ngx_http_v2_out_frame_t *frame)
268 {
269 ngx_http_v2_out_frame_t **out;
270
271 for (out = &h2c->last_out; *out; out = &(*out)->next) {
272
273 if ((*out)->blocked || (*out)->stream == NULL) {
274 break;
275 }
276 }
277
278 frame->next = *out;
279 *out = frame;
280 }
281
282
283 static ngx_inline void
ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)284 ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t *h2c,
285 ngx_http_v2_out_frame_t *frame)
286 {
287 frame->next = h2c->last_out;
288 h2c->last_out = frame;
289 }
290
291
292 void ngx_http_v2_init(ngx_event_t *rev);
293
294 ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r);
295 ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r);
296
297 ngx_http_v2_stream_t *ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent,
298 ngx_str_t *path);
299
300 void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
301
302 ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c);
303
304
305 ngx_str_t *ngx_http_v2_get_static_name(ngx_uint_t index);
306 ngx_str_t *ngx_http_v2_get_static_value(ngx_uint_t index);
307
308 ngx_int_t ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c,
309 ngx_uint_t index, ngx_uint_t name_only);
310 ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c,
311 ngx_http_v2_header_t *header);
312 ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size);
313
314
315 ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len,
316 u_char **dst, ngx_uint_t last, ngx_log_t *log);
317 size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst,
318 ngx_uint_t lower);
319
320
321 #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1)
322
323
324 #if (NGX_HAVE_NONALIGNED)
325
326 #define ngx_http_v2_parse_uint16(p) ntohs(*(uint16_t *) (p))
327 #define ngx_http_v2_parse_uint32(p) ntohl(*(uint32_t *) (p))
328
329 #else
330
331 #define ngx_http_v2_parse_uint16(p) ((p)[0] << 8 | (p)[1])
332 #define ngx_http_v2_parse_uint32(p) \
333 ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])
334
335 #endif
336
337 #define ngx_http_v2_parse_length(p) ((p) >> 8)
338 #define ngx_http_v2_parse_type(p) ((p) & 0xff)
339 #define ngx_http_v2_parse_sid(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff)
340 #define ngx_http_v2_parse_window(p) (ngx_http_v2_parse_uint32(p) & 0x7fffffff)
341
342
343 #define ngx_http_v2_write_uint16_aligned(p, s) \
344 (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
345 #define ngx_http_v2_write_uint32_aligned(p, s) \
346 (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))
347
348 #if (NGX_HAVE_NONALIGNED)
349
350 #define ngx_http_v2_write_uint16 ngx_http_v2_write_uint16_aligned
351 #define ngx_http_v2_write_uint32 ngx_http_v2_write_uint32_aligned
352
353 #else
354
355 #define ngx_http_v2_write_uint16(p, s) \
356 ((p)[0] = (u_char) ((s) >> 8), \
357 (p)[1] = (u_char) (s), \
358 (p) + sizeof(uint16_t))
359
360 #define ngx_http_v2_write_uint32(p, s) \
361 ((p)[0] = (u_char) ((s) >> 24), \
362 (p)[1] = (u_char) ((s) >> 16), \
363 (p)[2] = (u_char) ((s) >> 8), \
364 (p)[3] = (u_char) (s), \
365 (p) + sizeof(uint32_t))
366
367 #endif
368
369 #define ngx_http_v2_write_len_and_type(p, l, t) \
370 ngx_http_v2_write_uint32_aligned(p, (l) << 8 | (t))
371
372 #define ngx_http_v2_write_sid ngx_http_v2_write_uint32
373
374
375 #define ngx_http_v2_indexed(i) (128 + (i))
376 #define ngx_http_v2_inc_indexed(i) (64 + (i))
377
378 #define ngx_http_v2_write_name(dst, src, len, tmp) \
379 ngx_http_v2_string_encode(dst, src, len, tmp, 1)
380 #define ngx_http_v2_write_value(dst, src, len, tmp) \
381 ngx_http_v2_string_encode(dst, src, len, tmp, 0)
382
383 #define NGX_HTTP_V2_ENCODE_RAW 0
384 #define NGX_HTTP_V2_ENCODE_HUFF 0x80
385
386 #define NGX_HTTP_V2_AUTHORITY_INDEX 1
387
388 #define NGX_HTTP_V2_METHOD_INDEX 2
389 #define NGX_HTTP_V2_METHOD_GET_INDEX 2
390 #define NGX_HTTP_V2_METHOD_POST_INDEX 3
391
392 #define NGX_HTTP_V2_PATH_INDEX 4
393 #define NGX_HTTP_V2_PATH_ROOT_INDEX 4
394
395 #define NGX_HTTP_V2_SCHEME_HTTP_INDEX 6
396 #define NGX_HTTP_V2_SCHEME_HTTPS_INDEX 7
397
398 #define NGX_HTTP_V2_STATUS_INDEX 8
399 #define NGX_HTTP_V2_STATUS_200_INDEX 8
400 #define NGX_HTTP_V2_STATUS_204_INDEX 9
401 #define NGX_HTTP_V2_STATUS_206_INDEX 10
402 #define NGX_HTTP_V2_STATUS_304_INDEX 11
403 #define NGX_HTTP_V2_STATUS_400_INDEX 12
404 #define NGX_HTTP_V2_STATUS_404_INDEX 13
405 #define NGX_HTTP_V2_STATUS_500_INDEX 14
406
407 #define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16
408 #define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17
409 #define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28
410 #define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31
411 #define NGX_HTTP_V2_DATE_INDEX 33
412 #define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44
413 #define NGX_HTTP_V2_LOCATION_INDEX 46
414 #define NGX_HTTP_V2_SERVER_INDEX 54
415 #define NGX_HTTP_V2_USER_AGENT_INDEX 58
416 #define NGX_HTTP_V2_VARY_INDEX 59
417
418
419 u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
420 u_char *tmp, ngx_uint_t lower);
421
422
423 #endif /* _NGX_HTTP_V2_H_INCLUDED_ */
424