Coverage Report

Created: 2024-02-11 06:05

/src/nginx/src/http/v2/ngx_http_v2.c
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright (C) Nginx, Inc.
4
 * Copyright (C) Valentin V. Bartenev
5
 */
6
7
8
#include <ngx_config.h>
9
#include <ngx_core.h>
10
#include <ngx_http.h>
11
#include <ngx_http_v2_module.h>
12
13
14
/* errors */
15
0
#define NGX_HTTP_V2_NO_ERROR                     0x0
16
0
#define NGX_HTTP_V2_PROTOCOL_ERROR               0x1
17
0
#define NGX_HTTP_V2_INTERNAL_ERROR               0x2
18
0
#define NGX_HTTP_V2_FLOW_CTRL_ERROR              0x3
19
#define NGX_HTTP_V2_SETTINGS_TIMEOUT             0x4
20
0
#define NGX_HTTP_V2_STREAM_CLOSED                0x5
21
0
#define NGX_HTTP_V2_SIZE_ERROR                   0x6
22
0
#define NGX_HTTP_V2_REFUSED_STREAM               0x7
23
0
#define NGX_HTTP_V2_CANCEL                       0x8
24
0
#define NGX_HTTP_V2_COMP_ERROR                   0x9
25
#define NGX_HTTP_V2_CONNECT_ERROR                0xa
26
0
#define NGX_HTTP_V2_ENHANCE_YOUR_CALM            0xb
27
#define NGX_HTTP_V2_INADEQUATE_SECURITY          0xc
28
#define NGX_HTTP_V2_HTTP_1_1_REQUIRED            0xd
29
30
/* frame sizes */
31
0
#define NGX_HTTP_V2_SETTINGS_ACK_SIZE            0
32
0
#define NGX_HTTP_V2_RST_STREAM_SIZE              4
33
0
#define NGX_HTTP_V2_PRIORITY_SIZE                5
34
0
#define NGX_HTTP_V2_PING_SIZE                    8
35
0
#define NGX_HTTP_V2_GOAWAY_SIZE                  8
36
0
#define NGX_HTTP_V2_WINDOW_UPDATE_SIZE           4
37
38
0
#define NGX_HTTP_V2_SETTINGS_PARAM_SIZE          6
39
40
/* settings fields */
41
0
#define NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING    0x1
42
0
#define NGX_HTTP_V2_ENABLE_PUSH_SETTING          0x2
43
#define NGX_HTTP_V2_MAX_STREAMS_SETTING          0x3
44
0
#define NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING     0x4
45
0
#define NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING       0x5
46
47
0
#define NGX_HTTP_V2_FRAME_BUFFER_SIZE            24
48
49
0
#define NGX_HTTP_V2_ROOT                         (void *) -1
50
51
52
static void ngx_http_v2_read_handler(ngx_event_t *rev);
53
static void ngx_http_v2_write_handler(ngx_event_t *wev);
54
static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c);
55
static void ngx_http_v2_lingering_close(ngx_connection_t *c);
56
static void ngx_http_v2_lingering_close_handler(ngx_event_t *rev);
57
58
static u_char *ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c,
59
    u_char *pos, u_char *end);
60
static u_char *ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c,
61
    u_char *pos, u_char *end);
62
static u_char *ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c,
63
    u_char *pos, u_char *end);
64
static u_char *ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c,
65
    u_char *pos, u_char *end);
66
static u_char *ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c,
67
    u_char *pos, u_char *end);
68
static u_char *ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c,
69
    u_char *pos, u_char *end);
70
static u_char *ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c,
71
    u_char *pos, u_char *end);
72
static u_char *ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c,
73
    u_char *pos, u_char *end);
74
static u_char *ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c,
75
    u_char *pos, u_char *end);
76
static u_char *ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c,
77
    u_char *pos, u_char *end);
78
static u_char *ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c,
79
    u_char *pos, u_char *end);
80
static u_char *ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c,
81
    u_char *pos, u_char *end);
82
static u_char *ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c,
83
    u_char *pos, u_char *end);
84
static u_char *ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c,
85
    u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
86
static u_char *ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c,
87
    u_char *pos, u_char *end);
88
static u_char *ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c,
89
    u_char *pos, u_char *end);
90
static u_char *ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c,
91
    u_char *pos, u_char *end);
92
static u_char *ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c,
93
    u_char *pos, u_char *end);
94
static u_char *ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c,
95
    u_char *pos, u_char *end);
96
static u_char *ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c,
97
    u_char *pos, u_char *end);
98
static u_char *ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c,
99
    u_char *pos, u_char *end);
100
static u_char *ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c,
101
    u_char *pos, u_char *end);
102
static u_char *ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c,
103
    u_char *pos, u_char *end);
104
static u_char *ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c,
105
    u_char *pos, u_char *end);
106
static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c,
107
    u_char *pos, u_char *end);
108
static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c,
109
    u_char *pos, u_char *end);
110
static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c,
111
    u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
112
static u_char *ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c,
113
    u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
114
static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
115
    ngx_uint_t err);
116
117
static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c,
118
    u_char **pos, u_char *end, ngx_uint_t prefix);
119
120
static ngx_http_v2_stream_t *ngx_http_v2_create_stream(
121
    ngx_http_v2_connection_t *h2c);
122
static ngx_http_v2_node_t *ngx_http_v2_get_node_by_id(
123
    ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t alloc);
124
static ngx_http_v2_node_t *ngx_http_v2_get_closed_node(
125
    ngx_http_v2_connection_t *h2c);
126
0
#define ngx_http_v2_index_size(h2scf)  (h2scf->streams_index_mask + 1)
127
0
#define ngx_http_v2_index(h2scf, sid)  ((sid >> 1) & h2scf->streams_index_mask)
128
129
static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c);
130
static ngx_int_t ngx_http_v2_settings_frame_handler(
131
    ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame);
132
static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c,
133
    ngx_uint_t sid, size_t window);
134
static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c,
135
    ngx_uint_t sid, ngx_uint_t status);
136
static ngx_int_t ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c,
137
    ngx_uint_t status);
138
139
static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame(
140
    ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type,
141
    u_char flags, ngx_uint_t sid);
142
static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
143
    ngx_http_v2_out_frame_t *frame);
144
145
static ngx_int_t ngx_http_v2_validate_header(ngx_http_request_t *r,
146
    ngx_http_v2_header_t *header);
147
static ngx_int_t ngx_http_v2_pseudo_header(ngx_http_request_t *r,
148
    ngx_http_v2_header_t *header);
149
static ngx_int_t ngx_http_v2_parse_path(ngx_http_request_t *r,
150
    ngx_str_t *value);
151
static ngx_int_t ngx_http_v2_parse_method(ngx_http_request_t *r,
152
    ngx_str_t *value);
153
static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r,
154
    ngx_str_t *value);
155
static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r,
156
    ngx_str_t *value);
157
static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
158
static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
159
    ngx_http_v2_header_t *header);
160
static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
161
static void ngx_http_v2_run_request(ngx_http_request_t *r);
162
static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r,
163
    u_char *pos, size_t size, ngx_uint_t last, ngx_uint_t flush);
164
static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r);
165
static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
166
167
static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
168
    ngx_http_v2_stream_t *stream, ngx_uint_t status);
169
static void ngx_http_v2_close_stream_handler(ngx_event_t *ev);
170
static void ngx_http_v2_retry_close_stream_handler(ngx_event_t *ev);
171
static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev);
172
static void ngx_http_v2_idle_handler(ngx_event_t *rev);
173
static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
174
    ngx_uint_t status);
175
176
static ngx_int_t ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c,
177
    ssize_t delta);
178
static void ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
179
    ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive);
180
static void ngx_http_v2_node_children_update(ngx_http_v2_node_t *node);
181
182
static void ngx_http_v2_pool_cleanup(void *data);
183
184
185
static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = {
186
    ngx_http_v2_state_data,               /* NGX_HTTP_V2_DATA_FRAME */
187
    ngx_http_v2_state_headers,            /* NGX_HTTP_V2_HEADERS_FRAME */
188
    ngx_http_v2_state_priority,           /* NGX_HTTP_V2_PRIORITY_FRAME */
189
    ngx_http_v2_state_rst_stream,         /* NGX_HTTP_V2_RST_STREAM_FRAME */
190
    ngx_http_v2_state_settings,           /* NGX_HTTP_V2_SETTINGS_FRAME */
191
    ngx_http_v2_state_push_promise,       /* NGX_HTTP_V2_PUSH_PROMISE_FRAME */
192
    ngx_http_v2_state_ping,               /* NGX_HTTP_V2_PING_FRAME */
193
    ngx_http_v2_state_goaway,             /* NGX_HTTP_V2_GOAWAY_FRAME */
194
    ngx_http_v2_state_window_update,      /* NGX_HTTP_V2_WINDOW_UPDATE_FRAME */
195
    ngx_http_v2_state_continuation        /* NGX_HTTP_V2_CONTINUATION_FRAME */
196
};
197
198
#define NGX_HTTP_V2_FRAME_STATES                                              \
199
0
    (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt))
200
201
202
void
203
ngx_http_v2_init(ngx_event_t *rev)
204
0
{
205
0
    u_char                    *p, *end;
206
0
    ngx_connection_t          *c;
207
0
    ngx_pool_cleanup_t        *cln;
208
0
    ngx_http_connection_t     *hc;
209
0
    ngx_http_v2_srv_conf_t    *h2scf;
210
0
    ngx_http_v2_main_conf_t   *h2mcf;
211
0
    ngx_http_v2_connection_t  *h2c;
212
0
    ngx_http_core_srv_conf_t  *cscf;
213
214
0
    c = rev->data;
215
0
    hc = c->data;
216
217
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init http2 connection");
218
219
0
    c->log->action = "processing HTTP/2 connection";
220
221
0
    h2mcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_v2_module);
222
223
0
    if (h2mcf->recv_buffer == NULL) {
224
0
        h2mcf->recv_buffer = ngx_palloc(ngx_cycle->pool,
225
0
                                        h2mcf->recv_buffer_size);
226
0
        if (h2mcf->recv_buffer == NULL) {
227
0
            ngx_http_close_connection(c);
228
0
            return;
229
0
        }
230
0
    }
231
232
0
    h2c = ngx_pcalloc(c->pool, sizeof(ngx_http_v2_connection_t));
233
0
    if (h2c == NULL) {
234
0
        ngx_http_close_connection(c);
235
0
        return;
236
0
    }
237
238
0
    h2c->connection = c;
239
0
    h2c->http_connection = hc;
240
241
0
    h2c->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
242
0
    h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;
243
244
0
    h2c->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
245
246
0
    h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
247
248
0
    h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
249
250
0
    h2c->priority_limit = ngx_max(h2scf->concurrent_streams, 100);
251
252
0
    h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
253
0
    if (h2c->pool == NULL) {
254
0
        ngx_http_close_connection(c);
255
0
        return;
256
0
    }
257
258
0
    cln = ngx_pool_cleanup_add(c->pool, 0);
259
0
    if (cln == NULL) {
260
0
        ngx_http_close_connection(c);
261
0
        return;
262
0
    }
263
264
0
    cln->handler = ngx_http_v2_pool_cleanup;
265
0
    cln->data = h2c;
266
267
0
    h2c->streams_index = ngx_pcalloc(c->pool, ngx_http_v2_index_size(h2scf)
268
0
                                              * sizeof(ngx_http_v2_node_t *));
269
0
    if (h2c->streams_index == NULL) {
270
0
        ngx_http_close_connection(c);
271
0
        return;
272
0
    }
273
274
0
    if (ngx_http_v2_send_settings(h2c) == NGX_ERROR) {
275
0
        ngx_http_close_connection(c);
276
0
        return;
277
0
    }
278
279
0
    if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW
280
0
                                               - NGX_HTTP_V2_DEFAULT_WINDOW)
281
0
        == NGX_ERROR)
282
0
    {
283
0
        ngx_http_close_connection(c);
284
0
        return;
285
0
    }
286
287
0
    h2c->state.handler = ngx_http_v2_state_preface;
288
289
0
    ngx_queue_init(&h2c->waiting);
290
0
    ngx_queue_init(&h2c->dependencies);
291
0
    ngx_queue_init(&h2c->closed);
292
293
0
    c->data = h2c;
294
295
0
    rev->handler = ngx_http_v2_read_handler;
296
0
    c->write->handler = ngx_http_v2_write_handler;
297
298
0
    if (!rev->timer_set) {
299
0
        cscf = ngx_http_get_module_srv_conf(hc->conf_ctx,
300
0
                                            ngx_http_core_module);
301
0
        ngx_add_timer(rev, cscf->client_header_timeout);
302
0
    }
303
304
0
    c->idle = 1;
305
0
    ngx_reusable_connection(c, 0);
306
307
0
    if (c->buffer) {
308
0
        p = c->buffer->pos;
309
0
        end = c->buffer->last;
310
311
0
        do {
312
0
            p = h2c->state.handler(h2c, p, end);
313
314
0
            if (p == NULL) {
315
0
                return;
316
0
            }
317
318
0
        } while (p != end);
319
320
0
        h2c->total_bytes += p - c->buffer->pos;
321
0
        c->buffer->pos = p;
322
0
    }
323
324
0
    ngx_http_v2_read_handler(rev);
325
0
}
326
327
328
static void
329
ngx_http_v2_read_handler(ngx_event_t *rev)
330
0
{
331
0
    u_char                    *p, *end;
332
0
    size_t                     available;
333
0
    ssize_t                    n;
334
0
    ngx_connection_t          *c;
335
0
    ngx_http_v2_main_conf_t   *h2mcf;
336
0
    ngx_http_v2_connection_t  *h2c;
337
338
0
    c = rev->data;
339
0
    h2c = c->data;
340
341
0
    if (rev->timedout) {
342
0
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
343
0
        ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
344
0
        return;
345
0
    }
346
347
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler");
348
349
0
    h2c->blocked = 1;
350
0
    h2c->new_streams = 0;
351
352
0
    if (c->close) {
353
0
        c->close = 0;
354
355
0
        if (c->error) {
356
0
            ngx_http_v2_finalize_connection(h2c, 0);
357
0
            return;
358
0
        }
359
360
0
        if (!h2c->processing) {
361
0
            ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
362
0
            return;
363
0
        }
364
365
0
        if (!h2c->goaway) {
366
0
            h2c->goaway = 1;
367
368
0
            if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR)
369
0
                == NGX_ERROR)
370
0
            {
371
0
                ngx_http_v2_finalize_connection(h2c, 0);
372
0
                return;
373
0
            }
374
375
0
            if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
376
0
                ngx_http_v2_finalize_connection(h2c, 0);
377
0
                return;
378
0
            }
379
0
        }
380
381
0
        h2c->blocked = 0;
382
383
0
        return;
384
0
    }
385
386
0
    h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx,
387
0
                                          ngx_http_v2_module);
388
389
0
    available = h2mcf->recv_buffer_size - NGX_HTTP_V2_STATE_BUFFER_SIZE;
390
391
0
    do {
392
0
        p = h2mcf->recv_buffer;
393
0
        end = ngx_cpymem(p, h2c->state.buffer, h2c->state.buffer_used);
394
395
0
        n = c->recv(c, end, available);
396
397
0
        if (n == NGX_AGAIN) {
398
0
            break;
399
0
        }
400
401
0
        if (n == 0 && (h2c->state.incomplete || h2c->processing)) {
402
0
            ngx_log_error(NGX_LOG_INFO, c->log, 0,
403
0
                          "client prematurely closed connection");
404
0
        }
405
406
0
        if (n == 0 || n == NGX_ERROR) {
407
0
            c->error = 1;
408
0
            ngx_http_v2_finalize_connection(h2c, 0);
409
0
            return;
410
0
        }
411
412
0
        end += n;
413
414
0
        h2c->state.buffer_used = 0;
415
0
        h2c->state.incomplete = 0;
416
417
0
        do {
418
0
            p = h2c->state.handler(h2c, p, end);
419
420
0
            if (p == NULL) {
421
0
                return;
422
0
            }
423
424
0
        } while (p != end);
425
426
0
        h2c->total_bytes += n;
427
428
0
        if (h2c->total_bytes / 8 > h2c->payload_bytes + 1048576) {
429
0
            ngx_log_error(NGX_LOG_INFO, c->log, 0, "http2 flood detected");
430
0
            ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
431
0
            return;
432
0
        }
433
434
0
    } while (rev->ready);
435
436
0
    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
437
0
        ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
438
0
        return;
439
0
    }
440
441
0
    if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
442
0
        ngx_http_v2_finalize_connection(h2c, 0);
443
0
        return;
444
0
    }
445
446
0
    h2c->blocked = 0;
447
448
0
    ngx_http_v2_handle_connection(h2c);
449
0
}
450
451
452
static void
453
ngx_http_v2_write_handler(ngx_event_t *wev)
454
0
{
455
0
    ngx_int_t                  rc;
456
0
    ngx_connection_t          *c;
457
0
    ngx_http_v2_connection_t  *h2c;
458
459
0
    c = wev->data;
460
0
    h2c = c->data;
461
462
0
    if (wev->timedout) {
463
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
464
0
                       "http2 write event timed out");
465
0
        c->error = 1;
466
0
        c->timedout = 1;
467
0
        ngx_http_v2_finalize_connection(h2c, 0);
468
0
        return;
469
0
    }
470
471
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler");
472
473
0
    if (h2c->last_out == NULL && !c->buffered) {
474
475
0
        if (wev->timer_set) {
476
0
            ngx_del_timer(wev);
477
0
        }
478
479
0
        ngx_http_v2_handle_connection(h2c);
480
0
        return;
481
0
    }
482
483
0
    h2c->blocked = 1;
484
485
0
    rc = ngx_http_v2_send_output_queue(h2c);
486
487
0
    if (rc == NGX_ERROR) {
488
0
        ngx_http_v2_finalize_connection(h2c, 0);
489
0
        return;
490
0
    }
491
492
0
    h2c->blocked = 0;
493
494
0
    if (rc == NGX_AGAIN) {
495
0
        return;
496
0
    }
497
498
0
    ngx_http_v2_handle_connection(h2c);
499
0
}
500
501
502
ngx_int_t
503
ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c)
504
0
{
505
0
    int                        tcp_nodelay;
506
0
    ngx_chain_t               *cl;
507
0
    ngx_event_t               *wev;
508
0
    ngx_connection_t          *c;
509
0
    ngx_http_v2_out_frame_t   *out, *frame, *fn;
510
0
    ngx_http_core_loc_conf_t  *clcf;
511
512
0
    c = h2c->connection;
513
0
    wev = c->write;
514
515
0
    if (c->error) {
516
0
        goto error;
517
0
    }
518
519
0
    if (!wev->ready) {
520
0
        return NGX_AGAIN;
521
0
    }
522
523
0
    cl = NULL;
524
0
    out = NULL;
525
526
0
    for (frame = h2c->last_out; frame; frame = fn) {
527
0
        frame->last->next = cl;
528
0
        cl = frame->first;
529
530
0
        fn = frame->next;
531
0
        frame->next = out;
532
0
        out = frame;
533
534
0
        ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
535
0
                       "http2 frame out: %p sid:%ui bl:%d len:%uz",
536
0
                       out, out->stream ? out->stream->node->id : 0,
537
0
                       out->blocked, out->length);
538
0
    }
539
540
0
    cl = c->send_chain(c, cl, 0);
541
542
0
    if (cl == NGX_CHAIN_ERROR) {
543
0
        goto error;
544
0
    }
545
546
0
    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
547
0
                                        ngx_http_core_module);
548
549
0
    if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
550
0
        goto error;
551
0
    }
552
553
0
    if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
554
0
        if (ngx_tcp_push(c->fd) == -1) {
555
0
            ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");
556
0
            goto error;
557
0
        }
558
559
0
        c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
560
0
        tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
561
562
0
    } else {
563
0
        tcp_nodelay = 1;
564
0
    }
565
566
0
    if (tcp_nodelay && clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
567
0
        goto error;
568
0
    }
569
570
0
    for ( /* void */ ; out; out = fn) {
571
0
        fn = out->next;
572
573
0
        if (out->handler(h2c, out) != NGX_OK) {
574
0
            out->blocked = 1;
575
0
            break;
576
0
        }
577
578
0
        ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
579
0
                       "http2 frame sent: %p sid:%ui bl:%d len:%uz",
580
0
                       out, out->stream ? out->stream->node->id : 0,
581
0
                       out->blocked, out->length);
582
0
    }
583
584
0
    frame = NULL;
585
586
0
    for ( /* void */ ; out; out = fn) {
587
0
        fn = out->next;
588
0
        out->next = frame;
589
0
        frame = out;
590
0
    }
591
592
0
    h2c->last_out = frame;
593
594
0
    if (!wev->ready) {
595
0
        ngx_add_timer(wev, clcf->send_timeout);
596
0
        return NGX_AGAIN;
597
0
    }
598
599
0
    if (wev->timer_set) {
600
0
        ngx_del_timer(wev);
601
0
    }
602
603
0
    return NGX_OK;
604
605
0
error:
606
607
0
    c->error = 1;
608
609
0
    if (!h2c->blocked) {
610
0
        ngx_post_event(wev, &ngx_posted_events);
611
0
    }
612
613
0
    return NGX_ERROR;
614
0
}
615
616
617
static void
618
ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
619
0
{
620
0
    ngx_int_t                  rc;
621
0
    ngx_connection_t          *c;
622
0
    ngx_http_core_loc_conf_t  *clcf;
623
624
0
    if (h2c->last_out || h2c->processing) {
625
0
        return;
626
0
    }
627
628
0
    c = h2c->connection;
629
630
0
    if (c->error) {
631
0
        ngx_http_close_connection(c);
632
0
        return;
633
0
    }
634
635
0
    if (c->buffered) {
636
0
        h2c->blocked = 1;
637
638
0
        rc = ngx_http_v2_send_output_queue(h2c);
639
640
0
        h2c->blocked = 0;
641
642
0
        if (rc == NGX_ERROR) {
643
0
            ngx_http_close_connection(c);
644
0
            return;
645
0
        }
646
647
0
        if (rc == NGX_AGAIN) {
648
0
            return;
649
0
        }
650
651
        /* rc == NGX_OK */
652
0
    }
653
654
0
    if (h2c->goaway) {
655
0
        ngx_http_v2_lingering_close(c);
656
0
        return;
657
0
    }
658
659
0
    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
660
0
                                        ngx_http_core_module);
661
662
0
    if (!c->read->timer_set) {
663
0
        ngx_add_timer(c->read, clcf->keepalive_timeout);
664
0
    }
665
666
0
    ngx_reusable_connection(c, 1);
667
668
0
    if (h2c->state.incomplete) {
669
0
        return;
670
0
    }
671
672
0
    ngx_destroy_pool(h2c->pool);
673
674
0
    h2c->pool = NULL;
675
0
    h2c->free_frames = NULL;
676
0
    h2c->frames = 0;
677
0
    h2c->free_fake_connections = NULL;
678
679
#if (NGX_HTTP_SSL)
680
    if (c->ssl) {
681
        ngx_ssl_free_buffer(c);
682
    }
683
#endif
684
685
0
    c->destroyed = 1;
686
687
0
    c->write->handler = ngx_http_empty_handler;
688
0
    c->read->handler = ngx_http_v2_idle_handler;
689
690
0
    if (c->write->timer_set) {
691
0
        ngx_del_timer(c->write);
692
0
    }
693
0
}
694
695
696
static void
697
ngx_http_v2_lingering_close(ngx_connection_t *c)
698
0
{
699
0
    ngx_event_t               *rev, *wev;
700
0
    ngx_http_v2_connection_t  *h2c;
701
0
    ngx_http_core_loc_conf_t  *clcf;
702
703
0
    h2c = c->data;
704
705
0
    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
706
0
                                        ngx_http_core_module);
707
708
0
    if (clcf->lingering_close == NGX_HTTP_LINGERING_OFF) {
709
0
        ngx_http_close_connection(c);
710
0
        return;
711
0
    }
712
713
0
    if (h2c->lingering_time == 0) {
714
0
        h2c->lingering_time = ngx_time()
715
0
                              + (time_t) (clcf->lingering_time / 1000);
716
0
    }
717
718
#if (NGX_HTTP_SSL)
719
    if (c->ssl) {
720
        ngx_int_t  rc;
721
722
        rc = ngx_ssl_shutdown(c);
723
724
        if (rc == NGX_ERROR) {
725
            ngx_http_close_connection(c);
726
            return;
727
        }
728
729
        if (rc == NGX_AGAIN) {
730
            c->ssl->handler = ngx_http_v2_lingering_close;
731
            return;
732
        }
733
    }
734
#endif
735
736
0
    rev = c->read;
737
0
    rev->handler = ngx_http_v2_lingering_close_handler;
738
739
0
    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
740
0
        ngx_http_close_connection(c);
741
0
        return;
742
0
    }
743
744
0
    wev = c->write;
745
0
    wev->handler = ngx_http_empty_handler;
746
747
0
    if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
748
0
        if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
749
0
            ngx_http_close_connection(c);
750
0
            return;
751
0
        }
752
0
    }
753
754
0
    if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
755
0
        ngx_connection_error(c, ngx_socket_errno,
756
0
                             ngx_shutdown_socket_n " failed");
757
0
        ngx_http_close_connection(c);
758
0
        return;
759
0
    }
760
761
0
    c->close = 0;
762
0
    ngx_reusable_connection(c, 1);
763
764
0
    ngx_add_timer(rev, clcf->lingering_timeout);
765
766
0
    if (rev->ready) {
767
0
        ngx_http_v2_lingering_close_handler(rev);
768
0
    }
769
0
}
770
771
772
static void
773
ngx_http_v2_lingering_close_handler(ngx_event_t *rev)
774
0
{
775
0
    ssize_t                    n;
776
0
    ngx_msec_t                 timer;
777
0
    ngx_connection_t          *c;
778
0
    ngx_http_core_loc_conf_t  *clcf;
779
0
    ngx_http_v2_connection_t  *h2c;
780
0
    u_char                     buffer[NGX_HTTP_LINGERING_BUFFER_SIZE];
781
782
0
    c = rev->data;
783
0
    h2c = c->data;
784
785
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
786
0
                   "http2 lingering close handler");
787
788
0
    if (rev->timedout || c->close) {
789
0
        ngx_http_close_connection(c);
790
0
        return;
791
0
    }
792
793
0
    timer = (ngx_msec_t) h2c->lingering_time - (ngx_msec_t) ngx_time();
794
0
    if ((ngx_msec_int_t) timer <= 0) {
795
0
        ngx_http_close_connection(c);
796
0
        return;
797
0
    }
798
799
0
    do {
800
0
        n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE);
801
802
0
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n);
803
804
0
        if (n == NGX_AGAIN) {
805
0
            break;
806
0
        }
807
808
0
        if (n == NGX_ERROR || n == 0) {
809
0
            ngx_http_close_connection(c);
810
0
            return;
811
0
        }
812
813
0
    } while (rev->ready);
814
815
0
    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
816
0
        ngx_http_close_connection(c);
817
0
        return;
818
0
    }
819
820
0
    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
821
0
                                        ngx_http_core_module);
822
0
    timer *= 1000;
823
824
0
    if (timer > clcf->lingering_timeout) {
825
0
        timer = clcf->lingering_timeout;
826
0
    }
827
828
0
    ngx_add_timer(rev, timer);
829
0
}
830
831
832
static u_char *
833
ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos,
834
    u_char *end)
835
0
{
836
0
    static const u_char preface[] = NGX_HTTP_V2_PREFACE_START;
837
838
0
    if ((size_t) (end - pos) < sizeof(preface) - 1) {
839
0
        return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_preface);
840
0
    }
841
842
0
    if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
843
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
844
0
                      "invalid connection preface");
845
846
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
847
0
    }
848
849
0
    return ngx_http_v2_state_preface_end(h2c, pos + sizeof(preface) - 1, end);
850
0
}
851
852
853
static u_char *
854
ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos,
855
    u_char *end)
856
0
{
857
0
    static const u_char preface[] = NGX_HTTP_V2_PREFACE_END;
858
859
0
    if ((size_t) (end - pos) < sizeof(preface) - 1) {
860
0
        return ngx_http_v2_state_save(h2c, pos, end,
861
0
                                      ngx_http_v2_state_preface_end);
862
0
    }
863
864
0
    if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
865
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
866
0
                      "invalid connection preface");
867
868
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
869
0
    }
870
871
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
872
0
                   "http2 preface verified");
873
874
0
    return ngx_http_v2_state_head(h2c, pos + sizeof(preface) - 1, end);
875
0
}
876
877
878
static u_char *
879
ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
880
0
{
881
0
    uint32_t    head;
882
0
    ngx_uint_t  type;
883
884
0
    if (end - pos < NGX_HTTP_V2_FRAME_HEADER_SIZE) {
885
0
        return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_head);
886
0
    }
887
888
0
    head = ngx_http_v2_parse_uint32(pos);
889
890
0
    h2c->state.length = ngx_http_v2_parse_length(head);
891
0
    h2c->state.flags = pos[4];
892
893
0
    h2c->state.sid = ngx_http_v2_parse_sid(&pos[5]);
894
895
0
    pos += NGX_HTTP_V2_FRAME_HEADER_SIZE;
896
897
0
    type = ngx_http_v2_parse_type(head);
898
899
0
    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
900
0
                   "http2 frame type:%ui f:%Xd l:%uz sid:%ui",
901
0
                   type, h2c->state.flags, h2c->state.length, h2c->state.sid);
902
903
0
    if (type >= NGX_HTTP_V2_FRAME_STATES) {
904
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
905
0
                      "client sent frame with unknown type %ui", type);
906
0
        return ngx_http_v2_state_skip(h2c, pos, end);
907
0
    }
908
909
0
    return ngx_http_v2_frame_states[type](h2c, pos, end);
910
0
}
911
912
913
static u_char *
914
ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
915
0
{
916
0
    size_t                 size;
917
0
    ngx_http_v2_node_t    *node;
918
0
    ngx_http_v2_stream_t  *stream;
919
920
0
    size = h2c->state.length;
921
922
0
    if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) {
923
924
0
        if (h2c->state.length == 0) {
925
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
926
0
                          "client sent padded DATA frame "
927
0
                          "with incorrect length: 0");
928
929
0
            return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
930
0
        }
931
932
0
        if (end - pos == 0) {
933
0
            return ngx_http_v2_state_save(h2c, pos, end,
934
0
                                          ngx_http_v2_state_data);
935
0
        }
936
937
0
        h2c->state.padding = *pos++;
938
939
0
        if (h2c->state.padding >= size) {
940
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
941
0
                          "client sent padded DATA frame "
942
0
                          "with incorrect length: %uz, padding: %uz",
943
0
                          size, h2c->state.padding);
944
945
0
            return ngx_http_v2_connection_error(h2c,
946
0
                                                NGX_HTTP_V2_PROTOCOL_ERROR);
947
0
        }
948
949
0
        h2c->state.length -= 1 + h2c->state.padding;
950
0
    }
951
952
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
953
0
                   "http2 DATA frame");
954
955
0
    if (h2c->state.sid == 0) {
956
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
957
0
                      "client sent DATA frame with incorrect identifier");
958
959
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
960
0
    }
961
962
0
    if (size > h2c->recv_window) {
963
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
964
0
                      "client violated connection flow control: "
965
0
                      "received DATA frame length %uz, available window %uz",
966
0
                      size, h2c->recv_window);
967
968
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
969
0
    }
970
971
0
    h2c->recv_window -= size;
972
973
0
    if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {
974
975
0
        if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW
976
0
                                                   - h2c->recv_window)
977
0
            == NGX_ERROR)
978
0
        {
979
0
            return ngx_http_v2_connection_error(h2c,
980
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
981
0
        }
982
983
0
        h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;
984
0
    }
985
986
0
    node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
987
988
0
    if (node == NULL || node->stream == NULL) {
989
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
990
0
                       "unknown http2 stream");
991
992
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
993
0
    }
994
995
0
    stream = node->stream;
996
997
0
    if (size > stream->recv_window) {
998
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
999
0
                      "client violated flow control for stream %ui: "
1000
0
                      "received DATA frame length %uz, available window %uz",
1001
0
                      node->id, size, stream->recv_window);
1002
1003
0
        if (ngx_http_v2_terminate_stream(h2c, stream,
1004
0
                                         NGX_HTTP_V2_FLOW_CTRL_ERROR)
1005
0
            == NGX_ERROR)
1006
0
        {
1007
0
            return ngx_http_v2_connection_error(h2c,
1008
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1009
0
        }
1010
1011
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1012
0
    }
1013
1014
0
    stream->recv_window -= size;
1015
1016
0
    if (stream->no_flow_control
1017
0
        && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
1018
0
    {
1019
0
        if (ngx_http_v2_send_window_update(h2c, node->id,
1020
0
                                           NGX_HTTP_V2_MAX_WINDOW
1021
0
                                           - stream->recv_window)
1022
0
            == NGX_ERROR)
1023
0
        {
1024
0
            return ngx_http_v2_connection_error(h2c,
1025
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1026
0
        }
1027
1028
0
        stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;
1029
0
    }
1030
1031
0
    if (stream->in_closed) {
1032
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1033
0
                      "client sent DATA frame for half-closed stream %ui",
1034
0
                      node->id);
1035
1036
0
        if (ngx_http_v2_terminate_stream(h2c, stream,
1037
0
                                         NGX_HTTP_V2_STREAM_CLOSED)
1038
0
            == NGX_ERROR)
1039
0
        {
1040
0
            return ngx_http_v2_connection_error(h2c,
1041
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1042
0
        }
1043
1044
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1045
0
    }
1046
1047
0
    h2c->state.stream = stream;
1048
1049
0
    return ngx_http_v2_state_read_data(h2c, pos, end);
1050
0
}
1051
1052
1053
static u_char *
1054
ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
1055
    u_char *end)
1056
0
{
1057
0
    size_t                   size;
1058
0
    ngx_buf_t               *buf;
1059
0
    ngx_int_t                rc;
1060
0
    ngx_connection_t        *fc;
1061
0
    ngx_http_request_t      *r;
1062
0
    ngx_http_v2_stream_t    *stream;
1063
0
    ngx_http_v2_srv_conf_t  *h2scf;
1064
1065
0
    stream = h2c->state.stream;
1066
1067
0
    if (stream == NULL) {
1068
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1069
0
    }
1070
1071
0
    if (stream->skip_data) {
1072
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1073
0
                       "skipping http2 DATA frame");
1074
1075
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1076
0
    }
1077
1078
0
    r = stream->request;
1079
0
    fc = r->connection;
1080
1081
0
    if (r->reading_body && !r->request_body_no_buffering) {
1082
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1083
0
                       "skipping http2 DATA frame");
1084
1085
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1086
0
    }
1087
1088
0
    if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
1089
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1090
0
                       "skipping http2 DATA frame");
1091
1092
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1093
0
    }
1094
1095
0
    size = end - pos;
1096
1097
0
    if (size >= h2c->state.length) {
1098
0
        size = h2c->state.length;
1099
0
        stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
1100
0
    }
1101
1102
0
    h2c->payload_bytes += size;
1103
1104
0
    if (r->request_body) {
1105
0
        rc = ngx_http_v2_process_request_body(r, pos, size,
1106
0
                                              stream->in_closed, 0);
1107
1108
0
        if (rc != NGX_OK && rc != NGX_AGAIN) {
1109
0
            stream->skip_data = 1;
1110
0
            ngx_http_finalize_request(r, rc);
1111
0
        }
1112
1113
0
        ngx_http_run_posted_requests(fc);
1114
1115
0
    } else if (size) {
1116
0
        buf = stream->preread;
1117
1118
0
        if (buf == NULL) {
1119
0
            h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
1120
1121
0
            buf = ngx_create_temp_buf(r->pool, h2scf->preread_size);
1122
0
            if (buf == NULL) {
1123
0
                return ngx_http_v2_connection_error(h2c,
1124
0
                                                    NGX_HTTP_V2_INTERNAL_ERROR);
1125
0
            }
1126
1127
0
            stream->preread = buf;
1128
0
        }
1129
1130
0
        if (size > (size_t) (buf->end - buf->last)) {
1131
0
            ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
1132
0
                          "http2 preread buffer overflow");
1133
0
            return ngx_http_v2_connection_error(h2c,
1134
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1135
0
        }
1136
1137
0
        buf->last = ngx_cpymem(buf->last, pos, size);
1138
0
    }
1139
1140
0
    pos += size;
1141
0
    h2c->state.length -= size;
1142
1143
0
    if (h2c->state.length) {
1144
0
        return ngx_http_v2_state_save(h2c, pos, end,
1145
0
                                      ngx_http_v2_state_read_data);
1146
0
    }
1147
1148
0
    if (h2c->state.padding) {
1149
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1150
0
    }
1151
1152
0
    return ngx_http_v2_state_complete(h2c, pos, end);
1153
0
}
1154
1155
1156
static u_char *
1157
ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
1158
    u_char *end)
1159
0
{
1160
0
    size_t                     size;
1161
0
    ngx_uint_t                 padded, priority, depend, dependency, excl,
1162
0
                               weight;
1163
0
    ngx_uint_t                 status;
1164
0
    ngx_http_v2_node_t        *node;
1165
0
    ngx_http_v2_stream_t      *stream;
1166
0
    ngx_http_v2_srv_conf_t    *h2scf;
1167
0
    ngx_http_core_srv_conf_t  *cscf;
1168
0
    ngx_http_core_loc_conf_t  *clcf;
1169
1170
0
    padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG;
1171
0
    priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG;
1172
1173
0
    size = 0;
1174
1175
0
    if (padded) {
1176
0
        size++;
1177
0
    }
1178
1179
0
    if (priority) {
1180
0
        size += sizeof(uint32_t) + 1;
1181
0
    }
1182
1183
0
    if (h2c->state.length < size) {
1184
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1185
0
                      "client sent HEADERS frame with incorrect length %uz",
1186
0
                      h2c->state.length);
1187
1188
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1189
0
    }
1190
1191
0
    if (h2c->state.length == size) {
1192
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1193
0
                      "client sent HEADERS frame with empty header block");
1194
1195
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1196
0
    }
1197
1198
0
    if (h2c->goaway) {
1199
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1200
0
                       "skipping http2 HEADERS frame");
1201
0
        return ngx_http_v2_state_skip(h2c, pos, end);
1202
0
    }
1203
1204
0
    if ((size_t) (end - pos) < size) {
1205
0
        return ngx_http_v2_state_save(h2c, pos, end,
1206
0
                                      ngx_http_v2_state_headers);
1207
0
    }
1208
1209
0
    h2c->state.length -= size;
1210
1211
0
    if (padded) {
1212
0
        h2c->state.padding = *pos++;
1213
1214
0
        if (h2c->state.padding > h2c->state.length) {
1215
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1216
0
                          "client sent padded HEADERS frame "
1217
0
                          "with incorrect length: %uz, padding: %uz",
1218
0
                          h2c->state.length, h2c->state.padding);
1219
1220
0
            return ngx_http_v2_connection_error(h2c,
1221
0
                                                NGX_HTTP_V2_PROTOCOL_ERROR);
1222
0
        }
1223
1224
0
        h2c->state.length -= h2c->state.padding;
1225
0
    }
1226
1227
0
    depend = 0;
1228
0
    excl = 0;
1229
0
    weight = NGX_HTTP_V2_DEFAULT_WEIGHT;
1230
1231
0
    if (priority) {
1232
0
        dependency = ngx_http_v2_parse_uint32(pos);
1233
1234
0
        depend = dependency & 0x7fffffff;
1235
0
        excl = dependency >> 31;
1236
0
        weight = pos[4] + 1;
1237
1238
0
        pos += sizeof(uint32_t) + 1;
1239
0
    }
1240
1241
0
    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1242
0
                   "http2 HEADERS frame sid:%ui "
1243
0
                   "depends on %ui excl:%ui weight:%ui",
1244
0
                   h2c->state.sid, depend, excl, weight);
1245
1246
0
    if (h2c->state.sid % 2 == 0 || h2c->state.sid <= h2c->last_sid) {
1247
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1248
0
                      "client sent HEADERS frame with incorrect identifier "
1249
0
                      "%ui, the last was %ui", h2c->state.sid, h2c->last_sid);
1250
1251
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1252
0
    }
1253
1254
0
    if (depend == h2c->state.sid) {
1255
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1256
0
                      "client sent HEADERS frame for stream %ui "
1257
0
                      "with incorrect dependency", h2c->state.sid);
1258
1259
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1260
0
    }
1261
1262
0
    h2c->last_sid = h2c->state.sid;
1263
1264
0
    h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
1265
0
    if (h2c->state.pool == NULL) {
1266
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1267
0
    }
1268
1269
0
    cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1270
0
                                        ngx_http_core_module);
1271
1272
0
    h2c->state.header_limit = cscf->large_client_header_buffers.size
1273
0
                              * cscf->large_client_header_buffers.num;
1274
1275
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1276
0
                                         ngx_http_v2_module);
1277
1278
0
    if (h2c->processing >= h2scf->concurrent_streams) {
1279
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1280
0
                      "concurrent streams exceeded %ui", h2c->processing);
1281
1282
0
        status = NGX_HTTP_V2_REFUSED_STREAM;
1283
0
        goto rst_stream;
1284
0
    }
1285
1286
0
    if (h2c->new_streams++ >= 2 * h2scf->concurrent_streams) {
1287
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1288
0
                      "client sent too many streams at once");
1289
1290
0
        status = NGX_HTTP_V2_REFUSED_STREAM;
1291
0
        goto rst_stream;
1292
0
    }
1293
1294
0
    if (!h2c->settings_ack
1295
0
        && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
1296
0
        && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
1297
0
    {
1298
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1299
0
                      "client sent stream with data "
1300
0
                      "before settings were acknowledged");
1301
1302
0
        status = NGX_HTTP_V2_REFUSED_STREAM;
1303
0
        goto rst_stream;
1304
0
    }
1305
1306
0
    node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
1307
1308
0
    if (node == NULL) {
1309
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1310
0
    }
1311
1312
0
    if (node->parent) {
1313
0
        ngx_queue_remove(&node->reuse);
1314
0
        h2c->closed_nodes--;
1315
0
    }
1316
1317
0
    stream = ngx_http_v2_create_stream(h2c);
1318
0
    if (stream == NULL) {
1319
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1320
0
    }
1321
1322
0
    h2c->state.stream = stream;
1323
1324
0
    stream->pool = h2c->state.pool;
1325
0
    h2c->state.keep_pool = 1;
1326
1327
0
    stream->request->request_length = h2c->state.length;
1328
1329
0
    stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
1330
0
    stream->node = node;
1331
1332
0
    node->stream = stream;
1333
1334
0
    if (priority || node->parent == NULL) {
1335
0
        node->weight = weight;
1336
0
        ngx_http_v2_set_dependency(h2c, node, depend, excl);
1337
0
    }
1338
1339
0
    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
1340
0
                                        ngx_http_core_module);
1341
1342
0
    if (clcf->keepalive_timeout == 0
1343
0
        || h2c->connection->requests >= clcf->keepalive_requests
1344
0
        || ngx_current_msec - h2c->connection->start_time
1345
0
           > clcf->keepalive_time)
1346
0
    {
1347
0
        h2c->goaway = 1;
1348
1349
0
        if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) {
1350
0
            return ngx_http_v2_connection_error(h2c,
1351
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1352
0
        }
1353
0
    }
1354
1355
0
    return ngx_http_v2_state_header_block(h2c, pos, end);
1356
1357
0
rst_stream:
1358
1359
0
    if (h2c->refused_streams++ > ngx_max(h2scf->concurrent_streams, 100)) {
1360
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1361
0
                      "client sent too many refused streams");
1362
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_NO_ERROR);
1363
0
    }
1364
1365
0
    if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) {
1366
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1367
0
    }
1368
1369
0
    return ngx_http_v2_state_header_block(h2c, pos, end);
1370
0
}
1371
1372
1373
static u_char *
1374
ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos,
1375
    u_char *end)
1376
0
{
1377
0
    u_char      ch;
1378
0
    ngx_int_t   value;
1379
0
    ngx_uint_t  indexed, size_update, prefix;
1380
1381
0
    if (end - pos < 1) {
1382
0
        return ngx_http_v2_state_headers_save(h2c, pos, end,
1383
0
                                              ngx_http_v2_state_header_block);
1384
0
    }
1385
1386
0
    if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
1387
0
        && h2c->state.length < NGX_HTTP_V2_INT_OCTETS)
1388
0
    {
1389
0
        return ngx_http_v2_handle_continuation(h2c, pos, end,
1390
0
                                               ngx_http_v2_state_header_block);
1391
0
    }
1392
1393
0
    size_update = 0;
1394
0
    indexed = 0;
1395
1396
0
    ch = *pos;
1397
1398
0
    if (ch >= (1 << 7)) {
1399
        /* indexed header field */
1400
0
        indexed = 1;
1401
0
        prefix = ngx_http_v2_prefix(7);
1402
1403
0
    } else if (ch >= (1 << 6)) {
1404
        /* literal header field with incremental indexing */
1405
0
        h2c->state.index = 1;
1406
0
        prefix = ngx_http_v2_prefix(6);
1407
1408
0
    } else if (ch >= (1 << 5)) {
1409
        /* dynamic table size update */
1410
0
        size_update = 1;
1411
0
        prefix = ngx_http_v2_prefix(5);
1412
1413
0
    } else if (ch >= (1 << 4)) {
1414
        /* literal header field never indexed */
1415
0
        prefix = ngx_http_v2_prefix(4);
1416
1417
0
    } else {
1418
        /* literal header field without indexing */
1419
0
        prefix = ngx_http_v2_prefix(4);
1420
0
    }
1421
1422
0
    value = ngx_http_v2_parse_int(h2c, &pos, end, prefix);
1423
1424
0
    if (value < 0) {
1425
0
        if (value == NGX_AGAIN) {
1426
0
            return ngx_http_v2_state_headers_save(h2c, pos, end,
1427
0
                                               ngx_http_v2_state_header_block);
1428
0
        }
1429
1430
0
        if (value == NGX_DECLINED) {
1431
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1432
0
                          "client sent header block with too long %s value",
1433
0
                          size_update ? "size update" : "header index");
1434
1435
0
            return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1436
0
        }
1437
1438
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1439
0
                      "client sent header block with incorrect length");
1440
1441
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1442
0
    }
1443
1444
0
    if (indexed) {
1445
0
        if (ngx_http_v2_get_indexed_header(h2c, value, 0) != NGX_OK) {
1446
0
            return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1447
0
        }
1448
1449
0
        return ngx_http_v2_state_process_header(h2c, pos, end);
1450
0
    }
1451
1452
0
    if (size_update) {
1453
0
        if (ngx_http_v2_table_size(h2c, value) != NGX_OK) {
1454
0
            return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1455
0
        }
1456
1457
0
        return ngx_http_v2_state_header_complete(h2c, pos, end);
1458
0
    }
1459
1460
0
    if (value == 0) {
1461
0
        h2c->state.parse_name = 1;
1462
1463
0
    } else if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) {
1464
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1465
0
    }
1466
1467
0
    h2c->state.parse_value = 1;
1468
1469
0
    return ngx_http_v2_state_field_len(h2c, pos, end);
1470
0
}
1471
1472
1473
static u_char *
1474
ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos,
1475
    u_char *end)
1476
0
{
1477
0
    size_t                     alloc;
1478
0
    ngx_int_t                  len;
1479
0
    ngx_uint_t                 huff;
1480
0
    ngx_http_core_srv_conf_t  *cscf;
1481
1482
0
    if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
1483
0
        && h2c->state.length < NGX_HTTP_V2_INT_OCTETS)
1484
0
    {
1485
0
        return ngx_http_v2_handle_continuation(h2c, pos, end,
1486
0
                                               ngx_http_v2_state_field_len);
1487
0
    }
1488
1489
0
    if (h2c->state.length < 1) {
1490
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1491
0
                      "client sent header block with incorrect length");
1492
1493
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1494
0
    }
1495
1496
0
    if (end - pos < 1) {
1497
0
        return ngx_http_v2_state_headers_save(h2c, pos, end,
1498
0
                                              ngx_http_v2_state_field_len);
1499
0
    }
1500
1501
0
    huff = *pos >> 7;
1502
0
    len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7));
1503
1504
0
    if (len < 0) {
1505
0
        if (len == NGX_AGAIN) {
1506
0
            return ngx_http_v2_state_headers_save(h2c, pos, end,
1507
0
                                                  ngx_http_v2_state_field_len);
1508
0
        }
1509
1510
0
        if (len == NGX_DECLINED) {
1511
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1512
0
                        "client sent header field with too long length value");
1513
1514
0
            return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1515
0
        }
1516
1517
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1518
0
                      "client sent header block with incorrect length");
1519
1520
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1521
0
    }
1522
1523
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1524
0
                   "http2 %s string, len:%i",
1525
0
                   huff ? "encoded" : "raw", len);
1526
1527
0
    cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1528
0
                                        ngx_http_core_module);
1529
1530
0
    if ((size_t) len > cscf->large_client_header_buffers.size) {
1531
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1532
0
                      "client sent too large header field");
1533
1534
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1535
0
    }
1536
1537
0
    h2c->state.field_rest = len;
1538
1539
0
    if (h2c->state.stream == NULL && !h2c->state.index) {
1540
0
        return ngx_http_v2_state_field_skip(h2c, pos, end);
1541
0
    }
1542
1543
0
    alloc = (huff ? len * 8 / 5 : len) + 1;
1544
1545
0
    h2c->state.field_start = ngx_pnalloc(h2c->state.pool, alloc);
1546
0
    if (h2c->state.field_start == NULL) {
1547
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1548
0
    }
1549
1550
0
    h2c->state.field_end = h2c->state.field_start;
1551
1552
0
    if (huff) {
1553
0
        return ngx_http_v2_state_field_huff(h2c, pos, end);
1554
0
    }
1555
1556
0
    return ngx_http_v2_state_field_raw(h2c, pos, end);
1557
0
}
1558
1559
1560
static u_char *
1561
ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos,
1562
    u_char *end)
1563
0
{
1564
0
    size_t  size;
1565
1566
0
    size = end - pos;
1567
1568
0
    if (size > h2c->state.field_rest) {
1569
0
        size = h2c->state.field_rest;
1570
0
    }
1571
1572
0
    if (size > h2c->state.length) {
1573
0
        size = h2c->state.length;
1574
0
    }
1575
1576
0
    h2c->state.length -= size;
1577
0
    h2c->state.field_rest -= size;
1578
1579
0
    if (ngx_http_huff_decode(&h2c->state.field_state, pos, size,
1580
0
                             &h2c->state.field_end,
1581
0
                             h2c->state.field_rest == 0,
1582
0
                             h2c->connection->log)
1583
0
        != NGX_OK)
1584
0
    {
1585
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1586
0
                      "client sent invalid encoded header field");
1587
1588
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1589
0
    }
1590
1591
0
    pos += size;
1592
1593
0
    if (h2c->state.field_rest == 0) {
1594
0
        *h2c->state.field_end = '\0';
1595
0
        return ngx_http_v2_state_process_header(h2c, pos, end);
1596
0
    }
1597
1598
0
    if (h2c->state.length) {
1599
0
        return ngx_http_v2_state_headers_save(h2c, pos, end,
1600
0
                                              ngx_http_v2_state_field_huff);
1601
0
    }
1602
1603
0
    if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1604
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1605
0
                      "client sent header field with incorrect length");
1606
1607
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1608
0
    }
1609
1610
0
    return ngx_http_v2_handle_continuation(h2c, pos, end,
1611
0
                                           ngx_http_v2_state_field_huff);
1612
0
}
1613
1614
1615
static u_char *
1616
ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, u_char *pos,
1617
    u_char *end)
1618
0
{
1619
0
    size_t  size;
1620
1621
0
    size = end - pos;
1622
1623
0
    if (size > h2c->state.field_rest) {
1624
0
        size = h2c->state.field_rest;
1625
0
    }
1626
1627
0
    if (size > h2c->state.length) {
1628
0
        size = h2c->state.length;
1629
0
    }
1630
1631
0
    h2c->state.length -= size;
1632
0
    h2c->state.field_rest -= size;
1633
1634
0
    h2c->state.field_end = ngx_cpymem(h2c->state.field_end, pos, size);
1635
1636
0
    pos += size;
1637
1638
0
    if (h2c->state.field_rest == 0) {
1639
0
        *h2c->state.field_end = '\0';
1640
0
        return ngx_http_v2_state_process_header(h2c, pos, end);
1641
0
    }
1642
1643
0
    if (h2c->state.length) {
1644
0
        return ngx_http_v2_state_headers_save(h2c, pos, end,
1645
0
                                              ngx_http_v2_state_field_raw);
1646
0
    }
1647
1648
0
    if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1649
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1650
0
                      "client sent header field with incorrect length");
1651
1652
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1653
0
    }
1654
1655
0
    return ngx_http_v2_handle_continuation(h2c, pos, end,
1656
0
                                           ngx_http_v2_state_field_raw);
1657
0
}
1658
1659
1660
static u_char *
1661
ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, u_char *pos,
1662
    u_char *end)
1663
0
{
1664
0
    size_t  size;
1665
1666
0
    size = end - pos;
1667
1668
0
    if (size > h2c->state.field_rest) {
1669
0
        size = h2c->state.field_rest;
1670
0
    }
1671
1672
0
    if (size > h2c->state.length) {
1673
0
        size = h2c->state.length;
1674
0
    }
1675
1676
0
    h2c->state.length -= size;
1677
0
    h2c->state.field_rest -= size;
1678
1679
0
    pos += size;
1680
1681
0
    if (h2c->state.field_rest == 0) {
1682
0
        return ngx_http_v2_state_process_header(h2c, pos, end);
1683
0
    }
1684
1685
0
    if (h2c->state.length) {
1686
0
        return ngx_http_v2_state_save(h2c, pos, end,
1687
0
                                      ngx_http_v2_state_field_skip);
1688
0
    }
1689
1690
0
    if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1691
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1692
0
                      "client sent header field with incorrect length");
1693
1694
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1695
0
    }
1696
1697
0
    return ngx_http_v2_handle_continuation(h2c, pos, end,
1698
0
                                           ngx_http_v2_state_field_skip);
1699
0
}
1700
1701
1702
static u_char *
1703
ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
1704
    u_char *end)
1705
0
{
1706
0
    size_t                      len;
1707
0
    ngx_int_t                   rc;
1708
0
    ngx_table_elt_t            *h;
1709
0
    ngx_connection_t           *fc;
1710
0
    ngx_http_header_t          *hh;
1711
0
    ngx_http_request_t         *r;
1712
0
    ngx_http_v2_header_t       *header;
1713
0
    ngx_http_core_srv_conf_t   *cscf;
1714
0
    ngx_http_core_main_conf_t  *cmcf;
1715
1716
0
    static ngx_str_t cookie = ngx_string("cookie");
1717
1718
0
    header = &h2c->state.header;
1719
1720
0
    if (h2c->state.parse_name) {
1721
0
        h2c->state.parse_name = 0;
1722
1723
0
        header->name.len = h2c->state.field_end - h2c->state.field_start;
1724
0
        header->name.data = h2c->state.field_start;
1725
1726
0
        if (header->name.len == 0) {
1727
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1728
0
                          "client sent zero header name length");
1729
1730
0
            return ngx_http_v2_connection_error(h2c,
1731
0
                                                NGX_HTTP_V2_PROTOCOL_ERROR);
1732
0
        }
1733
1734
0
        return ngx_http_v2_state_field_len(h2c, pos, end);
1735
0
    }
1736
1737
0
    if (h2c->state.parse_value) {
1738
0
        h2c->state.parse_value = 0;
1739
1740
0
        header->value.len = h2c->state.field_end - h2c->state.field_start;
1741
0
        header->value.data = h2c->state.field_start;
1742
0
    }
1743
1744
0
    len = header->name.len + header->value.len;
1745
1746
0
    if (len > h2c->state.header_limit) {
1747
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1748
0
                      "client sent too large header");
1749
1750
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1751
0
    }
1752
1753
0
    h2c->state.header_limit -= len;
1754
1755
0
    if (h2c->state.index) {
1756
0
        if (ngx_http_v2_add_header(h2c, header) != NGX_OK) {
1757
0
            return ngx_http_v2_connection_error(h2c,
1758
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1759
0
        }
1760
1761
0
        h2c->state.index = 0;
1762
0
    }
1763
1764
0
    if (h2c->state.stream == NULL) {
1765
0
        return ngx_http_v2_state_header_complete(h2c, pos, end);
1766
0
    }
1767
1768
0
    r = h2c->state.stream->request;
1769
0
    fc = r->connection;
1770
1771
    /* TODO Optimization: validate headers while parsing. */
1772
0
    if (ngx_http_v2_validate_header(r, header) != NGX_OK) {
1773
0
        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1774
0
        goto error;
1775
0
    }
1776
1777
0
    if (header->name.data[0] == ':') {
1778
0
        rc = ngx_http_v2_pseudo_header(r, header);
1779
1780
0
        if (rc == NGX_OK) {
1781
0
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1782
0
                           "http2 header: \":%V: %V\"",
1783
0
                           &header->name, &header->value);
1784
1785
0
            return ngx_http_v2_state_header_complete(h2c, pos, end);
1786
0
        }
1787
1788
0
        if (rc == NGX_ABORT) {
1789
0
            goto error;
1790
0
        }
1791
1792
0
        if (rc == NGX_DECLINED) {
1793
0
            ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1794
0
            goto error;
1795
0
        }
1796
1797
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1798
0
    }
1799
1800
0
    if (r->invalid_header) {
1801
0
        cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1802
1803
0
        if (cscf->ignore_invalid_headers) {
1804
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1805
0
                          "client sent invalid header: \"%V\"", &header->name);
1806
1807
0
            return ngx_http_v2_state_header_complete(h2c, pos, end);
1808
0
        }
1809
0
    }
1810
1811
0
    if (header->name.len == cookie.len
1812
0
        && ngx_memcmp(header->name.data, cookie.data, cookie.len) == 0)
1813
0
    {
1814
0
        if (ngx_http_v2_cookie(r, header) != NGX_OK) {
1815
0
            return ngx_http_v2_connection_error(h2c,
1816
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1817
0
        }
1818
1819
0
    } else {
1820
0
        h = ngx_list_push(&r->headers_in.headers);
1821
0
        if (h == NULL) {
1822
0
            return ngx_http_v2_connection_error(h2c,
1823
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
1824
0
        }
1825
1826
0
        h->key.len = header->name.len;
1827
0
        h->key.data = header->name.data;
1828
1829
        /*
1830
         * TODO Optimization: precalculate hash
1831
         * and handler for indexed headers.
1832
         */
1833
0
        h->hash = ngx_hash_key(h->key.data, h->key.len);
1834
1835
0
        h->value.len = header->value.len;
1836
0
        h->value.data = header->value.data;
1837
1838
0
        h->lowcase_key = h->key.data;
1839
1840
0
        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1841
1842
0
        hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1843
0
                           h->lowcase_key, h->key.len);
1844
1845
0
        if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1846
0
            goto error;
1847
0
        }
1848
0
    }
1849
1850
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1851
0
                   "http2 header: \"%V: %V\"",
1852
0
                   &header->name, &header->value);
1853
1854
0
    return ngx_http_v2_state_header_complete(h2c, pos, end);
1855
1856
0
error:
1857
1858
0
    h2c->state.stream = NULL;
1859
1860
0
    ngx_http_run_posted_requests(fc);
1861
1862
0
    return ngx_http_v2_state_header_complete(h2c, pos, end);
1863
0
}
1864
1865
1866
static u_char *
1867
ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
1868
    u_char *end)
1869
0
{
1870
0
    ngx_http_v2_stream_t  *stream;
1871
1872
0
    if (h2c->state.length) {
1873
0
        if (end - pos > 0) {
1874
0
            h2c->state.handler = ngx_http_v2_state_header_block;
1875
0
            return pos;
1876
0
        }
1877
1878
0
        return ngx_http_v2_state_headers_save(h2c, pos, end,
1879
0
                                              ngx_http_v2_state_header_block);
1880
0
    }
1881
1882
0
    if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) {
1883
0
        return ngx_http_v2_handle_continuation(h2c, pos, end,
1884
0
                                             ngx_http_v2_state_header_complete);
1885
0
    }
1886
1887
0
    stream = h2c->state.stream;
1888
1889
0
    if (stream) {
1890
0
        ngx_http_v2_run_request(stream->request);
1891
0
    }
1892
1893
0
    if (!h2c->state.keep_pool) {
1894
0
        ngx_destroy_pool(h2c->state.pool);
1895
0
    }
1896
1897
0
    h2c->state.pool = NULL;
1898
0
    h2c->state.keep_pool = 0;
1899
1900
0
    if (h2c->state.padding) {
1901
0
        return ngx_http_v2_state_skip_padded(h2c, pos, end);
1902
0
    }
1903
1904
0
    return ngx_http_v2_state_complete(h2c, pos, end);
1905
0
}
1906
1907
1908
static u_char *
1909
ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos,
1910
    u_char *end, ngx_http_v2_handler_pt handler)
1911
0
{
1912
0
    u_char    *p;
1913
0
    size_t     len, skip;
1914
0
    uint32_t   head;
1915
1916
0
    len = h2c->state.length;
1917
1918
0
    if (h2c->state.padding && (size_t) (end - pos) > len) {
1919
0
        skip = ngx_min(h2c->state.padding, (end - pos) - len);
1920
1921
0
        h2c->state.padding -= skip;
1922
1923
0
        p = pos;
1924
0
        pos += skip;
1925
0
        ngx_memmove(pos, p, len);
1926
0
    }
1927
1928
0
    if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) {
1929
0
        return ngx_http_v2_state_headers_save(h2c, pos, end, handler);
1930
0
    }
1931
1932
0
    p = pos + len;
1933
1934
0
    head = ngx_http_v2_parse_uint32(p);
1935
1936
0
    if (ngx_http_v2_parse_type(head) != NGX_HTTP_V2_CONTINUATION_FRAME) {
1937
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1938
0
             "client sent inappropriate frame while CONTINUATION was expected");
1939
1940
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1941
0
    }
1942
1943
0
    h2c->state.flags |= p[4];
1944
1945
0
    if (h2c->state.sid != ngx_http_v2_parse_sid(&p[5])) {
1946
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1947
0
                    "client sent CONTINUATION frame with incorrect identifier");
1948
1949
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1950
0
    }
1951
1952
0
    p = pos;
1953
0
    pos += NGX_HTTP_V2_FRAME_HEADER_SIZE;
1954
1955
0
    ngx_memcpy(pos, p, len);
1956
1957
0
    len = ngx_http_v2_parse_length(head);
1958
1959
0
    h2c->state.length += len;
1960
1961
0
    if (h2c->state.stream) {
1962
0
        h2c->state.stream->request->request_length += len;
1963
0
    }
1964
1965
0
    h2c->state.handler = handler;
1966
0
    return pos;
1967
0
}
1968
1969
1970
static u_char *
1971
ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
1972
    u_char *end)
1973
0
{
1974
0
    ngx_uint_t           depend, dependency, excl, weight;
1975
0
    ngx_http_v2_node_t  *node;
1976
1977
0
    if (h2c->state.length != NGX_HTTP_V2_PRIORITY_SIZE) {
1978
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1979
0
                      "client sent PRIORITY frame with incorrect length %uz",
1980
0
                      h2c->state.length);
1981
1982
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1983
0
    }
1984
1985
0
    if (--h2c->priority_limit == 0) {
1986
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1987
0
                      "client sent too many PRIORITY frames");
1988
1989
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1990
0
    }
1991
1992
0
    if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) {
1993
0
        return ngx_http_v2_state_save(h2c, pos, end,
1994
0
                                      ngx_http_v2_state_priority);
1995
0
    }
1996
1997
0
    dependency = ngx_http_v2_parse_uint32(pos);
1998
1999
0
    depend = dependency & 0x7fffffff;
2000
0
    excl = dependency >> 31;
2001
0
    weight = pos[4] + 1;
2002
2003
0
    pos += NGX_HTTP_V2_PRIORITY_SIZE;
2004
2005
0
    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2006
0
                   "http2 PRIORITY frame sid:%ui "
2007
0
                   "depends on %ui excl:%ui weight:%ui",
2008
0
                   h2c->state.sid, depend, excl, weight);
2009
2010
0
    if (h2c->state.sid == 0) {
2011
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2012
0
                      "client sent PRIORITY frame with incorrect identifier");
2013
2014
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2015
0
    }
2016
2017
0
    if (depend == h2c->state.sid) {
2018
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2019
0
                      "client sent PRIORITY frame for stream %ui "
2020
0
                      "with incorrect dependency", h2c->state.sid);
2021
2022
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2023
0
    }
2024
2025
0
    node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
2026
2027
0
    if (node == NULL) {
2028
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2029
0
    }
2030
2031
0
    node->weight = weight;
2032
2033
0
    if (node->stream == NULL) {
2034
0
        if (node->parent == NULL) {
2035
0
            h2c->closed_nodes++;
2036
2037
0
        } else {
2038
0
            ngx_queue_remove(&node->reuse);
2039
0
        }
2040
2041
0
        ngx_queue_insert_tail(&h2c->closed, &node->reuse);
2042
0
    }
2043
2044
0
    ngx_http_v2_set_dependency(h2c, node, depend, excl);
2045
2046
0
    return ngx_http_v2_state_complete(h2c, pos, end);
2047
0
}
2048
2049
2050
static u_char *
2051
ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, u_char *pos,
2052
    u_char *end)
2053
0
{
2054
0
    ngx_uint_t             status;
2055
0
    ngx_event_t           *ev;
2056
0
    ngx_connection_t      *fc;
2057
0
    ngx_http_v2_node_t    *node;
2058
0
    ngx_http_v2_stream_t  *stream;
2059
2060
0
    if (h2c->state.length != NGX_HTTP_V2_RST_STREAM_SIZE) {
2061
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2062
0
                      "client sent RST_STREAM frame with incorrect length %uz",
2063
0
                      h2c->state.length);
2064
2065
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2066
0
    }
2067
2068
0
    if (end - pos < NGX_HTTP_V2_RST_STREAM_SIZE) {
2069
0
        return ngx_http_v2_state_save(h2c, pos, end,
2070
0
                                      ngx_http_v2_state_rst_stream);
2071
0
    }
2072
2073
0
    status = ngx_http_v2_parse_uint32(pos);
2074
2075
0
    pos += NGX_HTTP_V2_RST_STREAM_SIZE;
2076
2077
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2078
0
                   "http2 RST_STREAM frame, sid:%ui status:%ui",
2079
0
                   h2c->state.sid, status);
2080
2081
0
    if (h2c->state.sid == 0) {
2082
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2083
0
                      "client sent RST_STREAM frame with incorrect identifier");
2084
2085
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2086
0
    }
2087
2088
0
    node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
2089
2090
0
    if (node == NULL || node->stream == NULL) {
2091
0
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2092
0
                       "unknown http2 stream");
2093
2094
0
        return ngx_http_v2_state_complete(h2c, pos, end);
2095
0
    }
2096
2097
0
    stream = node->stream;
2098
2099
0
    stream->in_closed = 1;
2100
0
    stream->out_closed = 1;
2101
2102
0
    fc = stream->request->connection;
2103
0
    fc->error = 1;
2104
2105
0
    switch (status) {
2106
2107
0
    case NGX_HTTP_V2_CANCEL:
2108
0
        ngx_log_error(NGX_LOG_INFO, fc->log, 0,
2109
0
                      "client canceled stream %ui", h2c->state.sid);
2110
0
        break;
2111
2112
0
    case NGX_HTTP_V2_INTERNAL_ERROR:
2113
0
        ngx_log_error(NGX_LOG_INFO, fc->log, 0,
2114
0
                      "client terminated stream %ui due to internal error",
2115
0
                      h2c->state.sid);
2116
0
        break;
2117
2118
0
    default:
2119
0
        ngx_log_error(NGX_LOG_INFO, fc->log, 0,
2120
0
                      "client terminated stream %ui with status %ui",
2121
0
                      h2c->state.sid, status);
2122
0
        break;
2123
0
    }
2124
2125
0
    ev = fc->read;
2126
0
    ev->handler(ev);
2127
2128
0
    return ngx_http_v2_state_complete(h2c, pos, end);
2129
0
}
2130
2131
2132
static u_char *
2133
ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos,
2134
    u_char *end)
2135
0
{
2136
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2137
0
                   "http2 SETTINGS frame");
2138
2139
0
    if (h2c->state.sid) {
2140
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2141
0
                      "client sent SETTINGS frame with incorrect identifier");
2142
2143
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2144
0
    }
2145
2146
0
    if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) {
2147
2148
0
        if (h2c->state.length != 0) {
2149
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2150
0
                          "client sent SETTINGS frame with the ACK flag "
2151
0
                          "and nonzero length");
2152
2153
0
            return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2154
0
        }
2155
2156
0
        h2c->settings_ack = 1;
2157
2158
0
        return ngx_http_v2_state_complete(h2c, pos, end);
2159
0
    }
2160
2161
0
    if (h2c->state.length % NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
2162
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2163
0
                      "client sent SETTINGS frame with incorrect length %uz",
2164
0
                      h2c->state.length);
2165
2166
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2167
0
    }
2168
2169
0
    return ngx_http_v2_state_settings_params(h2c, pos, end);
2170
0
}
2171
2172
2173
static u_char *
2174
ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
2175
    u_char *end)
2176
0
{
2177
0
    ssize_t                   window_delta;
2178
0
    ngx_uint_t                id, value;
2179
0
    ngx_http_v2_out_frame_t  *frame;
2180
2181
0
    window_delta = 0;
2182
2183
0
    while (h2c->state.length) {
2184
0
        if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
2185
0
            return ngx_http_v2_state_save(h2c, pos, end,
2186
0
                                          ngx_http_v2_state_settings_params);
2187
0
        }
2188
2189
0
        h2c->state.length -= NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
2190
2191
0
        id = ngx_http_v2_parse_uint16(pos);
2192
0
        value = ngx_http_v2_parse_uint32(&pos[2]);
2193
2194
0
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2195
0
                       "http2 setting %ui:%ui", id, value);
2196
2197
0
        switch (id) {
2198
2199
0
        case NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING:
2200
2201
0
            if (value > NGX_HTTP_V2_MAX_WINDOW) {
2202
0
                ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2203
0
                              "client sent SETTINGS frame with incorrect "
2204
0
                              "INITIAL_WINDOW_SIZE value %ui", value);
2205
2206
0
                return ngx_http_v2_connection_error(h2c,
2207
0
                                                  NGX_HTTP_V2_FLOW_CTRL_ERROR);
2208
0
            }
2209
2210
0
            window_delta = value - h2c->init_window;
2211
0
            break;
2212
2213
0
        case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING:
2214
2215
0
            if (value > NGX_HTTP_V2_MAX_FRAME_SIZE
2216
0
                || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE)
2217
0
            {
2218
0
                ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2219
0
                              "client sent SETTINGS frame with incorrect "
2220
0
                              "MAX_FRAME_SIZE value %ui", value);
2221
2222
0
                return ngx_http_v2_connection_error(h2c,
2223
0
                                                    NGX_HTTP_V2_PROTOCOL_ERROR);
2224
0
            }
2225
2226
0
            h2c->frame_size = value;
2227
0
            break;
2228
2229
0
        case NGX_HTTP_V2_ENABLE_PUSH_SETTING:
2230
2231
0
            if (value > 1) {
2232
0
                ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2233
0
                              "client sent SETTINGS frame with incorrect "
2234
0
                              "ENABLE_PUSH value %ui", value);
2235
2236
0
                return ngx_http_v2_connection_error(h2c,
2237
0
                                                    NGX_HTTP_V2_PROTOCOL_ERROR);
2238
0
            }
2239
2240
0
            break;
2241
2242
0
        case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING:
2243
2244
0
            h2c->table_update = 1;
2245
0
            break;
2246
2247
0
        default:
2248
0
            break;
2249
0
        }
2250
2251
0
        pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
2252
0
    }
2253
2254
0
    frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_SETTINGS_ACK_SIZE,
2255
0
                                  NGX_HTTP_V2_SETTINGS_FRAME,
2256
0
                                  NGX_HTTP_V2_ACK_FLAG, 0);
2257
0
    if (frame == NULL) {
2258
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2259
0
    }
2260
2261
0
    ngx_http_v2_queue_ordered_frame(h2c, frame);
2262
2263
0
    if (window_delta) {
2264
0
        h2c->init_window += window_delta;
2265
2266
0
        if (ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK) {
2267
0
            return ngx_http_v2_connection_error(h2c,
2268
0
                                                NGX_HTTP_V2_INTERNAL_ERROR);
2269
0
        }
2270
0
    }
2271
2272
0
    return ngx_http_v2_state_complete(h2c, pos, end);
2273
0
}
2274
2275
2276
static u_char *
2277
ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, u_char *pos,
2278
    u_char *end)
2279
0
{
2280
0
    ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2281
0
                  "client sent PUSH_PROMISE frame");
2282
2283
0
    return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2284
0
}
2285
2286
2287
static u_char *
2288
ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
2289
0
{
2290
0
    ngx_buf_t                *buf;
2291
0
    ngx_http_v2_out_frame_t  *frame;
2292
2293
0
    if (h2c->state.length != NGX_HTTP_V2_PING_SIZE) {
2294
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2295
0
                      "client sent PING frame with incorrect length %uz",
2296
0
                      h2c->state.length);
2297
2298
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2299
0
    }
2300
2301
0
    if (end - pos < NGX_HTTP_V2_PING_SIZE) {
2302
0
        return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_ping);
2303
0
    }
2304
2305
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2306
0
                   "http2 PING frame");
2307
2308
0
    if (h2c->state.sid) {
2309
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2310
0
                      "client sent PING frame with incorrect identifier");
2311
2312
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2313
0
    }
2314
2315
0
    if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) {
2316
0
        return ngx_http_v2_state_skip(h2c, pos, end);
2317
0
    }
2318
2319
0
    frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_PING_SIZE,
2320
0
                                  NGX_HTTP_V2_PING_FRAME,
2321
0
                                  NGX_HTTP_V2_ACK_FLAG, 0);
2322
0
    if (frame == NULL) {
2323
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2324
0
    }
2325
2326
0
    buf = frame->first->buf;
2327
2328
0
    buf->last = ngx_cpymem(buf->last, pos, NGX_HTTP_V2_PING_SIZE);
2329
2330
0
    ngx_http_v2_queue_blocked_frame(h2c, frame);
2331
2332
0
    return ngx_http_v2_state_complete(h2c, pos + NGX_HTTP_V2_PING_SIZE, end);
2333
0
}
2334
2335
2336
static u_char *
2337
ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, u_char *pos,
2338
    u_char *end)
2339
0
{
2340
#if (NGX_DEBUG)
2341
    ngx_uint_t  last_sid, error;
2342
#endif
2343
2344
0
    if (h2c->state.length < NGX_HTTP_V2_GOAWAY_SIZE) {
2345
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2346
0
                      "client sent GOAWAY frame "
2347
0
                      "with incorrect length %uz", h2c->state.length);
2348
2349
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2350
0
    }
2351
2352
0
    if (end - pos < NGX_HTTP_V2_GOAWAY_SIZE) {
2353
0
        return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway);
2354
0
    }
2355
2356
0
    if (h2c->state.sid) {
2357
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2358
0
                      "client sent GOAWAY frame with incorrect identifier");
2359
2360
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2361
0
    }
2362
2363
#if (NGX_DEBUG)
2364
    h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE;
2365
2366
    last_sid = ngx_http_v2_parse_sid(pos);
2367
    error = ngx_http_v2_parse_uint32(&pos[4]);
2368
2369
    pos += NGX_HTTP_V2_GOAWAY_SIZE;
2370
2371
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2372
                   "http2 GOAWAY frame: last sid %ui, error %ui",
2373
                   last_sid, error);
2374
#endif
2375
2376
0
    return ngx_http_v2_state_skip(h2c, pos, end);
2377
0
}
2378
2379
2380
static u_char *
2381
ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos,
2382
    u_char *end)
2383
0
{
2384
0
    size_t                 window;
2385
0
    ngx_event_t           *wev;
2386
0
    ngx_queue_t           *q;
2387
0
    ngx_http_v2_node_t    *node;
2388
0
    ngx_http_v2_stream_t  *stream;
2389
2390
0
    if (h2c->state.length != NGX_HTTP_V2_WINDOW_UPDATE_SIZE) {
2391
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2392
0
                      "client sent WINDOW_UPDATE frame "
2393
0
                      "with incorrect length %uz", h2c->state.length);
2394
2395
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2396
0
    }
2397
2398
0
    if (end - pos < NGX_HTTP_V2_WINDOW_UPDATE_SIZE) {
2399
0
        return ngx_http_v2_state_save(h2c, pos, end,
2400
0
                                      ngx_http_v2_state_window_update);
2401
0
    }
2402
2403
0
    window = ngx_http_v2_parse_window(pos);
2404
2405
0
    pos += NGX_HTTP_V2_WINDOW_UPDATE_SIZE;
2406
2407
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2408
0
                   "http2 WINDOW_UPDATE frame sid:%ui window:%uz",
2409
0
                   h2c->state.sid, window);
2410
2411
0
    if (window == 0) {
2412
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2413
0
                      "client sent WINDOW_UPDATE frame "
2414
0
                      "with incorrect window increment 0");
2415
2416
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2417
0
    }
2418
2419
0
    if (h2c->state.sid) {
2420
0
        node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
2421
2422
0
        if (node == NULL || node->stream == NULL) {
2423
0
            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2424
0
                           "unknown http2 stream");
2425
2426
0
            return ngx_http_v2_state_complete(h2c, pos, end);
2427
0
        }
2428
2429
0
        stream = node->stream;
2430
2431
0
        if (window > (size_t) (NGX_HTTP_V2_MAX_WINDOW - stream->send_window)) {
2432
2433
0
            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2434
0
                          "client violated flow control for stream %ui: "
2435
0
                          "received WINDOW_UPDATE frame "
2436
0
                          "with window increment %uz "
2437
0
                          "not allowed for window %z",
2438
0
                          h2c->state.sid, window, stream->send_window);
2439
2440
0
            if (ngx_http_v2_terminate_stream(h2c, stream,
2441
0
                                             NGX_HTTP_V2_FLOW_CTRL_ERROR)
2442
0
                == NGX_ERROR)
2443
0
            {
2444
0
                return ngx_http_v2_connection_error(h2c,
2445
0
                                                    NGX_HTTP_V2_INTERNAL_ERROR);
2446
0
            }
2447
2448
0
            return ngx_http_v2_state_complete(h2c, pos, end);
2449
0
        }
2450
2451
0
        stream->send_window += window;
2452
2453
0
        if (stream->exhausted) {
2454
0
            stream->exhausted = 0;
2455
2456
0
            wev = stream->request->connection->write;
2457
2458
0
            wev->active = 0;
2459
0
            wev->ready = 1;
2460
2461
0
            if (!wev->delayed) {
2462
0
                wev->handler(wev);
2463
0
            }
2464
0
        }
2465
2466
0
        return ngx_http_v2_state_complete(h2c, pos, end);
2467
0
    }
2468
2469
0
    if (window > NGX_HTTP_V2_MAX_WINDOW - h2c->send_window) {
2470
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2471
0
                      "client violated connection flow control: "
2472
0
                      "received WINDOW_UPDATE frame "
2473
0
                      "with window increment %uz "
2474
0
                      "not allowed for window %uz",
2475
0
                      window, h2c->send_window);
2476
2477
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
2478
0
    }
2479
2480
0
    h2c->send_window += window;
2481
2482
0
    while (!ngx_queue_empty(&h2c->waiting)) {
2483
0
        q = ngx_queue_head(&h2c->waiting);
2484
2485
0
        ngx_queue_remove(q);
2486
2487
0
        stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue);
2488
2489
0
        stream->waiting = 0;
2490
2491
0
        wev = stream->request->connection->write;
2492
2493
0
        wev->active = 0;
2494
0
        wev->ready = 1;
2495
2496
0
        if (!wev->delayed) {
2497
0
            wev->handler(wev);
2498
2499
0
            if (h2c->send_window == 0) {
2500
0
                break;
2501
0
            }
2502
0
        }
2503
0
    }
2504
2505
0
    return ngx_http_v2_state_complete(h2c, pos, end);
2506
0
}
2507
2508
2509
static u_char *
2510
ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, u_char *pos,
2511
    u_char *end)
2512
0
{
2513
0
    ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2514
0
                  "client sent unexpected CONTINUATION frame");
2515
2516
0
    return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2517
0
}
2518
2519
2520
static u_char *
2521
ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
2522
    u_char *end)
2523
0
{
2524
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2525
0
                   "http2 frame complete pos:%p end:%p", pos, end);
2526
2527
0
    if (pos > end) {
2528
0
        ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2529
0
                      "receive buffer overrun");
2530
2531
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2532
0
    }
2533
2534
0
    h2c->state.stream = NULL;
2535
0
    h2c->state.handler = ngx_http_v2_state_head;
2536
2537
0
    return pos;
2538
0
}
2539
2540
2541
static u_char *
2542
ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, u_char *pos,
2543
    u_char *end)
2544
0
{
2545
0
    h2c->state.length += h2c->state.padding;
2546
0
    h2c->state.padding = 0;
2547
2548
0
    return ngx_http_v2_state_skip(h2c, pos, end);
2549
0
}
2550
2551
2552
static u_char *
2553
ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
2554
0
{
2555
0
    size_t  size;
2556
2557
0
    size = end - pos;
2558
2559
0
    if (size < h2c->state.length) {
2560
0
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2561
0
                       "http2 frame skip %uz of %uz", size, h2c->state.length);
2562
2563
0
        h2c->state.length -= size;
2564
0
        return ngx_http_v2_state_save(h2c, end, end, ngx_http_v2_state_skip);
2565
0
    }
2566
2567
0
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2568
0
                   "http2 frame skip %uz", h2c->state.length);
2569
2570
0
    return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end);
2571
0
}
2572
2573
2574
static u_char *
2575
ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end,
2576
    ngx_http_v2_handler_pt handler)
2577
0
{
2578
0
    size_t  size;
2579
2580
0
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2581
0
                   "http2 frame state save pos:%p end:%p handler:%p",
2582
0
                   pos, end, handler);
2583
2584
0
    size = end - pos;
2585
2586
0
    if (size > NGX_HTTP_V2_STATE_BUFFER_SIZE) {
2587
0
        ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2588
0
                      "state buffer overflow: %uz bytes required", size);
2589
2590
0
        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2591
0
    }
2592
2593
0
    ngx_memcpy(h2c->state.buffer, pos, size);
2594
2595
0
    h2c->state.buffer_used = size;
2596
0
    h2c->state.handler = handler;
2597
0
    h2c->state.incomplete = 1;
2598
2599
0
    return end;
2600
0
}
2601
2602
2603
static u_char *
2604
ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, u_char *pos,
2605
    u_char *end, ngx_http_v2_handler_pt handler)
2606
0
{
2607
0
    ngx_event_t               *rev;
2608
0
    ngx_http_request_t        *r;
2609
0
    ngx_http_core_srv_conf_t  *cscf;
2610
2611
0
    if (h2c->state.stream) {
2612
0
        r = h2c->state.stream->request;
2613
0
        rev = r->connection->read;
2614
2615
0
        if (!rev->timer_set) {
2616
0
            cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2617
0
            ngx_add_timer(rev, cscf->client_header_timeout);
2618
0
        }
2619
0
    }
2620
2621
0
    return ngx_http_v2_state_save(h2c, pos, end, handler);
2622
0
}
2623
2624
2625
static u_char *
2626
ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
2627
    ngx_uint_t err)
2628
0
{
2629
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2630
0
                   "http2 state connection error");
2631
2632
0
    ngx_http_v2_finalize_connection(h2c, err);
2633
2634
0
    return NULL;
2635
0
}
2636
2637
2638
static ngx_int_t
2639
ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end,
2640
    ngx_uint_t prefix)
2641
0
{
2642
0
    u_char      *start, *p;
2643
0
    ngx_uint_t   value, octet, shift;
2644
2645
0
    start = *pos;
2646
0
    p = start;
2647
2648
0
    value = *p++ & prefix;
2649
2650
0
    if (value != prefix) {
2651
0
        if (h2c->state.length == 0) {
2652
0
            return NGX_ERROR;
2653
0
        }
2654
2655
0
        h2c->state.length--;
2656
2657
0
        *pos = p;
2658
0
        return value;
2659
0
    }
2660
2661
0
    if (end - start > NGX_HTTP_V2_INT_OCTETS) {
2662
0
        end = start + NGX_HTTP_V2_INT_OCTETS;
2663
0
    }
2664
2665
0
    for (shift = 0; p != end; shift += 7) {
2666
0
        octet = *p++;
2667
2668
0
        value += (octet & 0x7f) << shift;
2669
2670
0
        if (octet < 128) {
2671
0
            if ((size_t) (p - start) > h2c->state.length) {
2672
0
                return NGX_ERROR;
2673
0
            }
2674
2675
0
            h2c->state.length -= p - start;
2676
2677
0
            *pos = p;
2678
0
            return value;
2679
0
        }
2680
0
    }
2681
2682
0
    if ((size_t) (end - start) >= h2c->state.length) {
2683
0
        return NGX_ERROR;
2684
0
    }
2685
2686
0
    if (end == start + NGX_HTTP_V2_INT_OCTETS) {
2687
0
        return NGX_DECLINED;
2688
0
    }
2689
2690
0
    return NGX_AGAIN;
2691
0
}
2692
2693
2694
static ngx_int_t
2695
ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c)
2696
0
{
2697
0
    size_t                    len;
2698
0
    ngx_buf_t                *buf;
2699
0
    ngx_chain_t              *cl;
2700
0
    ngx_http_v2_srv_conf_t   *h2scf;
2701
0
    ngx_http_v2_out_frame_t  *frame;
2702
2703
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2704
0
                   "http2 send SETTINGS frame");
2705
2706
0
    frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t));
2707
0
    if (frame == NULL) {
2708
0
        return NGX_ERROR;
2709
0
    }
2710
2711
0
    cl = ngx_alloc_chain_link(h2c->pool);
2712
0
    if (cl == NULL) {
2713
0
        return NGX_ERROR;
2714
0
    }
2715
2716
0
    len = NGX_HTTP_V2_SETTINGS_PARAM_SIZE * 3;
2717
2718
0
    buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len);
2719
0
    if (buf == NULL) {
2720
0
        return NGX_ERROR;
2721
0
    }
2722
2723
0
    buf->last_buf = 1;
2724
2725
0
    cl->buf = buf;
2726
0
    cl->next = NULL;
2727
2728
0
    frame->first = cl;
2729
0
    frame->last = cl;
2730
0
    frame->handler = ngx_http_v2_settings_frame_handler;
2731
0
    frame->stream = NULL;
2732
#if (NGX_DEBUG)
2733
    frame->length = len;
2734
#endif
2735
0
    frame->blocked = 0;
2736
2737
0
    buf->last = ngx_http_v2_write_len_and_type(buf->last, len,
2738
0
                                               NGX_HTTP_V2_SETTINGS_FRAME);
2739
2740
0
    *buf->last++ = NGX_HTTP_V2_NO_FLAG;
2741
2742
0
    buf->last = ngx_http_v2_write_sid(buf->last, 0);
2743
2744
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2745
0
                                         ngx_http_v2_module);
2746
2747
0
    buf->last = ngx_http_v2_write_uint16(buf->last,
2748
0
                                         NGX_HTTP_V2_MAX_STREAMS_SETTING);
2749
0
    buf->last = ngx_http_v2_write_uint32(buf->last,
2750
0
                                         h2scf->concurrent_streams);
2751
2752
0
    buf->last = ngx_http_v2_write_uint16(buf->last,
2753
0
                                         NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING);
2754
0
    buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size);
2755
2756
0
    buf->last = ngx_http_v2_write_uint16(buf->last,
2757
0
                                         NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING);
2758
0
    buf->last = ngx_http_v2_write_uint32(buf->last,
2759
0
                                         NGX_HTTP_V2_MAX_FRAME_SIZE);
2760
2761
0
    ngx_http_v2_queue_blocked_frame(h2c, frame);
2762
2763
0
    return NGX_OK;
2764
0
}
2765
2766
2767
static ngx_int_t
2768
ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t *h2c,
2769
    ngx_http_v2_out_frame_t *frame)
2770
0
{
2771
0
    ngx_buf_t  *buf;
2772
2773
0
    buf = frame->first->buf;
2774
2775
0
    if (buf->pos != buf->last) {
2776
0
        return NGX_AGAIN;
2777
0
    }
2778
2779
0
    ngx_free_chain(h2c->pool, frame->first);
2780
2781
0
    return NGX_OK;
2782
0
}
2783
2784
2785
static ngx_int_t
2786
ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
2787
    size_t window)
2788
0
{
2789
0
    ngx_buf_t                *buf;
2790
0
    ngx_http_v2_out_frame_t  *frame;
2791
2792
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2793
0
                   "http2 send WINDOW_UPDATE frame sid:%ui, window:%uz",
2794
0
                   sid, window);
2795
2796
0
    frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE,
2797
0
                                  NGX_HTTP_V2_WINDOW_UPDATE_FRAME,
2798
0
                                  NGX_HTTP_V2_NO_FLAG, sid);
2799
0
    if (frame == NULL) {
2800
0
        return NGX_ERROR;
2801
0
    }
2802
2803
0
    buf = frame->first->buf;
2804
2805
0
    buf->last = ngx_http_v2_write_uint32(buf->last, window);
2806
2807
0
    ngx_http_v2_queue_blocked_frame(h2c, frame);
2808
2809
0
    return NGX_OK;
2810
0
}
2811
2812
2813
static ngx_int_t
2814
ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
2815
    ngx_uint_t status)
2816
0
{
2817
0
    ngx_buf_t                *buf;
2818
0
    ngx_http_v2_out_frame_t  *frame;
2819
2820
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2821
0
                   "http2 send RST_STREAM frame sid:%ui, status:%ui",
2822
0
                   sid, status);
2823
2824
0
    frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE,
2825
0
                                  NGX_HTTP_V2_RST_STREAM_FRAME,
2826
0
                                  NGX_HTTP_V2_NO_FLAG, sid);
2827
0
    if (frame == NULL) {
2828
0
        return NGX_ERROR;
2829
0
    }
2830
2831
0
    buf = frame->first->buf;
2832
2833
0
    buf->last = ngx_http_v2_write_uint32(buf->last, status);
2834
2835
0
    ngx_http_v2_queue_blocked_frame(h2c, frame);
2836
2837
0
    return NGX_OK;
2838
0
}
2839
2840
2841
static ngx_int_t
2842
ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status)
2843
0
{
2844
0
    ngx_buf_t                *buf;
2845
0
    ngx_http_v2_out_frame_t  *frame;
2846
2847
0
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2848
0
                   "http2 send GOAWAY frame: last sid %ui, error %ui",
2849
0
                   h2c->last_sid, status);
2850
2851
0
    frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE,
2852
0
                                  NGX_HTTP_V2_GOAWAY_FRAME,
2853
0
                                  NGX_HTTP_V2_NO_FLAG, 0);
2854
0
    if (frame == NULL) {
2855
0
        return NGX_ERROR;
2856
0
    }
2857
2858
0
    buf = frame->first->buf;
2859
2860
0
    buf->last = ngx_http_v2_write_sid(buf->last, h2c->last_sid);
2861
0
    buf->last = ngx_http_v2_write_uint32(buf->last, status);
2862
2863
0
    ngx_http_v2_queue_blocked_frame(h2c, frame);
2864
2865
0
    return NGX_OK;
2866
0
}
2867
2868
2869
static ngx_http_v2_out_frame_t *
2870
ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length,
2871
    ngx_uint_t type, u_char flags, ngx_uint_t sid)
2872
0
{
2873
0
    ngx_buf_t                *buf;
2874
0
    ngx_pool_t               *pool;
2875
0
    ngx_http_v2_out_frame_t  *frame;
2876
2877
0
    frame = h2c->free_frames;
2878
2879
0
    if (frame) {
2880
0
        h2c->free_frames = frame->next;
2881
2882
0
        buf = frame->first->buf;
2883
0
        buf->pos = buf->start;
2884
2885
0
        frame->blocked = 0;
2886
2887
0
    } else if (h2c->frames < 10000) {
2888
0
        pool = h2c->pool ? h2c->pool : h2c->connection->pool;
2889
2890
0
        frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t));
2891
0
        if (frame == NULL) {
2892
0
            return NULL;
2893
0
        }
2894
2895
0
        frame->first = ngx_alloc_chain_link(pool);
2896
0
        if (frame->first == NULL) {
2897
0
            return NULL;
2898
0
        }
2899
2900
0
        buf = ngx_create_temp_buf(pool, NGX_HTTP_V2_FRAME_BUFFER_SIZE);
2901
0
        if (buf == NULL) {
2902
0
            return NULL;
2903
0
        }
2904
2905
0
        buf->last_buf = 1;
2906
2907
0
        frame->first->buf = buf;
2908
0
        frame->last = frame->first;
2909
2910
0
        frame->handler = ngx_http_v2_frame_handler;
2911
2912
0
        h2c->frames++;
2913
2914
0
    } else {
2915
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2916
0
                      "http2 flood detected");
2917
2918
0
        h2c->connection->error = 1;
2919
0
        return NULL;
2920
0
    }
2921
2922
#if (NGX_DEBUG)
2923
    if (length > NGX_HTTP_V2_FRAME_BUFFER_SIZE - NGX_HTTP_V2_FRAME_HEADER_SIZE)
2924
    {
2925
        ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2926
                      "requested control frame is too large: %uz", length);
2927
        return NULL;
2928
    }
2929
#endif
2930
2931
0
    frame->length = length;
2932
2933
0
    buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);
2934
2935
0
    *buf->last++ = flags;
2936
2937
0
    buf->last = ngx_http_v2_write_sid(buf->last, sid);
2938
2939
0
    return frame;
2940
0
}
2941
2942
2943
static ngx_int_t
2944
ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
2945
    ngx_http_v2_out_frame_t *frame)
2946
0
{
2947
0
    ngx_buf_t  *buf;
2948
2949
0
    buf = frame->first->buf;
2950
2951
0
    if (buf->pos != buf->last) {
2952
0
        return NGX_AGAIN;
2953
0
    }
2954
2955
0
    frame->next = h2c->free_frames;
2956
0
    h2c->free_frames = frame;
2957
2958
0
    h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
2959
2960
0
    return NGX_OK;
2961
0
}
2962
2963
2964
static ngx_http_v2_stream_t *
2965
ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c)
2966
0
{
2967
0
    ngx_log_t                 *log;
2968
0
    ngx_event_t               *rev, *wev;
2969
0
    ngx_connection_t          *fc;
2970
0
    ngx_http_log_ctx_t        *ctx;
2971
0
    ngx_http_request_t        *r;
2972
0
    ngx_http_v2_stream_t      *stream;
2973
0
    ngx_http_v2_srv_conf_t    *h2scf;
2974
0
    ngx_http_core_srv_conf_t  *cscf;
2975
2976
0
    fc = h2c->free_fake_connections;
2977
2978
0
    if (fc) {
2979
0
        h2c->free_fake_connections = fc->data;
2980
2981
0
        rev = fc->read;
2982
0
        wev = fc->write;
2983
0
        log = fc->log;
2984
0
        ctx = log->data;
2985
2986
0
    } else {
2987
0
        fc = ngx_palloc(h2c->pool, sizeof(ngx_connection_t));
2988
0
        if (fc == NULL) {
2989
0
            return NULL;
2990
0
        }
2991
2992
0
        rev = ngx_palloc(h2c->pool, sizeof(ngx_event_t));
2993
0
        if (rev == NULL) {
2994
0
            return NULL;
2995
0
        }
2996
2997
0
        wev = ngx_palloc(h2c->pool, sizeof(ngx_event_t));
2998
0
        if (wev == NULL) {
2999
0
            return NULL;
3000
0
        }
3001
3002
0
        log = ngx_palloc(h2c->pool, sizeof(ngx_log_t));
3003
0
        if (log == NULL) {
3004
0
            return NULL;
3005
0
        }
3006
3007
0
        ctx = ngx_palloc(h2c->pool, sizeof(ngx_http_log_ctx_t));
3008
0
        if (ctx == NULL) {
3009
0
            return NULL;
3010
0
        }
3011
3012
0
        ctx->connection = fc;
3013
0
        ctx->request = NULL;
3014
0
        ctx->current_request = NULL;
3015
0
    }
3016
3017
0
    ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t));
3018
3019
0
    log->data = ctx;
3020
0
    log->action = "reading client request headers";
3021
3022
0
    ngx_memzero(rev, sizeof(ngx_event_t));
3023
3024
0
    rev->data = fc;
3025
0
    rev->ready = 1;
3026
0
    rev->handler = ngx_http_v2_close_stream_handler;
3027
0
    rev->log = log;
3028
3029
0
    ngx_memcpy(wev, rev, sizeof(ngx_event_t));
3030
3031
0
    wev->write = 1;
3032
3033
0
    ngx_memcpy(fc, h2c->connection, sizeof(ngx_connection_t));
3034
3035
0
    fc->data = h2c->http_connection;
3036
0
    fc->read = rev;
3037
0
    fc->write = wev;
3038
0
    fc->sent = 0;
3039
0
    fc->log = log;
3040
0
    fc->buffered = 0;
3041
0
    fc->sndlowat = 1;
3042
0
    fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
3043
3044
0
    r = ngx_http_create_request(fc);
3045
0
    if (r == NULL) {
3046
0
        return NULL;
3047
0
    }
3048
3049
0
    ngx_str_set(&r->http_protocol, "HTTP/2.0");
3050
3051
0
    r->http_version = NGX_HTTP_VERSION_20;
3052
0
    r->valid_location = 1;
3053
3054
0
    fc->data = r;
3055
0
    h2c->connection->requests++;
3056
3057
0
    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
3058
3059
0
    r->header_in = ngx_create_temp_buf(r->pool,
3060
0
                                       cscf->client_header_buffer_size);
3061
0
    if (r->header_in == NULL) {
3062
0
        ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3063
0
        return NULL;
3064
0
    }
3065
3066
0
    if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
3067
0
                      sizeof(ngx_table_elt_t))
3068
0
        != NGX_OK)
3069
0
    {
3070
0
        ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3071
0
        return NULL;
3072
0
    }
3073
3074
0
    r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
3075
3076
0
    stream = ngx_pcalloc(r->pool, sizeof(ngx_http_v2_stream_t));
3077
0
    if (stream == NULL) {
3078
0
        ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3079
0
        return NULL;
3080
0
    }
3081
3082
0
    r->stream = stream;
3083
3084
0
    stream->request = r;
3085
0
    stream->connection = h2c;
3086
3087
0
    h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3088
3089
0
    stream->send_window = h2c->init_window;
3090
0
    stream->recv_window = h2scf->preread_size;
3091
3092
0
    h2c->processing++;
3093
3094
0
    h2c->priority_limit += h2scf->concurrent_streams;
3095
3096
0
    if (h2c->connection->read->timer_set) {
3097
0
        ngx_del_timer(h2c->connection->read);
3098
0
    }
3099
3100
0
    return stream;
3101
0
}
3102
3103
3104
static ngx_http_v2_node_t *
3105
ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
3106
    ngx_uint_t alloc)
3107
0
{
3108
0
    ngx_uint_t               index;
3109
0
    ngx_http_v2_node_t      *node;
3110
0
    ngx_http_v2_srv_conf_t  *h2scf;
3111
3112
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
3113
0
                                         ngx_http_v2_module);
3114
3115
0
    index = ngx_http_v2_index(h2scf, sid);
3116
3117
0
    for (node = h2c->streams_index[index]; node; node = node->index) {
3118
3119
0
        if (node->id == sid) {
3120
0
            return node;
3121
0
        }
3122
0
    }
3123
3124
0
    if (!alloc) {
3125
0
        return NULL;
3126
0
    }
3127
3128
0
    if (h2c->closed_nodes < 32) {
3129
0
        node = ngx_pcalloc(h2c->connection->pool, sizeof(ngx_http_v2_node_t));
3130
0
        if (node == NULL) {
3131
0
            return NULL;
3132
0
        }
3133
3134
0
    } else {
3135
0
        node = ngx_http_v2_get_closed_node(h2c);
3136
0
    }
3137
3138
0
    node->id = sid;
3139
3140
0
    ngx_queue_init(&node->children);
3141
3142
0
    node->index = h2c->streams_index[index];
3143
0
    h2c->streams_index[index] = node;
3144
3145
0
    return node;
3146
0
}
3147
3148
3149
static ngx_http_v2_node_t *
3150
ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c)
3151
0
{
3152
0
    ngx_uint_t               weight;
3153
0
    ngx_queue_t             *q, *children;
3154
0
    ngx_http_v2_node_t      *node, **next, *n, *parent, *child;
3155
0
    ngx_http_v2_srv_conf_t  *h2scf;
3156
3157
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
3158
0
                                         ngx_http_v2_module);
3159
3160
0
    h2c->closed_nodes--;
3161
3162
0
    q = ngx_queue_head(&h2c->closed);
3163
3164
0
    ngx_queue_remove(q);
3165
3166
0
    node = ngx_queue_data(q, ngx_http_v2_node_t, reuse);
3167
3168
0
    next = &h2c->streams_index[ngx_http_v2_index(h2scf, node->id)];
3169
3170
0
    for ( ;; ) {
3171
0
        n = *next;
3172
3173
0
        if (n == node) {
3174
0
            *next = n->index;
3175
0
            break;
3176
0
        }
3177
3178
0
        next = &n->index;
3179
0
    }
3180
3181
0
    ngx_queue_remove(&node->queue);
3182
3183
0
    weight = 0;
3184
3185
0
    for (q = ngx_queue_head(&node->children);
3186
0
         q != ngx_queue_sentinel(&node->children);
3187
0
         q = ngx_queue_next(q))
3188
0
    {
3189
0
        child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
3190
0
        weight += child->weight;
3191
0
    }
3192
3193
0
    parent = node->parent;
3194
3195
0
    for (q = ngx_queue_head(&node->children);
3196
0
         q != ngx_queue_sentinel(&node->children);
3197
0
         q = ngx_queue_next(q))
3198
0
    {
3199
0
        child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
3200
0
        child->parent = parent;
3201
0
        child->weight = node->weight * child->weight / weight;
3202
3203
0
        if (child->weight == 0) {
3204
0
            child->weight = 1;
3205
0
        }
3206
0
    }
3207
3208
0
    if (parent == NGX_HTTP_V2_ROOT) {
3209
0
        node->rank = 0;
3210
0
        node->rel_weight = 1.0;
3211
3212
0
        children = &h2c->dependencies;
3213
3214
0
    } else {
3215
0
        node->rank = parent->rank;
3216
0
        node->rel_weight = parent->rel_weight;
3217
3218
0
        children = &parent->children;
3219
0
    }
3220
3221
0
    ngx_http_v2_node_children_update(node);
3222
0
    ngx_queue_add(children, &node->children);
3223
3224
0
    ngx_memzero(node, sizeof(ngx_http_v2_node_t));
3225
3226
0
    return node;
3227
0
}
3228
3229
3230
static ngx_int_t
3231
ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3232
0
{
3233
0
    u_char                     ch;
3234
0
    ngx_uint_t                 i;
3235
0
    ngx_http_core_srv_conf_t  *cscf;
3236
3237
0
    r->invalid_header = 0;
3238
3239
0
    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
3240
3241
0
    for (i = (header->name.data[0] == ':'); i != header->name.len; i++) {
3242
0
        ch = header->name.data[i];
3243
3244
0
        if ((ch >= 'a' && ch <= 'z')
3245
0
            || (ch == '-')
3246
0
            || (ch >= '0' && ch <= '9')
3247
0
            || (ch == '_' && cscf->underscores_in_headers))
3248
0
        {
3249
0
            continue;
3250
0
        }
3251
3252
0
        if (ch <= 0x20 || ch == 0x7f || ch == ':'
3253
0
            || (ch >= 'A' && ch <= 'Z'))
3254
0
        {
3255
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3256
0
                          "client sent invalid header name: \"%V\"",
3257
0
                          &header->name);
3258
3259
0
            return NGX_ERROR;
3260
0
        }
3261
3262
0
        r->invalid_header = 1;
3263
0
    }
3264
3265
0
    for (i = 0; i != header->value.len; i++) {
3266
0
        ch = header->value.data[i];
3267
3268
0
        if (ch == '\0' || ch == LF || ch == CR) {
3269
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3270
0
                          "client sent header \"%V\" with "
3271
0
                          "invalid value: \"%V\"",
3272
0
                          &header->name, &header->value);
3273
3274
0
            return NGX_ERROR;
3275
0
        }
3276
0
    }
3277
3278
0
    return NGX_OK;
3279
0
}
3280
3281
3282
static ngx_int_t
3283
ngx_http_v2_pseudo_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3284
0
{
3285
0
    header->name.len--;
3286
0
    header->name.data++;
3287
3288
0
    switch (header->name.len) {
3289
0
    case 4:
3290
0
        if (ngx_memcmp(header->name.data, "path", sizeof("path") - 1)
3291
0
            == 0)
3292
0
        {
3293
0
            return ngx_http_v2_parse_path(r, &header->value);
3294
0
        }
3295
3296
0
        break;
3297
3298
0
    case 6:
3299
0
        if (ngx_memcmp(header->name.data, "method", sizeof("method") - 1)
3300
0
            == 0)
3301
0
        {
3302
0
            return ngx_http_v2_parse_method(r, &header->value);
3303
0
        }
3304
3305
0
        if (ngx_memcmp(header->name.data, "scheme", sizeof("scheme") - 1)
3306
0
            == 0)
3307
0
        {
3308
0
            return ngx_http_v2_parse_scheme(r, &header->value);
3309
0
        }
3310
3311
0
        break;
3312
3313
0
    case 9:
3314
0
        if (ngx_memcmp(header->name.data, "authority", sizeof("authority") - 1)
3315
0
            == 0)
3316
0
        {
3317
0
            return ngx_http_v2_parse_authority(r, &header->value);
3318
0
        }
3319
3320
0
        break;
3321
0
    }
3322
3323
0
    ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3324
0
                  "client sent unknown pseudo-header \":%V\"",
3325
0
                  &header->name);
3326
3327
0
    return NGX_DECLINED;
3328
0
}
3329
3330
3331
static ngx_int_t
3332
ngx_http_v2_parse_path(ngx_http_request_t *r, ngx_str_t *value)
3333
0
{
3334
0
    if (r->unparsed_uri.len) {
3335
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3336
0
                      "client sent duplicate :path header");
3337
3338
0
        return NGX_DECLINED;
3339
0
    }
3340
3341
0
    if (value->len == 0) {
3342
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3343
0
                      "client sent empty :path header");
3344
3345
0
        return NGX_DECLINED;
3346
0
    }
3347
3348
0
    r->uri_start = value->data;
3349
0
    r->uri_end = value->data + value->len;
3350
3351
0
    if (ngx_http_parse_uri(r) != NGX_OK) {
3352
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3353
0
                      "client sent invalid :path header: \"%V\"", value);
3354
3355
0
        return NGX_DECLINED;
3356
0
    }
3357
3358
0
    if (ngx_http_process_request_uri(r) != NGX_OK) {
3359
        /*
3360
         * request has been finalized already
3361
         * in ngx_http_process_request_uri()
3362
         */
3363
0
        return NGX_ABORT;
3364
0
    }
3365
3366
0
    return NGX_OK;
3367
0
}
3368
3369
3370
static ngx_int_t
3371
ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value)
3372
0
{
3373
0
    size_t         k, len;
3374
0
    ngx_uint_t     n;
3375
0
    const u_char  *p, *m;
3376
3377
    /*
3378
     * This array takes less than 256 sequential bytes,
3379
     * and if typical CPU cache line size is 64 bytes,
3380
     * it is prefetched for 4 load operations.
3381
     */
3382
0
    static const struct {
3383
0
        u_char            len;
3384
0
        const u_char      method[11];
3385
0
        uint32_t          value;
3386
0
    } tests[] = {
3387
0
        { 3, "GET",       NGX_HTTP_GET },
3388
0
        { 4, "POST",      NGX_HTTP_POST },
3389
0
        { 4, "HEAD",      NGX_HTTP_HEAD },
3390
0
        { 7, "OPTIONS",   NGX_HTTP_OPTIONS },
3391
0
        { 8, "PROPFIND",  NGX_HTTP_PROPFIND },
3392
0
        { 3, "PUT",       NGX_HTTP_PUT },
3393
0
        { 5, "MKCOL",     NGX_HTTP_MKCOL },
3394
0
        { 6, "DELETE",    NGX_HTTP_DELETE },
3395
0
        { 4, "COPY",      NGX_HTTP_COPY },
3396
0
        { 4, "MOVE",      NGX_HTTP_MOVE },
3397
0
        { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
3398
0
        { 4, "LOCK",      NGX_HTTP_LOCK },
3399
0
        { 6, "UNLOCK",    NGX_HTTP_UNLOCK },
3400
0
        { 5, "PATCH",     NGX_HTTP_PATCH },
3401
0
        { 5, "TRACE",     NGX_HTTP_TRACE },
3402
0
        { 7, "CONNECT",   NGX_HTTP_CONNECT }
3403
0
    }, *test;
3404
3405
0
    if (r->method_name.len) {
3406
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3407
0
                      "client sent duplicate :method header");
3408
3409
0
        return NGX_DECLINED;
3410
0
    }
3411
3412
0
    if (value->len == 0) {
3413
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3414
0
                      "client sent empty :method header");
3415
3416
0
        return NGX_DECLINED;
3417
0
    }
3418
3419
0
    r->method_name.len = value->len;
3420
0
    r->method_name.data = value->data;
3421
3422
0
    len = r->method_name.len;
3423
0
    n = sizeof(tests) / sizeof(tests[0]);
3424
0
    test = tests;
3425
3426
0
    do {
3427
0
        if (len == test->len) {
3428
0
            p = r->method_name.data;
3429
0
            m = test->method;
3430
0
            k = len;
3431
3432
0
            do {
3433
0
                if (*p++ != *m++) {
3434
0
                    goto next;
3435
0
                }
3436
0
            } while (--k);
3437
3438
0
            r->method = test->value;
3439
0
            return NGX_OK;
3440
0
        }
3441
3442
0
    next:
3443
0
        test++;
3444
3445
0
    } while (--n);
3446
3447
0
    p = r->method_name.data;
3448
3449
0
    do {
3450
0
        if ((*p < 'A' || *p > 'Z') && *p != '_' && *p != '-') {
3451
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3452
0
                          "client sent invalid method: \"%V\"",
3453
0
                          &r->method_name);
3454
3455
0
            return NGX_DECLINED;
3456
0
        }
3457
3458
0
        p++;
3459
3460
0
    } while (--len);
3461
3462
0
    return NGX_OK;
3463
0
}
3464
3465
3466
static ngx_int_t
3467
ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value)
3468
0
{
3469
0
    u_char      c, ch;
3470
0
    ngx_uint_t  i;
3471
3472
0
    if (r->schema.len) {
3473
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3474
0
                      "client sent duplicate :scheme header");
3475
3476
0
        return NGX_DECLINED;
3477
0
    }
3478
3479
0
    if (value->len == 0) {
3480
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3481
0
                      "client sent empty :scheme header");
3482
3483
0
        return NGX_DECLINED;
3484
0
    }
3485
3486
0
    for (i = 0; i < value->len; i++) {
3487
0
        ch = value->data[i];
3488
3489
0
        c = (u_char) (ch | 0x20);
3490
0
        if (c >= 'a' && c <= 'z') {
3491
0
            continue;
3492
0
        }
3493
3494
0
        if (((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.')
3495
0
            && i > 0)
3496
0
        {
3497
0
            continue;
3498
0
        }
3499
3500
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3501
0
                      "client sent invalid :scheme header: \"%V\"", value);
3502
3503
0
        return NGX_DECLINED;
3504
0
    }
3505
3506
0
    r->schema = *value;
3507
3508
0
    return NGX_OK;
3509
0
}
3510
3511
3512
static ngx_int_t
3513
ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value)
3514
0
{
3515
0
    ngx_table_elt_t            *h;
3516
0
    ngx_http_header_t          *hh;
3517
0
    ngx_http_core_main_conf_t  *cmcf;
3518
3519
0
    static ngx_str_t host = ngx_string("host");
3520
3521
0
    h = ngx_list_push(&r->headers_in.headers);
3522
0
    if (h == NULL) {
3523
0
        return NGX_ERROR;
3524
0
    }
3525
3526
0
    h->hash = ngx_hash(ngx_hash(ngx_hash('h', 'o'), 's'), 't');
3527
3528
0
    h->key.len = host.len;
3529
0
    h->key.data = host.data;
3530
3531
0
    h->value.len = value->len;
3532
0
    h->value.data = value->data;
3533
3534
0
    h->lowcase_key = host.data;
3535
3536
0
    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3537
3538
0
    hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
3539
0
                       h->lowcase_key, h->key.len);
3540
3541
0
    if (hh == NULL) {
3542
0
        return NGX_ERROR;
3543
0
    }
3544
3545
0
    if (hh->handler(r, h, hh->offset) != NGX_OK) {
3546
        /*
3547
         * request has been finalized already
3548
         * in ngx_http_process_host()
3549
         */
3550
0
        return NGX_ABORT;
3551
0
    }
3552
3553
0
    return NGX_OK;
3554
0
}
3555
3556
3557
static ngx_int_t
3558
ngx_http_v2_construct_request_line(ngx_http_request_t *r)
3559
0
{
3560
0
    u_char  *p;
3561
3562
0
    static const u_char ending[] = " HTTP/2.0";
3563
3564
0
    if (r->method_name.len == 0
3565
0
        || r->schema.len == 0
3566
0
        || r->unparsed_uri.len == 0)
3567
0
    {
3568
0
        if (r->method_name.len == 0) {
3569
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3570
0
                          "client sent no :method header");
3571
3572
0
        } else if (r->schema.len == 0) {
3573
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3574
0
                          "client sent no :scheme header");
3575
3576
0
        } else {
3577
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3578
0
                          "client sent no :path header");
3579
0
        }
3580
3581
0
        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3582
0
        return NGX_ERROR;
3583
0
    }
3584
3585
0
    r->request_line.len = r->method_name.len + 1
3586
0
                          + r->unparsed_uri.len
3587
0
                          + sizeof(ending) - 1;
3588
3589
0
    p = ngx_pnalloc(r->pool, r->request_line.len + 1);
3590
0
    if (p == NULL) {
3591
0
        ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3592
0
        return NGX_ERROR;
3593
0
    }
3594
3595
0
    r->request_line.data = p;
3596
3597
0
    p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
3598
3599
0
    *p++ = ' ';
3600
3601
0
    p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
3602
3603
0
    ngx_memcpy(p, ending, sizeof(ending));
3604
3605
0
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3606
0
                   "http2 request line: \"%V\"", &r->request_line);
3607
3608
0
    return NGX_OK;
3609
0
}
3610
3611
3612
static ngx_int_t
3613
ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3614
0
{
3615
0
    ngx_str_t    *val;
3616
0
    ngx_array_t  *cookies;
3617
3618
0
    cookies = r->stream->cookies;
3619
3620
0
    if (cookies == NULL) {
3621
0
        cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t));
3622
0
        if (cookies == NULL) {
3623
0
            return NGX_ERROR;
3624
0
        }
3625
3626
0
        r->stream->cookies = cookies;
3627
0
    }
3628
3629
0
    val = ngx_array_push(cookies);
3630
0
    if (val == NULL) {
3631
0
        return NGX_ERROR;
3632
0
    }
3633
3634
0
    val->len = header->value.len;
3635
0
    val->data = header->value.data;
3636
3637
0
    return NGX_OK;
3638
0
}
3639
3640
3641
static ngx_int_t
3642
ngx_http_v2_construct_cookie_header(ngx_http_request_t *r)
3643
0
{
3644
0
    u_char                     *buf, *p, *end;
3645
0
    size_t                      len;
3646
0
    ngx_str_t                  *vals;
3647
0
    ngx_uint_t                  i;
3648
0
    ngx_array_t                *cookies;
3649
0
    ngx_table_elt_t            *h;
3650
0
    ngx_http_header_t          *hh;
3651
0
    ngx_http_core_main_conf_t  *cmcf;
3652
3653
0
    static ngx_str_t cookie = ngx_string("cookie");
3654
3655
0
    cookies = r->stream->cookies;
3656
3657
0
    if (cookies == NULL) {
3658
0
        return NGX_OK;
3659
0
    }
3660
3661
0
    vals = cookies->elts;
3662
3663
0
    i = 0;
3664
0
    len = 0;
3665
3666
0
    do {
3667
0
        len += vals[i].len + 2;
3668
0
    } while (++i != cookies->nelts);
3669
3670
0
    len -= 2;
3671
3672
0
    buf = ngx_pnalloc(r->pool, len + 1);
3673
0
    if (buf == NULL) {
3674
0
        ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3675
0
        return NGX_ERROR;
3676
0
    }
3677
3678
0
    p = buf;
3679
0
    end = buf + len;
3680
3681
0
    for (i = 0; /* void */ ; i++) {
3682
3683
0
        p = ngx_cpymem(p, vals[i].data, vals[i].len);
3684
3685
0
        if (p == end) {
3686
0
            *p = '\0';
3687
0
            break;
3688
0
        }
3689
3690
0
        *p++ = ';'; *p++ = ' ';
3691
0
    }
3692
3693
0
    h = ngx_list_push(&r->headers_in.headers);
3694
0
    if (h == NULL) {
3695
0
        ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3696
0
        return NGX_ERROR;
3697
0
    }
3698
3699
0
    h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
3700
0
                                    ngx_hash('c', 'o'), 'o'), 'k'), 'i'), 'e');
3701
3702
0
    h->key.len = cookie.len;
3703
0
    h->key.data = cookie.data;
3704
3705
0
    h->value.len = len;
3706
0
    h->value.data = buf;
3707
3708
0
    h->lowcase_key = cookie.data;
3709
3710
0
    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3711
3712
0
    hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
3713
0
                       h->lowcase_key, h->key.len);
3714
3715
0
    if (hh == NULL) {
3716
0
        ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3717
0
        return NGX_ERROR;
3718
0
    }
3719
3720
0
    if (hh->handler(r, h, hh->offset) != NGX_OK) {
3721
        /*
3722
         * request has been finalized already
3723
         * in ngx_http_process_multi_header_lines()
3724
         */
3725
0
        return NGX_ERROR;
3726
0
    }
3727
3728
0
    return NGX_OK;
3729
0
}
3730
3731
3732
static void
3733
ngx_http_v2_run_request(ngx_http_request_t *r)
3734
0
{
3735
0
    ngx_connection_t          *fc;
3736
0
    ngx_http_v2_srv_conf_t    *h2scf;
3737
0
    ngx_http_v2_connection_t  *h2c;
3738
3739
0
    fc = r->connection;
3740
3741
0
    h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3742
3743
0
    if (!h2scf->enable && !r->http_connection->addr_conf->http2) {
3744
0
        ngx_log_error(NGX_LOG_INFO, fc->log, 0,
3745
0
                      "client attempted to request the server name "
3746
0
                      "for which the negotiated protocol is disabled");
3747
3748
0
        ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST);
3749
0
        goto failed;
3750
0
    }
3751
3752
0
    if (ngx_http_v2_construct_request_line(r) != NGX_OK) {
3753
0
        goto failed;
3754
0
    }
3755
3756
0
    if (ngx_http_v2_construct_cookie_header(r) != NGX_OK) {
3757
0
        goto failed;
3758
0
    }
3759
3760
0
    r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
3761
3762
0
    if (ngx_http_process_request_header(r) != NGX_OK) {
3763
0
        goto failed;
3764
0
    }
3765
3766
0
    if (r->headers_in.content_length_n > 0 && r->stream->in_closed) {
3767
0
        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3768
0
                      "client prematurely closed stream");
3769
3770
0
        r->stream->skip_data = 1;
3771
3772
0
        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3773
0
        goto failed;
3774
0
    }
3775
3776
0
    if (r->headers_in.content_length_n == -1 && !r->stream->in_closed) {
3777
0
        r->headers_in.chunked = 1;
3778
0
    }
3779
3780
0
    h2c = r->stream->connection;
3781
3782
0
    h2c->payload_bytes += r->request_length;
3783
3784
0
    ngx_http_process_request(r);
3785
3786
0
failed:
3787
3788
0
    ngx_http_run_posted_requests(fc);
3789
0
}
3790
3791
3792
ngx_int_t
3793
ngx_http_v2_read_request_body(ngx_http_request_t *r)
3794
0
{
3795
0
    off_t                      len;
3796
0
    size_t                     size;
3797
0
    ngx_buf_t                 *buf;
3798
0
    ngx_int_t                  rc;
3799
0
    ngx_http_v2_stream_t      *stream;
3800
0
    ngx_http_v2_srv_conf_t    *h2scf;
3801
0
    ngx_http_request_body_t   *rb;
3802
0
    ngx_http_core_loc_conf_t  *clcf;
3803
0
    ngx_http_v2_connection_t  *h2c;
3804
3805
0
    stream = r->stream;
3806
0
    rb = r->request_body;
3807
3808
0
    if (stream->skip_data) {
3809
0
        r->request_body_no_buffering = 0;
3810
0
        rb->post_handler(r);
3811
0
        return NGX_OK;
3812
0
    }
3813
3814
0
    rb->rest = 1;
3815
3816
    /* set rb->filter_need_buffering */
3817
3818
0
    rc = ngx_http_top_request_body_filter(r, NULL);
3819
3820
0
    if (rc != NGX_OK) {
3821
0
        stream->skip_data = 1;
3822
0
        return rc;
3823
0
    }
3824
3825
0
    h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3826
0
    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3827
3828
0
    len = r->headers_in.content_length_n;
3829
3830
0
    if (len < 0 || len > (off_t) clcf->client_body_buffer_size) {
3831
0
        len = clcf->client_body_buffer_size;
3832
3833
0
    } else {
3834
0
        len++;
3835
0
    }
3836
3837
0
    if (r->request_body_no_buffering || rb->filter_need_buffering) {
3838
3839
        /*
3840
         * We need a room to store data up to the stream's initial window size,
3841
         * at least until this window will be exhausted.
3842
         */
3843
3844
0
        if (len < (off_t) h2scf->preread_size) {
3845
0
            len = h2scf->preread_size;
3846
0
        }
3847
3848
0
        if (len > NGX_HTTP_V2_MAX_WINDOW) {
3849
0
            len = NGX_HTTP_V2_MAX_WINDOW;
3850
0
        }
3851
0
    }
3852
3853
0
    rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
3854
3855
0
    if (rb->buf == NULL) {
3856
0
        stream->skip_data = 1;
3857
0
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
3858
0
    }
3859
3860
0
    buf = stream->preread;
3861
3862
0
    if (stream->in_closed) {
3863
0
        if (!rb->filter_need_buffering) {
3864
0
            r->request_body_no_buffering = 0;
3865
0
        }
3866
3867
0
        if (buf) {
3868
0
            rc = ngx_http_v2_process_request_body(r, buf->pos,
3869
0
                                                  buf->last - buf->pos, 1, 0);
3870
0
            ngx_pfree(r->pool, buf->start);
3871
3872
0
        } else {
3873
0
            rc = ngx_http_v2_process_request_body(r, NULL, 0, 1, 0);
3874
0
        }
3875
3876
0
        if (rc != NGX_AGAIN) {
3877
0
            return rc;
3878
0
        }
3879
3880
0
        r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
3881
0
        r->write_event_handler = ngx_http_request_empty_handler;
3882
3883
0
        return NGX_AGAIN;
3884
0
    }
3885
3886
0
    if (buf) {
3887
0
        rc = ngx_http_v2_process_request_body(r, buf->pos,
3888
0
                                              buf->last - buf->pos, 0, 0);
3889
3890
0
        ngx_pfree(r->pool, buf->start);
3891
3892
0
        if (rc != NGX_OK && rc != NGX_AGAIN) {
3893
0
            stream->skip_data = 1;
3894
0
            return rc;
3895
0
        }
3896
0
    }
3897
3898
0
    if (r->request_body_no_buffering || rb->filter_need_buffering) {
3899
0
        size = (size_t) len - h2scf->preread_size;
3900
3901
0
    } else {
3902
0
        stream->no_flow_control = 1;
3903
0
        size = NGX_HTTP_V2_MAX_WINDOW - stream->recv_window;
3904
0
    }
3905
3906
0
    if (size) {
3907
0
        if (ngx_http_v2_send_window_update(stream->connection,
3908
0
                                           stream->node->id, size)
3909
0
            == NGX_ERROR)
3910
0
        {
3911
0
            stream->skip_data = 1;
3912
0
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
3913
0
        }
3914
3915
0
        h2c = stream->connection;
3916
3917
0
        if (!h2c->blocked) {
3918
0
            if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
3919
0
                stream->skip_data = 1;
3920
0
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
3921
0
            }
3922
0
        }
3923
3924
0
        stream->recv_window += size;
3925
0
    }
3926
3927
0
    if (!buf) {
3928
0
        ngx_add_timer(r->connection->read, clcf->client_body_timeout);
3929
0
    }
3930
3931
0
    r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
3932
0
    r->write_event_handler = ngx_http_request_empty_handler;
3933
3934
0
    return NGX_AGAIN;
3935
0
}
3936
3937
3938
static ngx_int_t
3939
ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos,
3940
    size_t size, ngx_uint_t last, ngx_uint_t flush)
3941
0
{
3942
0
    size_t                     n;
3943
0
    ngx_int_t                  rc;
3944
0
    ngx_connection_t          *fc;
3945
0
    ngx_http_request_body_t   *rb;
3946
0
    ngx_http_core_loc_conf_t  *clcf;
3947
3948
0
    fc = r->connection;
3949
0
    rb = r->request_body;
3950
3951
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
3952
0
                   "http2 process request body");
3953
3954
0
    if (size == 0 && !last && !flush) {
3955
0
        return NGX_AGAIN;
3956
0
    }
3957
3958
0
    for ( ;; ) {
3959
0
        for ( ;; ) {
3960
0
            if (rb->buf->last == rb->buf->end && size) {
3961
3962
0
                if (r->request_body_no_buffering) {
3963
3964
                    /* should never happen due to flow control */
3965
3966
0
                    ngx_log_error(NGX_LOG_ALERT, fc->log, 0,
3967
0
                                  "no space in http2 body buffer");
3968
3969
0
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
3970
0
                }
3971
3972
                /* update chains */
3973
3974
0
                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
3975
0
                               "http2 body update chains");
3976
3977
0
                rc = ngx_http_v2_filter_request_body(r);
3978
3979
0
                if (rc != NGX_OK) {
3980
0
                    return rc;
3981
0
                }
3982
3983
0
                if (rb->busy != NULL) {
3984
0
                    ngx_log_error(NGX_LOG_ALERT, fc->log, 0,
3985
0
                                  "busy buffers after request body flush");
3986
0
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
3987
0
                }
3988
3989
0
                rb->buf->pos = rb->buf->start;
3990
0
                rb->buf->last = rb->buf->start;
3991
0
            }
3992
3993
            /* copy body data to the buffer */
3994
3995
0
            n = rb->buf->end - rb->buf->last;
3996
3997
0
            if (n > size) {
3998
0
                n = size;
3999
0
            }
4000
4001
0
            if (n > 0) {
4002
0
                rb->buf->last = ngx_cpymem(rb->buf->last, pos, n);
4003
0
            }
4004
4005
0
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4006
0
                           "http2 request body recv %uz", n);
4007
4008
0
            pos += n;
4009
0
            size -= n;
4010
4011
0
            if (size == 0 && last) {
4012
0
                rb->rest = 0;
4013
0
            }
4014
4015
0
            if (size == 0) {
4016
0
                break;
4017
0
            }
4018
0
        }
4019
4020
0
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4021
0
                       "http2 request body rest %O", rb->rest);
4022
4023
0
        if (flush) {
4024
0
            rc = ngx_http_v2_filter_request_body(r);
4025
4026
0
            if (rc != NGX_OK) {
4027
0
                return rc;
4028
0
            }
4029
0
        }
4030
4031
0
        if (rb->rest == 0 && rb->last_saved) {
4032
0
            break;
4033
0
        }
4034
4035
0
        if (size == 0) {
4036
0
            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4037
0
            ngx_add_timer(fc->read, clcf->client_body_timeout);
4038
4039
0
            if (!flush) {
4040
0
                ngx_post_event(fc->read, &ngx_posted_events);
4041
0
            }
4042
4043
0
            return NGX_AGAIN;
4044
0
        }
4045
0
    }
4046
4047
0
    if (fc->read->timer_set) {
4048
0
        ngx_del_timer(fc->read);
4049
0
    }
4050
4051
0
    if (r->request_body_no_buffering) {
4052
0
        if (!flush) {
4053
0
            ngx_post_event(fc->read, &ngx_posted_events);
4054
0
        }
4055
4056
0
        return NGX_OK;
4057
0
    }
4058
4059
0
    if (r->headers_in.chunked) {
4060
0
        r->headers_in.content_length_n = rb->received;
4061
0
    }
4062
4063
0
    r->read_event_handler = ngx_http_block_reading;
4064
0
    rb->post_handler(r);
4065
4066
0
    return NGX_OK;
4067
0
}
4068
4069
4070
static ngx_int_t
4071
ngx_http_v2_filter_request_body(ngx_http_request_t *r)
4072
0
{
4073
0
    ngx_buf_t                 *b, *buf;
4074
0
    ngx_int_t                  rc;
4075
0
    ngx_chain_t               *cl;
4076
0
    ngx_http_request_body_t   *rb;
4077
0
    ngx_http_core_loc_conf_t  *clcf;
4078
4079
0
    rb = r->request_body;
4080
0
    buf = rb->buf;
4081
4082
0
    if (buf->pos == buf->last && (rb->rest || rb->last_sent)) {
4083
0
        cl = NULL;
4084
0
        goto update;
4085
0
    }
4086
4087
0
    cl = ngx_chain_get_free_buf(r->pool, &rb->free);
4088
0
    if (cl == NULL) {
4089
0
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
4090
0
    }
4091
4092
0
    b = cl->buf;
4093
4094
0
    ngx_memzero(b, sizeof(ngx_buf_t));
4095
4096
0
    if (buf->pos != buf->last) {
4097
0
        r->request_length += buf->last - buf->pos;
4098
0
        rb->received += buf->last - buf->pos;
4099
4100
0
        if (r->headers_in.content_length_n != -1) {
4101
0
            if (rb->received > r->headers_in.content_length_n) {
4102
0
                ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
4103
0
                              "client intended to send body data "
4104
0
                              "larger than declared");
4105
4106
0
                return NGX_HTTP_BAD_REQUEST;
4107
0
            }
4108
4109
0
        } else {
4110
0
            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4111
4112
0
            if (clcf->client_max_body_size
4113
0
                && rb->received > clcf->client_max_body_size)
4114
0
            {
4115
0
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
4116
0
                              "client intended to send too large chunked body: "
4117
0
                              "%O bytes", rb->received);
4118
4119
0
                return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
4120
0
            }
4121
0
        }
4122
4123
0
        b->temporary = 1;
4124
0
        b->pos = buf->pos;
4125
0
        b->last = buf->last;
4126
0
        b->start = b->pos;
4127
0
        b->end = b->last;
4128
4129
0
        buf->pos = buf->last;
4130
0
    }
4131
4132
0
    if (!rb->rest) {
4133
0
        if (r->headers_in.content_length_n != -1
4134
0
            && r->headers_in.content_length_n != rb->received)
4135
0
        {
4136
0
            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
4137
0
                          "client prematurely closed stream: "
4138
0
                          "only %O out of %O bytes of request body received",
4139
0
                          rb->received, r->headers_in.content_length_n);
4140
4141
0
            return NGX_HTTP_BAD_REQUEST;
4142
0
        }
4143
4144
0
        b->last_buf = 1;
4145
0
        rb->last_sent = 1;
4146
0
    }
4147
4148
0
    b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body;
4149
0
    b->flush = r->request_body_no_buffering;
4150
4151
0
update:
4152
4153
0
    rc = ngx_http_top_request_body_filter(r, cl);
4154
4155
0
    ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &cl,
4156
0
                            (ngx_buf_tag_t) &ngx_http_v2_filter_request_body);
4157
4158
0
    return rc;
4159
0
}
4160
4161
4162
static void
4163
ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r)
4164
0
{
4165
0
    size_t                     window;
4166
0
    ngx_buf_t                 *buf;
4167
0
    ngx_int_t                  rc;
4168
0
    ngx_connection_t          *fc;
4169
0
    ngx_http_v2_stream_t      *stream;
4170
0
    ngx_http_v2_connection_t  *h2c;
4171
4172
0
    fc = r->connection;
4173
4174
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4175
0
                   "http2 read client request body handler");
4176
4177
0
    if (fc->read->timedout) {
4178
0
        ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
4179
4180
0
        fc->timedout = 1;
4181
0
        r->stream->skip_data = 1;
4182
4183
0
        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
4184
0
        return;
4185
0
    }
4186
4187
0
    if (fc->error) {
4188
0
        ngx_log_error(NGX_LOG_INFO, fc->log, 0,
4189
0
                      "client prematurely closed stream");
4190
4191
0
        r->stream->skip_data = 1;
4192
4193
0
        ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
4194
0
        return;
4195
0
    }
4196
4197
0
    rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1);
4198
4199
0
    if (rc != NGX_OK && rc != NGX_AGAIN) {
4200
0
        r->stream->skip_data = 1;
4201
0
        ngx_http_finalize_request(r, rc);
4202
0
        return;
4203
0
    }
4204
4205
0
    if (rc == NGX_OK) {
4206
0
        return;
4207
0
    }
4208
4209
0
    if (r->stream->no_flow_control) {
4210
0
        return;
4211
0
    }
4212
4213
0
    if (r->request_body->rest == 0) {
4214
0
        return;
4215
0
    }
4216
4217
0
    if (r->request_body->busy != NULL) {
4218
0
        return;
4219
0
    }
4220
4221
0
    stream = r->stream;
4222
0
    h2c = stream->connection;
4223
4224
0
    buf = r->request_body->buf;
4225
4226
0
    buf->pos = buf->start;
4227
0
    buf->last = buf->start;
4228
4229
0
    window = buf->end - buf->start;
4230
4231
0
    if (h2c->state.stream == stream) {
4232
0
        window -= h2c->state.length;
4233
0
    }
4234
4235
0
    if (window <= stream->recv_window) {
4236
0
        if (window < stream->recv_window) {
4237
0
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
4238
0
                          "http2 negative window update");
4239
4240
0
            stream->skip_data = 1;
4241
4242
0
            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
4243
0
            return;
4244
0
        }
4245
4246
0
        return;
4247
0
    }
4248
4249
0
    if (ngx_http_v2_send_window_update(h2c, stream->node->id,
4250
0
                                       window - stream->recv_window)
4251
0
        == NGX_ERROR)
4252
0
    {
4253
0
        stream->skip_data = 1;
4254
0
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
4255
0
        return;
4256
0
    }
4257
4258
0
    stream->recv_window = window;
4259
4260
0
    if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4261
0
        stream->skip_data = 1;
4262
0
        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
4263
0
        return;
4264
0
    }
4265
0
}
4266
4267
4268
ngx_int_t
4269
ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r)
4270
0
{
4271
0
    size_t                     window;
4272
0
    ngx_buf_t                 *buf;
4273
0
    ngx_int_t                  rc;
4274
0
    ngx_connection_t          *fc;
4275
0
    ngx_http_v2_stream_t      *stream;
4276
0
    ngx_http_v2_connection_t  *h2c;
4277
4278
0
    stream = r->stream;
4279
0
    fc = r->connection;
4280
4281
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4282
0
                   "http2 read unbuffered request body");
4283
4284
0
    if (fc->read->timedout) {
4285
0
        if (stream->recv_window) {
4286
0
            stream->skip_data = 1;
4287
0
            fc->timedout = 1;
4288
4289
0
            return NGX_HTTP_REQUEST_TIME_OUT;
4290
0
        }
4291
4292
0
        fc->read->timedout = 0;
4293
0
    }
4294
4295
0
    if (fc->error) {
4296
0
        stream->skip_data = 1;
4297
0
        return NGX_HTTP_BAD_REQUEST;
4298
0
    }
4299
4300
0
    rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1);
4301
4302
0
    if (rc != NGX_OK && rc != NGX_AGAIN) {
4303
0
        stream->skip_data = 1;
4304
0
        return rc;
4305
0
    }
4306
4307
0
    if (rc == NGX_OK) {
4308
0
        return NGX_OK;
4309
0
    }
4310
4311
0
    if (r->request_body->rest == 0) {
4312
0
        return NGX_AGAIN;
4313
0
    }
4314
4315
0
    if (r->request_body->busy != NULL) {
4316
0
        return NGX_AGAIN;
4317
0
    }
4318
4319
0
    buf = r->request_body->buf;
4320
4321
0
    buf->pos = buf->start;
4322
0
    buf->last = buf->start;
4323
4324
0
    window = buf->end - buf->start;
4325
0
    h2c = stream->connection;
4326
4327
0
    if (h2c->state.stream == stream) {
4328
0
        window -= h2c->state.length;
4329
0
    }
4330
4331
0
    if (window <= stream->recv_window) {
4332
0
        if (window < stream->recv_window) {
4333
0
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
4334
0
                          "http2 negative window update");
4335
0
            stream->skip_data = 1;
4336
0
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
4337
0
        }
4338
4339
0
        return NGX_AGAIN;
4340
0
    }
4341
4342
0
    if (ngx_http_v2_send_window_update(h2c, stream->node->id,
4343
0
                                       window - stream->recv_window)
4344
0
        == NGX_ERROR)
4345
0
    {
4346
0
        stream->skip_data = 1;
4347
0
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
4348
0
    }
4349
4350
0
    if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4351
0
        stream->skip_data = 1;
4352
0
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
4353
0
    }
4354
4355
0
    stream->recv_window = window;
4356
4357
0
    return NGX_AGAIN;
4358
0
}
4359
4360
4361
static ngx_int_t
4362
ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
4363
    ngx_http_v2_stream_t *stream, ngx_uint_t status)
4364
0
{
4365
0
    ngx_event_t       *rev;
4366
0
    ngx_connection_t  *fc;
4367
4368
0
    if (stream->rst_sent) {
4369
0
        return NGX_OK;
4370
0
    }
4371
4372
0
    if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status)
4373
0
        == NGX_ERROR)
4374
0
    {
4375
0
        return NGX_ERROR;
4376
0
    }
4377
4378
0
    stream->rst_sent = 1;
4379
0
    stream->skip_data = 1;
4380
4381
0
    fc = stream->request->connection;
4382
0
    fc->error = 1;
4383
4384
0
    rev = fc->read;
4385
0
    rev->handler(rev);
4386
4387
0
    return NGX_OK;
4388
0
}
4389
4390
4391
void
4392
ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
4393
0
{
4394
0
    ngx_pool_t                *pool;
4395
0
    ngx_event_t               *ev;
4396
0
    ngx_connection_t          *fc;
4397
0
    ngx_http_v2_node_t        *node;
4398
0
    ngx_http_v2_connection_t  *h2c;
4399
4400
0
    h2c = stream->connection;
4401
0
    node = stream->node;
4402
4403
0
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
4404
0
                   "http2 close stream %ui, queued %ui, processing %ui",
4405
0
                   node->id, stream->queued, h2c->processing);
4406
4407
0
    fc = stream->request->connection;
4408
4409
0
    if (stream->queued) {
4410
0
        fc->error = 1;
4411
0
        fc->write->handler = ngx_http_v2_retry_close_stream_handler;
4412
0
        fc->read->handler = ngx_http_v2_retry_close_stream_handler;
4413
0
        return;
4414
0
    }
4415
4416
0
    if (!stream->rst_sent && !h2c->connection->error) {
4417
4418
0
        if (!stream->out_closed) {
4419
0
            if (ngx_http_v2_send_rst_stream(h2c, node->id,
4420
0
                                      fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR
4421
0
                                                   : NGX_HTTP_V2_INTERNAL_ERROR)
4422
0
                != NGX_OK)
4423
0
            {
4424
0
                h2c->connection->error = 1;
4425
0
            }
4426
4427
0
        } else if (!stream->in_closed) {
4428
0
            if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
4429
0
                != NGX_OK)
4430
0
            {
4431
0
                h2c->connection->error = 1;
4432
0
            }
4433
0
        }
4434
0
    }
4435
4436
0
    if (h2c->state.stream == stream) {
4437
0
        h2c->state.stream = NULL;
4438
0
    }
4439
4440
0
    node->stream = NULL;
4441
4442
0
    ngx_queue_insert_tail(&h2c->closed, &node->reuse);
4443
0
    h2c->closed_nodes++;
4444
4445
    /*
4446
     * This pool keeps decoded request headers which can be used by log phase
4447
     * handlers in ngx_http_free_request().
4448
     *
4449
     * The pointer is stored into local variable because the stream object
4450
     * will be destroyed after a call to ngx_http_free_request().
4451
     */
4452
0
    pool = stream->pool;
4453
4454
0
    h2c->frames -= stream->frames;
4455
4456
0
    ngx_http_free_request(stream->request, rc);
4457
4458
0
    if (pool != h2c->state.pool) {
4459
0
        ngx_destroy_pool(pool);
4460
4461
0
    } else {
4462
        /* pool will be destroyed when the complete header is parsed */
4463
0
        h2c->state.keep_pool = 0;
4464
0
    }
4465
4466
0
    ev = fc->read;
4467
4468
0
    if (ev->timer_set) {
4469
0
        ngx_del_timer(ev);
4470
0
    }
4471
4472
0
    if (ev->posted) {
4473
0
        ngx_delete_posted_event(ev);
4474
0
    }
4475
4476
0
    ev = fc->write;
4477
4478
0
    if (ev->timer_set) {
4479
0
        ngx_del_timer(ev);
4480
0
    }
4481
4482
0
    if (ev->posted) {
4483
0
        ngx_delete_posted_event(ev);
4484
0
    }
4485
4486
0
    fc->data = h2c->free_fake_connections;
4487
0
    h2c->free_fake_connections = fc;
4488
4489
0
    h2c->processing--;
4490
4491
0
    if (h2c->processing || h2c->blocked) {
4492
0
        return;
4493
0
    }
4494
4495
0
    ev = h2c->connection->read;
4496
4497
0
    ev->handler = ngx_http_v2_handle_connection_handler;
4498
0
    ngx_post_event(ev, &ngx_posted_events);
4499
0
}
4500
4501
4502
static void
4503
ngx_http_v2_close_stream_handler(ngx_event_t *ev)
4504
0
{
4505
0
    ngx_connection_t    *fc;
4506
0
    ngx_http_request_t  *r;
4507
4508
0
    fc = ev->data;
4509
0
    r = fc->data;
4510
4511
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4512
0
                   "http2 close stream handler");
4513
4514
0
    if (ev->timedout) {
4515
0
        ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
4516
4517
0
        fc->timedout = 1;
4518
4519
0
        ngx_http_v2_close_stream(r->stream, NGX_HTTP_REQUEST_TIME_OUT);
4520
0
        return;
4521
0
    }
4522
4523
0
    ngx_http_v2_close_stream(r->stream, 0);
4524
0
}
4525
4526
4527
static void
4528
ngx_http_v2_retry_close_stream_handler(ngx_event_t *ev)
4529
0
{
4530
0
    ngx_connection_t    *fc;
4531
0
    ngx_http_request_t  *r;
4532
4533
0
    fc = ev->data;
4534
0
    r = fc->data;
4535
4536
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4537
0
                   "http2 retry close stream handler");
4538
4539
0
    ngx_http_v2_close_stream(r->stream, 0);
4540
0
}
4541
4542
4543
static void
4544
ngx_http_v2_handle_connection_handler(ngx_event_t *rev)
4545
0
{
4546
0
    ngx_connection_t          *c;
4547
0
    ngx_http_v2_connection_t  *h2c;
4548
4549
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
4550
0
                   "http2 handle connection handler");
4551
4552
0
    c = rev->data;
4553
0
    h2c = c->data;
4554
4555
0
    if (c->error) {
4556
0
        ngx_http_v2_finalize_connection(h2c, 0);
4557
0
        return;
4558
0
    }
4559
4560
0
    rev->handler = ngx_http_v2_read_handler;
4561
4562
0
    if (rev->ready) {
4563
0
        ngx_http_v2_read_handler(rev);
4564
0
        return;
4565
0
    }
4566
4567
0
    if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4568
0
        ngx_http_v2_finalize_connection(h2c, 0);
4569
0
        return;
4570
0
    }
4571
4572
0
    ngx_http_v2_handle_connection(c->data);
4573
0
}
4574
4575
4576
static void
4577
ngx_http_v2_idle_handler(ngx_event_t *rev)
4578
0
{
4579
0
    ngx_connection_t          *c;
4580
0
    ngx_http_v2_srv_conf_t    *h2scf;
4581
0
    ngx_http_v2_connection_t  *h2c;
4582
0
    ngx_http_core_loc_conf_t  *clcf;
4583
4584
0
    c = rev->data;
4585
0
    h2c = c->data;
4586
4587
0
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 idle handler");
4588
4589
0
    if (rev->timedout || c->close) {
4590
0
        ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
4591
0
        return;
4592
0
    }
4593
4594
#if (NGX_HAVE_KQUEUE)
4595
4596
    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
4597
        if (rev->pending_eof) {
4598
            c->log->handler = NULL;
4599
            ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
4600
                          "kevent() reported that client %V closed "
4601
                          "idle connection", &c->addr_text);
4602
#if (NGX_HTTP_SSL)
4603
            if (c->ssl) {
4604
                c->ssl->no_send_shutdown = 1;
4605
            }
4606
#endif
4607
            ngx_http_close_connection(c);
4608
            return;
4609
        }
4610
    }
4611
4612
#endif
4613
4614
0
    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
4615
0
                                        ngx_http_core_module);
4616
4617
0
    if (h2c->idle++ > 10 * clcf->keepalive_requests) {
4618
0
        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
4619
0
                      "http2 flood detected");
4620
0
        ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
4621
0
        return;
4622
0
    }
4623
4624
0
    c->destroyed = 0;
4625
0
    ngx_reusable_connection(c, 0);
4626
4627
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4628
0
                                         ngx_http_v2_module);
4629
4630
0
    h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
4631
0
    if (h2c->pool == NULL) {
4632
0
        ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
4633
0
        return;
4634
0
    }
4635
4636
0
    c->write->handler = ngx_http_v2_write_handler;
4637
4638
0
    rev->handler = ngx_http_v2_read_handler;
4639
0
    ngx_http_v2_read_handler(rev);
4640
0
}
4641
4642
4643
static void
4644
ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
4645
    ngx_uint_t status)
4646
0
{
4647
0
    ngx_uint_t               i, size;
4648
0
    ngx_event_t             *ev;
4649
0
    ngx_connection_t        *c, *fc;
4650
0
    ngx_http_request_t      *r;
4651
0
    ngx_http_v2_node_t      *node;
4652
0
    ngx_http_v2_stream_t    *stream;
4653
0
    ngx_http_v2_srv_conf_t  *h2scf;
4654
4655
0
    c = h2c->connection;
4656
4657
0
    h2c->blocked = 1;
4658
4659
0
    if (!c->error && !h2c->goaway) {
4660
0
        h2c->goaway = 1;
4661
4662
0
        if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
4663
0
            (void) ngx_http_v2_send_output_queue(h2c);
4664
0
        }
4665
0
    }
4666
4667
0
    if (!h2c->processing) {
4668
0
        goto done;
4669
0
    }
4670
4671
0
    c->read->handler = ngx_http_empty_handler;
4672
0
    c->write->handler = ngx_http_empty_handler;
4673
4674
0
    h2c->last_out = NULL;
4675
4676
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4677
0
                                         ngx_http_v2_module);
4678
4679
0
    size = ngx_http_v2_index_size(h2scf);
4680
4681
0
    for (i = 0; i < size; i++) {
4682
4683
0
        for (node = h2c->streams_index[i]; node; node = node->index) {
4684
0
            stream = node->stream;
4685
4686
0
            if (stream == NULL) {
4687
0
                continue;
4688
0
            }
4689
4690
0
            stream->waiting = 0;
4691
4692
0
            r = stream->request;
4693
0
            fc = r->connection;
4694
4695
0
            fc->error = 1;
4696
4697
0
            if (stream->queued) {
4698
0
                stream->queued = 0;
4699
4700
0
                ev = fc->write;
4701
0
                ev->active = 0;
4702
0
                ev->ready = 1;
4703
4704
0
            } else {
4705
0
                ev = fc->read;
4706
0
            }
4707
4708
0
            ev->eof = 1;
4709
0
            ev->handler(ev);
4710
0
        }
4711
0
    }
4712
4713
0
    h2c->blocked = 0;
4714
4715
0
    if (h2c->processing) {
4716
0
        c->error = 1;
4717
0
        return;
4718
0
    }
4719
4720
0
done:
4721
4722
0
    if (c->error) {
4723
0
        ngx_http_close_connection(c);
4724
0
        return;
4725
0
    }
4726
4727
0
    ngx_http_v2_lingering_close(c);
4728
0
}
4729
4730
4731
static ngx_int_t
4732
ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, ssize_t delta)
4733
0
{
4734
0
    ngx_uint_t               i, size;
4735
0
    ngx_event_t             *wev;
4736
0
    ngx_http_v2_node_t      *node;
4737
0
    ngx_http_v2_stream_t    *stream;
4738
0
    ngx_http_v2_srv_conf_t  *h2scf;
4739
4740
0
    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4741
0
                                         ngx_http_v2_module);
4742
4743
0
    size = ngx_http_v2_index_size(h2scf);
4744
4745
0
    for (i = 0; i < size; i++) {
4746
4747
0
        for (node = h2c->streams_index[i]; node; node = node->index) {
4748
0
            stream = node->stream;
4749
4750
0
            if (stream == NULL) {
4751
0
                continue;
4752
0
            }
4753
4754
0
            if (delta > 0
4755
0
                && stream->send_window
4756
0
                      > (ssize_t) (NGX_HTTP_V2_MAX_WINDOW - delta))
4757
0
            {
4758
0
                if (ngx_http_v2_terminate_stream(h2c, stream,
4759
0
                                                 NGX_HTTP_V2_FLOW_CTRL_ERROR)
4760
0
                    == NGX_ERROR)
4761
0
                {
4762
0
                    return NGX_ERROR;
4763
0
                }
4764
4765
0
                continue;
4766
0
            }
4767
4768
0
            stream->send_window += delta;
4769
4770
0
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
4771
0
                           "http2:%ui adjusted window: %z",
4772
0
                           node->id, stream->send_window);
4773
4774
0
            if (stream->send_window > 0 && stream->exhausted) {
4775
0
                stream->exhausted = 0;
4776
4777
0
                wev = stream->request->connection->write;
4778
4779
0
                wev->active = 0;
4780
0
                wev->ready = 1;
4781
4782
0
                if (!wev->delayed) {
4783
0
                    wev->handler(wev);
4784
0
                }
4785
0
            }
4786
0
        }
4787
0
    }
4788
4789
0
    return NGX_OK;
4790
0
}
4791
4792
4793
static void
4794
ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
4795
    ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive)
4796
0
{
4797
0
    ngx_queue_t         *children, *q;
4798
0
    ngx_http_v2_node_t  *parent, *child, *next;
4799
4800
0
    parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL;
4801
4802
0
    if (parent == NULL) {
4803
0
        parent = NGX_HTTP_V2_ROOT;
4804
4805
0
        if (depend != 0) {
4806
0
            exclusive = 0;
4807
0
        }
4808
4809
0
        node->rank = 1;
4810
0
        node->rel_weight = (1.0 / 256) * node->weight;
4811
4812
0
        children = &h2c->dependencies;
4813
4814
0
    } else {
4815
0
        if (node->parent != NULL) {
4816
4817
0
            for (next = parent->parent;
4818
0
                 next != NGX_HTTP_V2_ROOT && next->rank >= node->rank;
4819
0
                 next = next->parent)
4820
0
            {
4821
0
                if (next != node) {
4822
0
                    continue;
4823
0
                }
4824
4825
0
                ngx_queue_remove(&parent->queue);
4826
0
                ngx_queue_insert_after(&node->queue, &parent->queue);
4827
4828
0
                parent->parent = node->parent;
4829
4830
0
                if (node->parent == NGX_HTTP_V2_ROOT) {
4831
0
                    parent->rank = 1;
4832
0
                    parent->rel_weight = (1.0 / 256) * parent->weight;
4833
4834
0
                } else {
4835
0
                    parent->rank = node->parent->rank + 1;
4836
0
                    parent->rel_weight = (node->parent->rel_weight / 256)
4837
0
                                         * parent->weight;
4838
0
                }
4839
4840
0
                if (!exclusive) {
4841
0
                    ngx_http_v2_node_children_update(parent);
4842
0
                }
4843
4844
0
                break;
4845
0
            }
4846
0
        }
4847
4848
0
        node->rank = parent->rank + 1;
4849
0
        node->rel_weight = (parent->rel_weight / 256) * node->weight;
4850
4851
0
        if (parent->stream == NULL) {
4852
0
            ngx_queue_remove(&parent->reuse);
4853
0
            ngx_queue_insert_tail(&h2c->closed, &parent->reuse);
4854
0
        }
4855
4856
0
        children = &parent->children;
4857
0
    }
4858
4859
0
    if (exclusive) {
4860
0
        for (q = ngx_queue_head(children);
4861
0
             q != ngx_queue_sentinel(children);
4862
0
             q = ngx_queue_next(q))
4863
0
        {
4864
0
            child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
4865
0
            child->parent = node;
4866
0
        }
4867
4868
0
        ngx_queue_add(&node->children, children);
4869
0
        ngx_queue_init(children);
4870
0
    }
4871
4872
0
    if (node->parent != NULL) {
4873
0
        ngx_queue_remove(&node->queue);
4874
0
    }
4875
4876
0
    ngx_queue_insert_tail(children, &node->queue);
4877
4878
0
    node->parent = parent;
4879
4880
0
    ngx_http_v2_node_children_update(node);
4881
0
}
4882
4883
4884
static void
4885
ngx_http_v2_node_children_update(ngx_http_v2_node_t *node)
4886
0
{
4887
0
    ngx_queue_t         *q;
4888
0
    ngx_http_v2_node_t  *child;
4889
4890
0
    for (q = ngx_queue_head(&node->children);
4891
0
         q != ngx_queue_sentinel(&node->children);
4892
0
         q = ngx_queue_next(q))
4893
0
    {
4894
0
        child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
4895
4896
0
        child->rank = node->rank + 1;
4897
0
        child->rel_weight = (node->rel_weight / 256) * child->weight;
4898
4899
0
        ngx_http_v2_node_children_update(child);
4900
0
    }
4901
0
}
4902
4903
4904
static void
4905
ngx_http_v2_pool_cleanup(void *data)
4906
0
{
4907
0
    ngx_http_v2_connection_t  *h2c = data;
4908
4909
0
    if (h2c->state.pool) {
4910
0
        ngx_destroy_pool(h2c->state.pool);
4911
0
    }
4912
4913
0
    if (h2c->pool) {
4914
0
        ngx_destroy_pool(h2c->pool);
4915
0
    }
4916
0
}