Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2.c @ 6246:257b51c37c5a
The HTTP/2 implementation (RFC 7240, 7241).
The SPDY support is removed, as it's incompatible with the new module.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Fri, 11 Sep 2015 20:13:06 +0300 |
parents | |
children | f5380c244cd7 |
comparison
equal
deleted
inserted
replaced
6245:3cf25d33886a | 6246:257b51c37c5a |
---|---|
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 #define NGX_HTTP_V2_NO_ERROR 0x0 | |
16 #define NGX_HTTP_V2_PROTOCOL_ERROR 0x1 | |
17 #define NGX_HTTP_V2_INTERNAL_ERROR 0x2 | |
18 #define NGX_HTTP_V2_FLOW_CTRL_ERROR 0x3 | |
19 #define NGX_HTTP_V2_SETTINGS_TIMEOUT 0x4 | |
20 #define NGX_HTTP_V2_STREAM_CLOSED 0x5 | |
21 #define NGX_HTTP_V2_SIZE_ERROR 0x6 | |
22 #define NGX_HTTP_V2_REFUSED_STREAM 0x7 | |
23 #define NGX_HTTP_V2_CANCEL 0x8 | |
24 #define NGX_HTTP_V2_COMP_ERROR 0x9 | |
25 #define NGX_HTTP_V2_CONNECT_ERROR 0xa | |
26 #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 #define NGX_HTTP_V2_RST_STREAM_SIZE 4 | |
32 #define NGX_HTTP_V2_PRIORITY_SIZE 5 | |
33 #define NGX_HTTP_V2_PING_SIZE 8 | |
34 #define NGX_HTTP_V2_GOAWAY_SIZE 8 | |
35 #define NGX_HTTP_V2_WINDOW_UPDATE_SIZE 4 | |
36 | |
37 #define NGX_HTTP_V2_STREAM_ID_SIZE 4 | |
38 | |
39 #define NGX_HTTP_V2_SETTINGS_PARAM_SIZE 6 | |
40 | |
41 /* settings fields */ | |
42 #define NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING 0x1 | |
43 #define NGX_HTTP_V2_MAX_STREAMS_SETTING 0x3 | |
44 #define NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING 0x4 | |
45 #define NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING 0x5 | |
46 | |
47 #define NGX_HTTP_V2_FRAME_BUFFER_SIZE 24 | |
48 | |
49 #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14) | |
50 | |
51 #define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) | |
52 #define NGX_HTTP_V2_DEFAULT_WINDOW 65535 | |
53 | |
54 #define NGX_HTTP_V2_ROOT (void *) -1 | |
55 | |
56 | |
57 static void ngx_http_v2_read_handler(ngx_event_t *rev); | |
58 static void ngx_http_v2_write_handler(ngx_event_t *wev); | |
59 static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c); | |
60 | |
61 static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, | |
62 u_char *pos, u_char *end); | |
63 static u_char *ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, | |
64 u_char *pos, u_char *end); | |
65 static u_char *ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, | |
66 u_char *pos, u_char *end); | |
67 static u_char *ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, | |
68 u_char *pos, u_char *end); | |
69 static u_char *ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, | |
70 u_char *pos, u_char *end); | |
71 static u_char *ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, | |
72 u_char *pos, u_char *end); | |
73 static u_char *ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, | |
74 u_char *pos, u_char *end); | |
75 static u_char *ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, | |
76 u_char *pos, u_char *end); | |
77 static u_char *ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, | |
78 u_char *pos, u_char *end); | |
79 static u_char *ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, | |
80 u_char *pos, u_char *end); | |
81 static u_char *ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, | |
82 u_char *pos, u_char *end); | |
83 static u_char *ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, | |
84 u_char *pos, u_char *end); | |
85 static u_char *ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, | |
86 u_char *pos, u_char *end); | |
87 static u_char *ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, | |
88 u_char *pos, u_char *end); | |
89 static u_char *ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, | |
90 u_char *pos, u_char *end); | |
91 static u_char *ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, | |
92 u_char *pos, u_char *end); | |
93 static u_char *ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, | |
94 u_char *pos, u_char *end); | |
95 static u_char *ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, | |
96 u_char *pos, u_char *end); | |
97 static u_char *ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, | |
98 u_char *pos, u_char *end); | |
99 static u_char *ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, | |
100 u_char *pos, u_char *end); | |
101 static u_char *ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, | |
102 u_char *pos, u_char *end); | |
103 static u_char *ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, | |
104 u_char *pos, u_char *end); | |
105 static u_char *ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, | |
106 u_char *pos, u_char *end); | |
107 static u_char *ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, | |
108 u_char *pos, u_char *end); | |
109 static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, | |
110 u_char *pos, u_char *end); | |
111 static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, | |
112 u_char *pos, u_char *end); | |
113 static u_char *ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, | |
114 u_char *pos, u_char *end); | |
115 static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, | |
116 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); | |
117 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, | |
118 ngx_uint_t err); | |
119 | |
120 static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, | |
121 u_char **pos, u_char *end, ngx_uint_t prefix); | |
122 | |
123 static ngx_http_v2_stream_t *ngx_http_v2_create_stream( | |
124 ngx_http_v2_connection_t *h2c); | |
125 static ngx_http_v2_node_t *ngx_http_v2_get_node_by_id( | |
126 ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t alloc); | |
127 static ngx_http_v2_node_t *ngx_http_v2_get_closed_node( | |
128 ngx_http_v2_connection_t *h2c); | |
129 #define ngx_http_v2_index_size(h2scf) (h2scf->streams_index_mask + 1) | |
130 #define ngx_http_v2_index(h2scf, sid) ((sid >> 1) & h2scf->streams_index_mask) | |
131 | |
132 static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, | |
133 ngx_uint_t ack); | |
134 static ngx_int_t ngx_http_v2_settings_frame_handler( | |
135 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); | |
136 static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, | |
137 ngx_uint_t sid, size_t window); | |
138 static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, | |
139 ngx_uint_t sid, ngx_uint_t status); | |
140 | |
141 static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame( | |
142 ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type, | |
143 u_char flags, ngx_uint_t sid); | |
144 static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, | |
145 ngx_http_v2_out_frame_t *frame); | |
146 | |
147 static ngx_int_t ngx_http_v2_validate_header(ngx_http_request_t *r, | |
148 ngx_http_v2_header_t *header); | |
149 static ngx_int_t ngx_http_v2_pseudo_header(ngx_http_request_t *r, | |
150 ngx_http_v2_header_t *header); | |
151 static ngx_int_t ngx_http_v2_parse_path(ngx_http_request_t *r, | |
152 ngx_http_v2_header_t *header); | |
153 static ngx_int_t ngx_http_v2_parse_method(ngx_http_request_t *r, | |
154 ngx_http_v2_header_t *header); | |
155 static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r, | |
156 ngx_http_v2_header_t *header); | |
157 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r, | |
158 ngx_http_v2_header_t *header); | |
159 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r); | |
160 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, | |
161 ngx_http_v2_header_t *header); | |
162 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); | |
163 static void ngx_http_v2_run_request(ngx_http_request_t *r); | |
164 static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r); | |
165 | |
166 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, | |
167 ngx_http_v2_stream_t *stream, ngx_uint_t status); | |
168 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev); | |
169 static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev); | |
170 static void ngx_http_v2_idle_handler(ngx_event_t *rev); | |
171 static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, | |
172 ngx_uint_t status); | |
173 | |
174 static ngx_int_t ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, | |
175 ssize_t delta); | |
176 static void ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c, | |
177 ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive); | |
178 static void ngx_http_v2_node_children_update(ngx_http_v2_node_t *node); | |
179 | |
180 static void ngx_http_v2_pool_cleanup(void *data); | |
181 | |
182 | |
183 static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = { | |
184 ngx_http_v2_state_data, | |
185 ngx_http_v2_state_headers, | |
186 ngx_http_v2_state_priority, | |
187 ngx_http_v2_state_rst_stream, | |
188 ngx_http_v2_state_settings, | |
189 ngx_http_v2_state_push_promise, | |
190 ngx_http_v2_state_ping, | |
191 ngx_http_v2_state_goaway, | |
192 ngx_http_v2_state_window_update, | |
193 ngx_http_v2_state_continuation | |
194 }; | |
195 | |
196 #define NGX_HTTP_V2_FRAME_STATES \ | |
197 (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt)) | |
198 | |
199 | |
200 void | |
201 ngx_http_v2_init(ngx_event_t *rev) | |
202 { | |
203 ngx_connection_t *c; | |
204 ngx_pool_cleanup_t *cln; | |
205 ngx_http_connection_t *hc; | |
206 ngx_http_v2_srv_conf_t *h2scf; | |
207 ngx_http_v2_main_conf_t *h2mcf; | |
208 ngx_http_v2_connection_t *h2c; | |
209 | |
210 c = rev->data; | |
211 hc = c->data; | |
212 | |
213 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init http2 connection"); | |
214 | |
215 c->log->action = "processing HTTP/2 connection"; | |
216 | |
217 h2mcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_v2_module); | |
218 | |
219 if (h2mcf->recv_buffer == NULL) { | |
220 h2mcf->recv_buffer = ngx_palloc(ngx_cycle->pool, | |
221 h2mcf->recv_buffer_size); | |
222 if (h2mcf->recv_buffer == NULL) { | |
223 ngx_http_close_connection(c); | |
224 return; | |
225 } | |
226 } | |
227 | |
228 h2c = ngx_pcalloc(c->pool, sizeof(ngx_http_v2_connection_t)); | |
229 if (h2c == NULL) { | |
230 ngx_http_close_connection(c); | |
231 return; | |
232 } | |
233 | |
234 h2c->connection = c; | |
235 h2c->http_connection = hc; | |
236 | |
237 h2c->send_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
238 h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
239 | |
240 h2c->init_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
241 | |
242 h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; | |
243 | |
244 h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); | |
245 | |
246 h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); | |
247 if (h2c->pool == NULL) { | |
248 ngx_http_close_connection(c); | |
249 return; | |
250 } | |
251 | |
252 cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_pool_cleanup_file_t)); | |
253 if (cln == NULL) { | |
254 ngx_http_close_connection(c); | |
255 return; | |
256 } | |
257 | |
258 cln->handler = ngx_http_v2_pool_cleanup; | |
259 cln->data = h2c; | |
260 | |
261 h2c->streams_index = ngx_pcalloc(c->pool, ngx_http_v2_index_size(h2scf) | |
262 * sizeof(ngx_http_v2_node_t *)); | |
263 if (h2c->streams_index == NULL) { | |
264 ngx_http_close_connection(c); | |
265 return; | |
266 } | |
267 | |
268 if (ngx_http_v2_send_settings(h2c, 0) == NGX_ERROR) { | |
269 ngx_http_close_connection(c); | |
270 return; | |
271 } | |
272 | |
273 if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW | |
274 - NGX_HTTP_V2_DEFAULT_WINDOW) | |
275 == NGX_ERROR) | |
276 { | |
277 ngx_http_close_connection(c); | |
278 return; | |
279 } | |
280 | |
281 h2c->state.handler = hc->proxy_protocol ? ngx_http_v2_state_proxy_protocol | |
282 : ngx_http_v2_state_preface; | |
283 | |
284 ngx_queue_init(&h2c->waiting); | |
285 ngx_queue_init(&h2c->posted); | |
286 ngx_queue_init(&h2c->dependencies); | |
287 ngx_queue_init(&h2c->closed); | |
288 | |
289 c->data = h2c; | |
290 | |
291 rev->handler = ngx_http_v2_read_handler; | |
292 c->write->handler = ngx_http_v2_write_handler; | |
293 | |
294 ngx_http_v2_read_handler(rev); | |
295 } | |
296 | |
297 | |
298 static void | |
299 ngx_http_v2_read_handler(ngx_event_t *rev) | |
300 { | |
301 u_char *p, *end; | |
302 size_t available; | |
303 ssize_t n; | |
304 ngx_connection_t *c; | |
305 ngx_http_v2_main_conf_t *h2mcf; | |
306 ngx_http_v2_connection_t *h2c; | |
307 | |
308 c = rev->data; | |
309 h2c = c->data; | |
310 | |
311 if (rev->timedout) { | |
312 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
313 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
314 return; | |
315 } | |
316 | |
317 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); | |
318 | |
319 h2c->blocked = 1; | |
320 | |
321 h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx, | |
322 ngx_http_v2_module); | |
323 | |
324 available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE; | |
325 | |
326 do { | |
327 p = h2mcf->recv_buffer; | |
328 | |
329 ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE); | |
330 end = p + h2c->state.buffer_used; | |
331 | |
332 n = c->recv(c, end, available); | |
333 | |
334 if (n == NGX_AGAIN) { | |
335 break; | |
336 } | |
337 | |
338 if (n == 0 && (h2c->state.incomplete || h2c->processing)) { | |
339 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
340 "client prematurely closed connection"); | |
341 } | |
342 | |
343 if (n == 0 || n == NGX_ERROR) { | |
344 c->error = 1; | |
345 ngx_http_v2_finalize_connection(h2c, 0); | |
346 return; | |
347 } | |
348 | |
349 end += n; | |
350 | |
351 h2c->state.buffer_used = 0; | |
352 h2c->state.incomplete = 0; | |
353 | |
354 do { | |
355 p = h2c->state.handler(h2c, p, end); | |
356 | |
357 if (p == NULL) { | |
358 return; | |
359 } | |
360 | |
361 } while (p != end); | |
362 | |
363 } while (rev->ready); | |
364 | |
365 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
366 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
367 return; | |
368 } | |
369 | |
370 if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { | |
371 ngx_http_v2_finalize_connection(h2c, 0); | |
372 return; | |
373 } | |
374 | |
375 h2c->blocked = 0; | |
376 | |
377 if (h2c->processing) { | |
378 if (rev->timer_set) { | |
379 ngx_del_timer(rev); | |
380 } | |
381 | |
382 return; | |
383 } | |
384 | |
385 ngx_http_v2_handle_connection(h2c); | |
386 } | |
387 | |
388 | |
389 static void | |
390 ngx_http_v2_write_handler(ngx_event_t *wev) | |
391 { | |
392 ngx_int_t rc; | |
393 ngx_queue_t *q; | |
394 ngx_connection_t *c; | |
395 ngx_http_v2_stream_t *stream; | |
396 ngx_http_v2_connection_t *h2c; | |
397 | |
398 c = wev->data; | |
399 h2c = c->data; | |
400 | |
401 if (wev->timedout) { | |
402 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
403 "http2 write event timed out"); | |
404 c->error = 1; | |
405 ngx_http_v2_finalize_connection(h2c, 0); | |
406 return; | |
407 } | |
408 | |
409 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler"); | |
410 | |
411 h2c->blocked = 1; | |
412 | |
413 rc = ngx_http_v2_send_output_queue(h2c); | |
414 | |
415 if (rc == NGX_ERROR) { | |
416 ngx_http_v2_finalize_connection(h2c, 0); | |
417 return; | |
418 } | |
419 | |
420 while (!ngx_queue_empty(&h2c->posted)) { | |
421 q = ngx_queue_head(&h2c->posted); | |
422 | |
423 ngx_queue_remove(q); | |
424 | |
425 stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); | |
426 | |
427 stream->handled = 0; | |
428 | |
429 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
430 "run http2 stream %ui", stream->node->id); | |
431 | |
432 wev = stream->request->connection->write; | |
433 wev->handler(wev); | |
434 } | |
435 | |
436 h2c->blocked = 0; | |
437 | |
438 if (rc == NGX_AGAIN) { | |
439 return; | |
440 } | |
441 | |
442 ngx_http_v2_handle_connection(h2c); | |
443 } | |
444 | |
445 | |
446 ngx_int_t | |
447 ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) | |
448 { | |
449 int tcp_nodelay; | |
450 ngx_chain_t *cl; | |
451 ngx_event_t *wev; | |
452 ngx_connection_t *c; | |
453 ngx_http_v2_out_frame_t *out, *frame, *fn; | |
454 ngx_http_core_loc_conf_t *clcf; | |
455 | |
456 c = h2c->connection; | |
457 | |
458 if (c->error) { | |
459 return NGX_ERROR; | |
460 } | |
461 | |
462 wev = c->write; | |
463 | |
464 if (!wev->ready) { | |
465 return NGX_OK; | |
466 } | |
467 | |
468 cl = NULL; | |
469 out = NULL; | |
470 | |
471 for (frame = h2c->last_out; frame; frame = fn) { | |
472 frame->last->next = cl; | |
473 cl = frame->first; | |
474 | |
475 fn = frame->next; | |
476 frame->next = out; | |
477 out = frame; | |
478 | |
479 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
480 "http2 frame out: %p sid:%ui bl:%d len:%uz", | |
481 out, out->stream ? out->stream->node->id : 0, | |
482 out->blocked, out->length); | |
483 } | |
484 | |
485 cl = c->send_chain(c, cl, 0); | |
486 | |
487 if (cl == NGX_CHAIN_ERROR) { | |
488 goto error; | |
489 } | |
490 | |
491 clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, | |
492 ngx_http_core_module); | |
493 | |
494 if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { | |
495 goto error; | |
496 } | |
497 | |
498 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { | |
499 if (ngx_tcp_push(c->fd) == -1) { | |
500 ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); | |
501 goto error; | |
502 } | |
503 | |
504 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; | |
505 tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; | |
506 | |
507 } else { | |
508 tcp_nodelay = 1; | |
509 } | |
510 | |
511 if (tcp_nodelay | |
512 && clcf->tcp_nodelay | |
513 && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) | |
514 { | |
515 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); | |
516 | |
517 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, | |
518 (const void *) &tcp_nodelay, sizeof(int)) | |
519 == -1) | |
520 { | |
521 #if (NGX_SOLARIS) | |
522 /* Solaris returns EINVAL if a socket has been shut down */ | |
523 c->log_error = NGX_ERROR_IGNORE_EINVAL; | |
524 #endif | |
525 | |
526 ngx_connection_error(c, ngx_socket_errno, | |
527 "setsockopt(TCP_NODELAY) failed"); | |
528 | |
529 c->log_error = NGX_ERROR_INFO; | |
530 goto error; | |
531 } | |
532 | |
533 c->tcp_nodelay = NGX_TCP_NODELAY_SET; | |
534 } | |
535 | |
536 if (cl) { | |
537 ngx_add_timer(wev, clcf->send_timeout); | |
538 | |
539 } else { | |
540 if (wev->timer_set) { | |
541 ngx_del_timer(wev); | |
542 } | |
543 } | |
544 | |
545 for ( /* void */ ; out; out = fn) { | |
546 fn = out->next; | |
547 | |
548 if (out->handler(h2c, out) != NGX_OK) { | |
549 out->blocked = 1; | |
550 break; | |
551 } | |
552 | |
553 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
554 "http2 frame sent: %p sid:%ui bl:%d len:%uz", | |
555 out, out->stream ? out->stream->node->id : 0, | |
556 out->blocked, out->length); | |
557 } | |
558 | |
559 frame = NULL; | |
560 | |
561 for ( /* void */ ; out; out = fn) { | |
562 fn = out->next; | |
563 out->next = frame; | |
564 frame = out; | |
565 } | |
566 | |
567 h2c->last_out = frame; | |
568 | |
569 return NGX_OK; | |
570 | |
571 error: | |
572 | |
573 c->error = 1; | |
574 | |
575 if (!h2c->blocked) { | |
576 ngx_post_event(wev, &ngx_posted_events); | |
577 } | |
578 | |
579 return NGX_ERROR; | |
580 } | |
581 | |
582 | |
583 static void | |
584 ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) | |
585 { | |
586 ngx_connection_t *c; | |
587 ngx_http_v2_srv_conf_t *h2scf; | |
588 | |
589 if (h2c->last_out || h2c->processing) { | |
590 return; | |
591 } | |
592 | |
593 c = h2c->connection; | |
594 | |
595 if (c->error) { | |
596 ngx_http_close_connection(c); | |
597 return; | |
598 } | |
599 | |
600 if (c->buffered) { | |
601 return; | |
602 } | |
603 | |
604 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
605 ngx_http_v2_module); | |
606 if (h2c->state.incomplete) { | |
607 ngx_add_timer(c->read, h2scf->recv_timeout); | |
608 return; | |
609 } | |
610 | |
611 if (ngx_terminate || ngx_exiting) { | |
612 ngx_http_close_connection(c); | |
613 return; | |
614 } | |
615 | |
616 ngx_destroy_pool(h2c->pool); | |
617 | |
618 h2c->pool = NULL; | |
619 h2c->free_frames = NULL; | |
620 h2c->free_fake_connections = NULL; | |
621 | |
622 #if (NGX_HTTP_SSL) | |
623 if (c->ssl) { | |
624 ngx_ssl_free_buffer(c); | |
625 } | |
626 #endif | |
627 | |
628 c->destroyed = 1; | |
629 c->idle = 1; | |
630 ngx_reusable_connection(c, 1); | |
631 | |
632 c->write->handler = ngx_http_empty_handler; | |
633 c->read->handler = ngx_http_v2_idle_handler; | |
634 | |
635 if (c->write->timer_set) { | |
636 ngx_del_timer(c->write); | |
637 } | |
638 | |
639 ngx_add_timer(c->read, h2scf->idle_timeout); | |
640 } | |
641 | |
642 | |
643 static u_char * | |
644 ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos, | |
645 u_char *end) | |
646 { | |
647 ngx_log_t *log; | |
648 | |
649 log = h2c->connection->log; | |
650 log->action = "reading PROXY protocol"; | |
651 | |
652 pos = ngx_proxy_protocol_read(h2c->connection, pos, end); | |
653 | |
654 log->action = "processing HTTP/2 connection"; | |
655 | |
656 if (pos == NULL) { | |
657 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
658 } | |
659 | |
660 return ngx_http_v2_state_preface(h2c, pos, end); | |
661 } | |
662 | |
663 | |
664 static u_char * | |
665 ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos, | |
666 u_char *end) | |
667 { | |
668 static const u_char preface[] = "PRI * HTTP/2.0\r\n"; | |
669 | |
670 if ((size_t) (end - pos) < sizeof(preface) - 1) { | |
671 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_preface); | |
672 } | |
673 | |
674 if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { | |
675 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
676 "invalid http2 connection preface \"%*s\"", | |
677 sizeof(preface) - 1, pos); | |
678 | |
679 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
680 } | |
681 | |
682 return ngx_http_v2_state_preface_end(h2c, pos + sizeof(preface) - 1, end); | |
683 } | |
684 | |
685 | |
686 static u_char * | |
687 ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos, | |
688 u_char *end) | |
689 { | |
690 static const u_char preface[] = "\r\nSM\r\n\r\n"; | |
691 | |
692 if ((size_t) (end - pos) < sizeof(preface) - 1) { | |
693 return ngx_http_v2_state_save(h2c, pos, end, | |
694 ngx_http_v2_state_preface_end); | |
695 } | |
696 | |
697 if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { | |
698 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
699 "invalid http2 connection preface \"%*s\"", | |
700 sizeof(preface) - 1, pos); | |
701 | |
702 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
703 } | |
704 | |
705 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
706 "http2 preface verified"); | |
707 | |
708 return ngx_http_v2_state_head(h2c, pos + sizeof(preface) - 1, end); | |
709 } | |
710 | |
711 | |
712 static u_char * | |
713 ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) | |
714 { | |
715 uint32_t head; | |
716 ngx_uint_t type; | |
717 | |
718 if (end - pos < NGX_HTTP_V2_FRAME_HEADER_SIZE) { | |
719 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_head); | |
720 } | |
721 | |
722 head = ngx_http_v2_parse_uint32(pos); | |
723 | |
724 h2c->state.length = ngx_http_v2_parse_length(head); | |
725 h2c->state.flags = pos[4]; | |
726 | |
727 h2c->state.sid = ngx_http_v2_parse_sid(&pos[5]); | |
728 | |
729 pos += NGX_HTTP_V2_FRAME_HEADER_SIZE; | |
730 | |
731 type = ngx_http_v2_parse_type(head); | |
732 | |
733 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
734 "process http2 frame type:%ui f:%Xd l:%uz sid:%ui", | |
735 type, h2c->state.flags, h2c->state.length, h2c->state.sid); | |
736 | |
737 if (type >= NGX_HTTP_V2_FRAME_STATES) { | |
738 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
739 "http2 frame with unknown type %ui", type); | |
740 return ngx_http_v2_state_skip(h2c, pos, end); | |
741 } | |
742 | |
743 return ngx_http_v2_frame_states[type](h2c, pos, end); | |
744 } | |
745 | |
746 | |
747 static u_char * | |
748 ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) | |
749 { | |
750 ngx_http_v2_node_t *node; | |
751 ngx_http_v2_stream_t *stream; | |
752 | |
753 if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) { | |
754 | |
755 if (h2c->state.length == 0) { | |
756 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
757 "client sent padded DATA frame " | |
758 "with incorrect length: %uz", | |
759 h2c->state.length); | |
760 | |
761 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
762 } | |
763 | |
764 if (end - pos == 0) { | |
765 return ngx_http_v2_state_save(h2c, pos, end, | |
766 ngx_http_v2_state_data); | |
767 } | |
768 | |
769 h2c->state.padding = *pos++; | |
770 h2c->state.length--; | |
771 | |
772 if (h2c->state.padding > h2c->state.length) { | |
773 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
774 "client sent padded DATA frame " | |
775 "with incorrect length: %uz, padding: %uz", | |
776 h2c->state.length, h2c->state.padding); | |
777 | |
778 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
779 } | |
780 | |
781 h2c->state.length -= h2c->state.padding; | |
782 } | |
783 | |
784 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
785 "http2 DATA frame"); | |
786 | |
787 if (h2c->state.length > h2c->recv_window) { | |
788 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
789 "client violated connection flow control: " | |
790 "received DATA frame length %uz, available window %uz", | |
791 h2c->state.length, h2c->recv_window); | |
792 | |
793 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR); | |
794 } | |
795 | |
796 h2c->recv_window -= h2c->state.length; | |
797 | |
798 if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) { | |
799 | |
800 if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW | |
801 - h2c->recv_window) | |
802 == NGX_ERROR) | |
803 { | |
804 return ngx_http_v2_connection_error(h2c, | |
805 NGX_HTTP_V2_INTERNAL_ERROR); | |
806 } | |
807 | |
808 h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
809 } | |
810 | |
811 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); | |
812 | |
813 if (node == NULL || node->stream == NULL) { | |
814 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
815 "unknown http2 stream"); | |
816 | |
817 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
818 } | |
819 | |
820 stream = node->stream; | |
821 | |
822 if (h2c->state.length > stream->recv_window) { | |
823 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
824 "client violated flow control for stream %ui: " | |
825 "received DATA frame length %uz, available window %uz", | |
826 node->id, h2c->state.length, stream->recv_window); | |
827 | |
828 if (ngx_http_v2_terminate_stream(h2c, stream, | |
829 NGX_HTTP_V2_FLOW_CTRL_ERROR) | |
830 == NGX_ERROR) | |
831 { | |
832 return ngx_http_v2_connection_error(h2c, | |
833 NGX_HTTP_V2_INTERNAL_ERROR); | |
834 } | |
835 | |
836 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
837 } | |
838 | |
839 stream->recv_window -= h2c->state.length; | |
840 | |
841 if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) { | |
842 | |
843 if (ngx_http_v2_send_window_update(h2c, node->id, | |
844 NGX_HTTP_V2_MAX_WINDOW | |
845 - stream->recv_window) | |
846 == NGX_ERROR) | |
847 { | |
848 return ngx_http_v2_connection_error(h2c, | |
849 NGX_HTTP_V2_INTERNAL_ERROR); | |
850 } | |
851 | |
852 stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
853 } | |
854 | |
855 if (stream->in_closed) { | |
856 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
857 "client sent DATA frame for half-closed stream %ui", | |
858 node->id); | |
859 | |
860 if (ngx_http_v2_terminate_stream(h2c, stream, | |
861 NGX_HTTP_V2_STREAM_CLOSED) | |
862 == NGX_ERROR) | |
863 { | |
864 return ngx_http_v2_connection_error(h2c, | |
865 NGX_HTTP_V2_INTERNAL_ERROR); | |
866 } | |
867 | |
868 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
869 } | |
870 | |
871 h2c->state.stream = stream; | |
872 | |
873 return ngx_http_v2_state_read_data(h2c, pos, end); | |
874 } | |
875 | |
876 | |
877 static u_char * | |
878 ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, | |
879 u_char *end) | |
880 { | |
881 size_t size; | |
882 ssize_t n; | |
883 ngx_buf_t *buf; | |
884 ngx_int_t rc; | |
885 ngx_temp_file_t *tf; | |
886 ngx_http_request_t *r; | |
887 ngx_http_v2_stream_t *stream; | |
888 ngx_http_request_body_t *rb; | |
889 ngx_http_core_loc_conf_t *clcf; | |
890 | |
891 stream = h2c->state.stream; | |
892 | |
893 if (stream == NULL) { | |
894 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
895 } | |
896 | |
897 if (stream->skip_data) { | |
898 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; | |
899 | |
900 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
901 "skipping http2 DATA frame, reason: %d", | |
902 stream->skip_data); | |
903 | |
904 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
905 } | |
906 | |
907 size = end - pos; | |
908 | |
909 if (size > h2c->state.length) { | |
910 size = h2c->state.length; | |
911 } | |
912 | |
913 r = stream->request; | |
914 | |
915 if (r->request_body == NULL | |
916 && ngx_http_v2_init_request_body(r) != NGX_OK) | |
917 { | |
918 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; | |
919 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
920 } | |
921 | |
922 rb = r->request_body; | |
923 tf = rb->temp_file; | |
924 buf = rb->buf; | |
925 | |
926 if (size) { | |
927 rb->rest += size; | |
928 | |
929 if (r->headers_in.content_length_n != -1 | |
930 && r->headers_in.content_length_n < rb->rest) | |
931 { | |
932 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
933 "client intended to send body data " | |
934 "larger than declared"); | |
935 | |
936 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | |
937 goto error; | |
938 | |
939 } else { | |
940 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
941 | |
942 if (clcf->client_max_body_size | |
943 && clcf->client_max_body_size < rb->rest) | |
944 { | |
945 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
946 "client intended to send " | |
947 "too large chunked body: %O bytes", rb->rest); | |
948 | |
949 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | |
950 goto error; | |
951 } | |
952 } | |
953 | |
954 h2c->state.length -= size; | |
955 | |
956 if (tf) { | |
957 buf->start = pos; | |
958 buf->pos = pos; | |
959 | |
960 pos += size; | |
961 | |
962 buf->end = pos; | |
963 buf->last = pos; | |
964 | |
965 n = ngx_write_chain_to_temp_file(tf, rb->bufs); | |
966 | |
967 /* TODO: n == 0 or not complete and level event */ | |
968 | |
969 if (n == NGX_ERROR) { | |
970 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; | |
971 goto error; | |
972 } | |
973 | |
974 tf->offset += n; | |
975 | |
976 } else { | |
977 buf->last = ngx_cpymem(buf->last, pos, size); | |
978 pos += size; | |
979 } | |
980 | |
981 r->request_length += size; | |
982 } | |
983 | |
984 if (h2c->state.length) { | |
985 return ngx_http_v2_state_save(h2c, pos, end, | |
986 ngx_http_v2_state_read_data); | |
987 } | |
988 | |
989 if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
990 stream->in_closed = 1; | |
991 | |
992 if (r->headers_in.content_length_n < 0) { | |
993 r->headers_in.content_length_n = rb->rest; | |
994 | |
995 } else if (r->headers_in.content_length_n != rb->rest) { | |
996 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
997 "client prematurely closed stream: " | |
998 "only %O out of %O bytes of request body received", | |
999 rb->rest, r->headers_in.content_length_n); | |
1000 | |
1001 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | |
1002 goto error; | |
1003 } | |
1004 | |
1005 if (tf) { | |
1006 ngx_memzero(buf, sizeof(ngx_buf_t)); | |
1007 | |
1008 buf->in_file = 1; | |
1009 buf->file_last = tf->file.offset; | |
1010 buf->file = &tf->file; | |
1011 | |
1012 rb->buf = NULL; | |
1013 } | |
1014 | |
1015 if (rb->post_handler) { | |
1016 r->read_event_handler = ngx_http_block_reading; | |
1017 rb->post_handler(r); | |
1018 } | |
1019 } | |
1020 | |
1021 if (h2c->state.padding) { | |
1022 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
1023 } | |
1024 | |
1025 return ngx_http_v2_state_complete(h2c, pos, end); | |
1026 | |
1027 error: | |
1028 | |
1029 if (rb->post_handler) { | |
1030 | |
1031 if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) { | |
1032 rc = (r->headers_in.content_length_n == -1) | |
1033 ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE : NGX_HTTP_BAD_REQUEST; | |
1034 | |
1035 } else { | |
1036 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1037 } | |
1038 | |
1039 ngx_http_finalize_request(r, rc); | |
1040 } | |
1041 | |
1042 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
1043 } | |
1044 | |
1045 | |
1046 static u_char * | |
1047 ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1048 u_char *end) | |
1049 { | |
1050 size_t size; | |
1051 ngx_uint_t padded, priority, depend, dependency, excl, weight; | |
1052 ngx_http_v2_node_t *node; | |
1053 ngx_http_v2_stream_t *stream; | |
1054 ngx_http_v2_srv_conf_t *h2scf; | |
1055 | |
1056 padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG; | |
1057 priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG; | |
1058 | |
1059 size = 0; | |
1060 | |
1061 if (padded) { | |
1062 size++; | |
1063 } | |
1064 | |
1065 if (priority) { | |
1066 size += sizeof(uint32_t) + 1; | |
1067 } | |
1068 | |
1069 if (h2c->state.length < size) { | |
1070 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1071 "client sent HEADERS frame with incorrect length %uz", | |
1072 h2c->state.length); | |
1073 | |
1074 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1075 } | |
1076 | |
1077 if (h2c->state.length == size) { | |
1078 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1079 "client sent HEADERS frame with empty header block"); | |
1080 | |
1081 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1082 } | |
1083 | |
1084 if ((size_t) (end - pos) < size) { | |
1085 return ngx_http_v2_state_save(h2c, pos, end, | |
1086 ngx_http_v2_state_headers); | |
1087 } | |
1088 | |
1089 h2c->state.length -= size; | |
1090 | |
1091 if (padded) { | |
1092 h2c->state.padding = *pos++; | |
1093 | |
1094 if (h2c->state.padding > h2c->state.length) { | |
1095 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1096 "client sent padded HEADERS frame " | |
1097 "with incorrect length: %uz, padding: %uz", | |
1098 h2c->state.length, h2c->state.padding); | |
1099 | |
1100 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1101 } | |
1102 | |
1103 h2c->state.length -= h2c->state.padding; | |
1104 } | |
1105 | |
1106 depend = 0; | |
1107 excl = 0; | |
1108 weight = 16; | |
1109 | |
1110 if (priority) { | |
1111 dependency = ngx_http_v2_parse_uint32(pos); | |
1112 | |
1113 depend = dependency & 0x7fffffff; | |
1114 excl = dependency >> 31; | |
1115 weight = pos[4] + 1; | |
1116 | |
1117 pos += sizeof(uint32_t) + 1; | |
1118 } | |
1119 | |
1120 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1121 "http2 HEADERS frame sid:%ui on %ui excl:%ui weight:%ui", | |
1122 h2c->state.sid, depend, excl, weight); | |
1123 | |
1124 if (h2c->state.sid % 2 == 0 || h2c->state.sid <= h2c->last_sid) { | |
1125 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1126 "client sent HEADERS frame with incorrect identifier " | |
1127 "%ui, the last was %ui", h2c->state.sid, h2c->last_sid); | |
1128 | |
1129 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
1130 } | |
1131 | |
1132 h2c->last_sid = h2c->state.sid; | |
1133 | |
1134 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
1135 ngx_http_v2_module); | |
1136 | |
1137 h2c->state.header_limit = h2scf->max_header_size; | |
1138 | |
1139 if (h2c->processing >= h2scf->concurrent_streams) { | |
1140 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1141 "concurrent streams exceeded %ui", h2c->processing); | |
1142 | |
1143 if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, | |
1144 NGX_HTTP_V2_REFUSED_STREAM) | |
1145 != NGX_OK) | |
1146 { | |
1147 return ngx_http_v2_connection_error(h2c, | |
1148 NGX_HTTP_V2_INTERNAL_ERROR); | |
1149 } | |
1150 | |
1151 return ngx_http_v2_state_skip_headers(h2c, pos, end); | |
1152 } | |
1153 | |
1154 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); | |
1155 | |
1156 if (node == NULL) { | |
1157 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1158 } | |
1159 | |
1160 if (node->parent) { | |
1161 ngx_queue_remove(&node->reuse); | |
1162 h2c->closed_nodes--; | |
1163 } | |
1164 | |
1165 stream = ngx_http_v2_create_stream(h2c); | |
1166 if (stream == NULL) { | |
1167 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1168 } | |
1169 | |
1170 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; | |
1171 stream->node = node; | |
1172 | |
1173 node->stream = stream; | |
1174 | |
1175 h2c->state.stream = stream; | |
1176 h2c->state.pool = stream->request->pool; | |
1177 | |
1178 if (priority || node->parent == NULL) { | |
1179 node->weight = weight; | |
1180 ngx_http_v2_set_dependency(h2c, node, depend, excl); | |
1181 } | |
1182 | |
1183 return ngx_http_v2_state_header_block(h2c, pos, end); | |
1184 } | |
1185 | |
1186 | |
1187 static u_char * | |
1188 ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1189 u_char *end) | |
1190 { | |
1191 u_char ch; | |
1192 ngx_int_t value; | |
1193 ngx_uint_t indexed, size_update, prefix; | |
1194 ngx_http_v2_srv_conf_t *h2scf; | |
1195 | |
1196 if (end - pos < 1) { | |
1197 return ngx_http_v2_state_save(h2c, pos, end, | |
1198 ngx_http_v2_state_header_block); | |
1199 } | |
1200 | |
1201 size_update = 0; | |
1202 indexed = 0; | |
1203 | |
1204 ch = *pos; | |
1205 | |
1206 if (ch >= (1 << 7)) { | |
1207 /* indexed header field */ | |
1208 indexed = 1; | |
1209 prefix = ngx_http_v2_prefix(7); | |
1210 | |
1211 } else if (ch >= (1 << 6)) { | |
1212 /* literal header field with incremental indexing */ | |
1213 h2c->state.index = 1; | |
1214 prefix = ngx_http_v2_prefix(6); | |
1215 | |
1216 } else if (ch >= (1 << 5)) { | |
1217 /* dynamic table size update */ | |
1218 size_update = 1; | |
1219 prefix = ngx_http_v2_prefix(5); | |
1220 | |
1221 } else if (ch >= (1 << 4)) { | |
1222 /* literal header field never indexed */ | |
1223 prefix = ngx_http_v2_prefix(4); | |
1224 | |
1225 } else { | |
1226 /* literal header field without indexing */ | |
1227 prefix = ngx_http_v2_prefix(3); | |
1228 } | |
1229 | |
1230 value = ngx_http_v2_parse_int(h2c, &pos, end, prefix); | |
1231 | |
1232 if (value < 0) { | |
1233 if (value == NGX_AGAIN) { | |
1234 return ngx_http_v2_state_save(h2c, pos, end, | |
1235 ngx_http_v2_state_header_block); | |
1236 } | |
1237 | |
1238 if (value == NGX_DECLINED) { | |
1239 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1240 "client sent header block with too long %s value", | |
1241 size_update ? "size update" : "header index"); | |
1242 | |
1243 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); | |
1244 } | |
1245 | |
1246 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1247 "client sent header block with incorrect length"); | |
1248 | |
1249 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1250 } | |
1251 | |
1252 if (indexed) { | |
1253 if (ngx_http_v2_get_indexed_header(h2c, value, 0) != NGX_OK) { | |
1254 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); | |
1255 } | |
1256 | |
1257 return ngx_http_v2_state_process_header(h2c, pos, end); | |
1258 } | |
1259 | |
1260 if (size_update) { | |
1261 if (ngx_http_v2_table_size(h2c, value) != NGX_OK) { | |
1262 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); | |
1263 } | |
1264 | |
1265 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1266 } | |
1267 | |
1268 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
1269 ngx_http_v2_module); | |
1270 | |
1271 h2c->state.field_limit = h2scf->max_field_size; | |
1272 | |
1273 if (value == 0) { | |
1274 h2c->state.parse_name = 1; | |
1275 | |
1276 } else { | |
1277 if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) { | |
1278 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); | |
1279 } | |
1280 | |
1281 h2c->state.field_limit -= h2c->state.header.name.len; | |
1282 } | |
1283 | |
1284 h2c->state.parse_value = 1; | |
1285 | |
1286 return ngx_http_v2_state_field_len(h2c, pos, end); | |
1287 } | |
1288 | |
1289 | |
1290 static u_char * | |
1291 ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1292 u_char *end) | |
1293 { | |
1294 size_t alloc; | |
1295 ngx_int_t len; | |
1296 ngx_uint_t huff; | |
1297 | |
1298 if (h2c->state.length < 1) { | |
1299 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1300 "client sent header block with incorrect length"); | |
1301 | |
1302 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1303 } | |
1304 | |
1305 if (end - pos < 1) { | |
1306 return ngx_http_v2_state_save(h2c, pos, end, | |
1307 ngx_http_v2_state_field_len); | |
1308 } | |
1309 | |
1310 huff = *pos >> 7; | |
1311 len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7)); | |
1312 | |
1313 if (len < 0) { | |
1314 if (len == NGX_AGAIN) { | |
1315 return ngx_http_v2_state_save(h2c, pos, end, | |
1316 ngx_http_v2_state_field_len); | |
1317 } | |
1318 | |
1319 if (len == NGX_DECLINED) { | |
1320 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1321 "client sent header field with too long length value"); | |
1322 | |
1323 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); | |
1324 } | |
1325 | |
1326 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1327 "client sent header block with incorrect length"); | |
1328 | |
1329 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1330 } | |
1331 | |
1332 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1333 "http2 hpack %s string length: %i", | |
1334 huff ? "encoded" : "raw", len); | |
1335 | |
1336 if ((size_t) len > h2c->state.length) { | |
1337 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1338 "client sent header field with incorrect length"); | |
1339 | |
1340 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1341 } | |
1342 | |
1343 h2c->state.length -= len; | |
1344 | |
1345 if ((size_t) len > h2c->state.field_limit) { | |
1346 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1347 "client exceeded http2_max_field_size limit"); | |
1348 | |
1349 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); | |
1350 } | |
1351 | |
1352 h2c->state.field_limit -= len; | |
1353 h2c->state.field_rest = len; | |
1354 | |
1355 if (h2c->state.stream == NULL && !h2c->state.index) { | |
1356 return ngx_http_v2_state_field_skip(h2c, pos, end); | |
1357 } | |
1358 | |
1359 alloc = (huff ? len * 8 / 5 : len) + 1; | |
1360 | |
1361 h2c->state.field_start = ngx_pnalloc(h2c->state.pool, alloc); | |
1362 if (h2c->state.field_start == NULL) { | |
1363 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1364 } | |
1365 | |
1366 h2c->state.field_end = h2c->state.field_start; | |
1367 | |
1368 if (huff) { | |
1369 return ngx_http_v2_state_field_huff(h2c, pos, end); | |
1370 } | |
1371 | |
1372 return ngx_http_v2_state_field_raw(h2c, pos, end); | |
1373 } | |
1374 | |
1375 | |
1376 static u_char * | |
1377 ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1378 u_char *end) | |
1379 { | |
1380 size_t size; | |
1381 | |
1382 size = end - pos; | |
1383 | |
1384 if (size > h2c->state.field_rest) { | |
1385 size = h2c->state.field_rest; | |
1386 } | |
1387 | |
1388 h2c->state.field_rest -= size; | |
1389 | |
1390 if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size, | |
1391 &h2c->state.field_end, | |
1392 h2c->state.field_rest == 0, | |
1393 h2c->connection->log) | |
1394 != NGX_OK) | |
1395 { | |
1396 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1397 "client sent invalid encoded header field"); | |
1398 | |
1399 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR); | |
1400 } | |
1401 | |
1402 if (h2c->state.field_rest != 0) { | |
1403 return ngx_http_v2_state_save(h2c, end, end, | |
1404 ngx_http_v2_state_field_huff); | |
1405 } | |
1406 | |
1407 *h2c->state.field_end = '\0'; | |
1408 | |
1409 return ngx_http_v2_state_process_header(h2c, pos + size, end); | |
1410 } | |
1411 | |
1412 | |
1413 static u_char * | |
1414 ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1415 u_char *end) | |
1416 { | |
1417 size_t size; | |
1418 | |
1419 size = end - pos; | |
1420 | |
1421 if (size > h2c->state.field_rest) { | |
1422 size = h2c->state.field_rest; | |
1423 } | |
1424 | |
1425 h2c->state.field_rest -= size; | |
1426 | |
1427 h2c->state.field_end = ngx_cpymem(h2c->state.field_end, pos, size); | |
1428 | |
1429 if (h2c->state.field_rest) { | |
1430 return ngx_http_v2_state_save(h2c, end, end, | |
1431 ngx_http_v2_state_field_raw); | |
1432 } | |
1433 | |
1434 *h2c->state.field_end = '\0'; | |
1435 | |
1436 return ngx_http_v2_state_process_header(h2c, pos + size, end); | |
1437 } | |
1438 | |
1439 | |
1440 static u_char * | |
1441 ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1442 u_char *end) | |
1443 { | |
1444 size_t size; | |
1445 | |
1446 size = end - pos; | |
1447 | |
1448 if (size > h2c->state.field_rest) { | |
1449 size = h2c->state.field_rest; | |
1450 } | |
1451 | |
1452 h2c->state.field_rest -= size; | |
1453 | |
1454 return ngx_http_v2_state_process_header(h2c, pos + size, end); | |
1455 } | |
1456 | |
1457 | |
1458 static u_char * | |
1459 ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1460 u_char *end) | |
1461 { | |
1462 size_t len; | |
1463 ngx_int_t rc; | |
1464 ngx_table_elt_t *h; | |
1465 ngx_http_header_t *hh; | |
1466 ngx_http_request_t *r; | |
1467 ngx_http_v2_header_t *header; | |
1468 ngx_http_core_srv_conf_t *cscf; | |
1469 ngx_http_core_main_conf_t *cmcf; | |
1470 | |
1471 static ngx_str_t cookie = ngx_string("cookie"); | |
1472 | |
1473 header = &h2c->state.header; | |
1474 | |
1475 if (h2c->state.parse_name) { | |
1476 h2c->state.parse_name = 0; | |
1477 | |
1478 header->name.len = h2c->state.field_end - h2c->state.field_start; | |
1479 header->name.data = h2c->state.field_start; | |
1480 | |
1481 return ngx_http_v2_state_field_len(h2c, pos, end); | |
1482 } | |
1483 | |
1484 if (h2c->state.parse_value) { | |
1485 h2c->state.parse_value = 0; | |
1486 | |
1487 header->value.len = h2c->state.field_end - h2c->state.field_start; | |
1488 header->value.data = h2c->state.field_start; | |
1489 } | |
1490 | |
1491 len = header->name.len + header->value.len; | |
1492 | |
1493 if (len > h2c->state.header_limit) { | |
1494 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1495 "client exceeded http2_max_header_size limit"); | |
1496 | |
1497 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); | |
1498 } | |
1499 | |
1500 h2c->state.header_limit -= len; | |
1501 | |
1502 if (h2c->state.index) { | |
1503 if (ngx_http_v2_add_header(h2c, header) != NGX_OK) { | |
1504 return ngx_http_v2_connection_error(h2c, | |
1505 NGX_HTTP_V2_INTERNAL_ERROR); | |
1506 } | |
1507 | |
1508 h2c->state.index = 0; | |
1509 } | |
1510 | |
1511 if (h2c->state.stream == NULL) { | |
1512 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1513 } | |
1514 | |
1515 r = h2c->state.stream->request; | |
1516 | |
1517 /* TODO Optimization: validate headers while parsing. */ | |
1518 if (ngx_http_v2_validate_header(r, header) != NGX_OK) { | |
1519 if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream, | |
1520 NGX_HTTP_V2_PROTOCOL_ERROR) | |
1521 == NGX_ERROR) | |
1522 { | |
1523 return ngx_http_v2_connection_error(h2c, | |
1524 NGX_HTTP_V2_INTERNAL_ERROR); | |
1525 } | |
1526 | |
1527 goto error; | |
1528 } | |
1529 | |
1530 if (header->name.data[0] == ':') { | |
1531 rc = ngx_http_v2_pseudo_header(r, header); | |
1532 | |
1533 if (rc == NGX_OK) { | |
1534 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1535 } | |
1536 | |
1537 if (rc == NGX_ABORT) { | |
1538 goto error; | |
1539 } | |
1540 | |
1541 if (rc == NGX_DECLINED) { | |
1542 if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream, | |
1543 NGX_HTTP_V2_PROTOCOL_ERROR) | |
1544 == NGX_ERROR) | |
1545 { | |
1546 return ngx_http_v2_connection_error(h2c, | |
1547 NGX_HTTP_V2_INTERNAL_ERROR); | |
1548 } | |
1549 | |
1550 goto error; | |
1551 } | |
1552 | |
1553 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1554 } | |
1555 | |
1556 if (r->invalid_header) { | |
1557 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
1558 | |
1559 if (cscf->ignore_invalid_headers) { | |
1560 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
1561 "client sent invalid header: \"%V\"", &header->name); | |
1562 | |
1563 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1564 } | |
1565 } | |
1566 | |
1567 if (header->name.len == cookie.len | |
1568 && ngx_memcmp(header->name.data, cookie.data, cookie.len) == 0) | |
1569 { | |
1570 if (ngx_http_v2_cookie(r, header) != NGX_OK) { | |
1571 return ngx_http_v2_connection_error(h2c, | |
1572 NGX_HTTP_V2_INTERNAL_ERROR); | |
1573 } | |
1574 | |
1575 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1576 } | |
1577 | |
1578 h = ngx_list_push(&r->headers_in.headers); | |
1579 if (h == NULL) { | |
1580 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1581 } | |
1582 | |
1583 h->key.len = header->name.len; | |
1584 h->key.data = header->name.data; | |
1585 | |
1586 /* TODO Optimization: precalculate hash and hadnler for indexed headers. */ | |
1587 h->hash = ngx_hash_key(h->key.data, h->key.len); | |
1588 | |
1589 h->value.len = header->value.len; | |
1590 h->value.data = header->value.data; | |
1591 | |
1592 h->lowcase_key = h->key.data; | |
1593 | |
1594 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
1595 | |
1596 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, | |
1597 h->lowcase_key, h->key.len); | |
1598 | |
1599 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { | |
1600 goto error; | |
1601 } | |
1602 | |
1603 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1604 "http2 http header: \"%V: %V\"", &h->key, &h->value); | |
1605 | |
1606 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1607 | |
1608 error: | |
1609 | |
1610 h2c->state.stream = NULL; | |
1611 h2c->state.pool = NULL; | |
1612 | |
1613 return ngx_http_v2_state_header_complete(h2c, pos, end); | |
1614 } | |
1615 | |
1616 | |
1617 static u_char * | |
1618 ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1619 u_char *end) | |
1620 { | |
1621 ngx_http_v2_stream_t *stream; | |
1622 | |
1623 if (h2c->state.length) { | |
1624 h2c->state.handler = h2c->state.pool ? ngx_http_v2_state_header_block | |
1625 : ngx_http_v2_state_skip_headers; | |
1626 return pos; | |
1627 } | |
1628 | |
1629 stream = h2c->state.stream; | |
1630 | |
1631 if (stream) { | |
1632 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { | |
1633 stream->end_headers = 1; | |
1634 ngx_http_v2_run_request(stream->request); | |
1635 | |
1636 } else { | |
1637 stream->header_limit = h2c->state.header_limit; | |
1638 } | |
1639 | |
1640 } else if (h2c->state.pool) { | |
1641 ngx_destroy_pool(h2c->state.pool); | |
1642 } | |
1643 | |
1644 h2c->state.pool = NULL; | |
1645 | |
1646 if (h2c->state.padding) { | |
1647 return ngx_http_v2_state_skip_padded(h2c, pos, end); | |
1648 } | |
1649 | |
1650 return ngx_http_v2_state_complete(h2c, pos, end); | |
1651 } | |
1652 | |
1653 | |
1654 static u_char * | |
1655 ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1656 u_char *end) | |
1657 { | |
1658 ngx_uint_t depend, dependency, excl, weight; | |
1659 ngx_http_v2_node_t *node; | |
1660 | |
1661 if (h2c->state.length != NGX_HTTP_V2_PRIORITY_SIZE) { | |
1662 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1663 "client sent PRIORITY frame with incorrect length %uz", | |
1664 h2c->state.length); | |
1665 | |
1666 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1667 } | |
1668 | |
1669 if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { | |
1670 return ngx_http_v2_state_save(h2c, pos, end, | |
1671 ngx_http_v2_state_priority); | |
1672 } | |
1673 | |
1674 dependency = ngx_http_v2_parse_uint32(pos); | |
1675 | |
1676 depend = dependency & 0x7fffffff; | |
1677 excl = dependency >> 31; | |
1678 weight = pos[4] + 1; | |
1679 | |
1680 pos += NGX_HTTP_V2_PRIORITY_SIZE; | |
1681 | |
1682 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1683 "http2 PRIORITY frame sid:%ui on %ui excl:%ui weight:%ui", | |
1684 h2c->state.sid, depend, excl, weight); | |
1685 | |
1686 if (h2c->state.sid == 0) { | |
1687 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1688 "client sent PRIORITY frame with incorrect identifier"); | |
1689 | |
1690 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
1691 } | |
1692 | |
1693 if (depend == h2c->state.sid) { | |
1694 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1695 "client sent PRIORITY frame for stream %ui " | |
1696 "with incorrect dependancy", h2c->state.sid); | |
1697 | |
1698 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); | |
1699 | |
1700 if (node && node->stream) { | |
1701 if (ngx_http_v2_terminate_stream(h2c, node->stream, | |
1702 NGX_HTTP_V2_PROTOCOL_ERROR) | |
1703 == NGX_ERROR) | |
1704 { | |
1705 return ngx_http_v2_connection_error(h2c, | |
1706 NGX_HTTP_V2_INTERNAL_ERROR); | |
1707 } | |
1708 | |
1709 } else { | |
1710 if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, | |
1711 NGX_HTTP_V2_PROTOCOL_ERROR) | |
1712 == NGX_ERROR) | |
1713 { | |
1714 return ngx_http_v2_connection_error(h2c, | |
1715 NGX_HTTP_V2_INTERNAL_ERROR); | |
1716 } | |
1717 } | |
1718 | |
1719 return ngx_http_v2_state_complete(h2c, pos, end); | |
1720 } | |
1721 | |
1722 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); | |
1723 | |
1724 if (node == NULL) { | |
1725 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1726 } | |
1727 | |
1728 node->weight = weight; | |
1729 | |
1730 if (node->stream == NULL) { | |
1731 if (node->parent == NULL) { | |
1732 h2c->closed_nodes++; | |
1733 | |
1734 } else { | |
1735 ngx_queue_remove(&node->reuse); | |
1736 } | |
1737 | |
1738 ngx_queue_insert_tail(&h2c->closed, &node->reuse); | |
1739 } | |
1740 | |
1741 ngx_http_v2_set_dependency(h2c, node, depend, excl); | |
1742 | |
1743 return ngx_http_v2_state_complete(h2c, pos, end); | |
1744 } | |
1745 | |
1746 | |
1747 static u_char * | |
1748 ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1749 u_char *end) | |
1750 { | |
1751 ngx_uint_t status; | |
1752 ngx_event_t *ev; | |
1753 ngx_connection_t *fc; | |
1754 ngx_http_v2_node_t *node; | |
1755 ngx_http_v2_stream_t *stream; | |
1756 | |
1757 if (h2c->state.length != NGX_HTTP_V2_RST_STREAM_SIZE) { | |
1758 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1759 "client sent RST_STREAM frame with incorrect length %uz", | |
1760 h2c->state.length); | |
1761 | |
1762 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1763 } | |
1764 | |
1765 if (end - pos < NGX_HTTP_V2_RST_STREAM_SIZE) { | |
1766 return ngx_http_v2_state_save(h2c, pos, end, | |
1767 ngx_http_v2_state_rst_stream); | |
1768 } | |
1769 | |
1770 status = ngx_http_v2_parse_uint32(pos); | |
1771 | |
1772 pos += NGX_HTTP_V2_RST_STREAM_SIZE; | |
1773 | |
1774 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1775 "http2 RST_STREAM frame, sid:%ui status:%ui", | |
1776 h2c->state.sid, status); | |
1777 | |
1778 if (h2c->state.sid == 0) { | |
1779 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1780 "client sent RST_STREAM frame with incorrect identifier"); | |
1781 | |
1782 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
1783 } | |
1784 | |
1785 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); | |
1786 | |
1787 if (node == NULL || node->stream == NULL) { | |
1788 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1789 "unknown http2 stream"); | |
1790 | |
1791 return ngx_http_v2_state_complete(h2c, pos, end); | |
1792 } | |
1793 | |
1794 stream = node->stream; | |
1795 | |
1796 stream->in_closed = 1; | |
1797 stream->out_closed = 1; | |
1798 | |
1799 fc = stream->request->connection; | |
1800 fc->error = 1; | |
1801 | |
1802 switch (status) { | |
1803 | |
1804 case NGX_HTTP_V2_CANCEL: | |
1805 ngx_log_error(NGX_LOG_INFO, fc->log, 0, | |
1806 "client canceled stream %ui", h2c->state.sid); | |
1807 break; | |
1808 | |
1809 case NGX_HTTP_V2_INTERNAL_ERROR: | |
1810 ngx_log_error(NGX_LOG_INFO, fc->log, 0, | |
1811 "client terminated stream %ui due to internal error", | |
1812 h2c->state.sid); | |
1813 break; | |
1814 | |
1815 default: | |
1816 ngx_log_error(NGX_LOG_INFO, fc->log, 0, | |
1817 "client terminated stream %ui with status %ui", | |
1818 h2c->state.sid, status); | |
1819 break; | |
1820 } | |
1821 | |
1822 ev = fc->read; | |
1823 ev->handler(ev); | |
1824 | |
1825 return ngx_http_v2_state_complete(h2c, pos, end); | |
1826 } | |
1827 | |
1828 | |
1829 static u_char * | |
1830 ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1831 u_char *end) | |
1832 { | |
1833 if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) { | |
1834 | |
1835 if (h2c->state.length != 0) { | |
1836 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1837 "client sent SETTINGS frame with the ACK flag " | |
1838 "and nonzero length"); | |
1839 | |
1840 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1841 } | |
1842 | |
1843 /* TODO settings acknowledged */ | |
1844 | |
1845 return ngx_http_v2_state_complete(h2c, pos, end); | |
1846 } | |
1847 | |
1848 if (h2c->state.length % NGX_HTTP_V2_SETTINGS_PARAM_SIZE) { | |
1849 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1850 "client sent SETTINGS frame with incorrect length %uz", | |
1851 h2c->state.length); | |
1852 | |
1853 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1854 } | |
1855 | |
1856 ngx_http_v2_send_settings(h2c, 1); | |
1857 | |
1858 return ngx_http_v2_state_settings_params(h2c, pos, end); | |
1859 } | |
1860 | |
1861 | |
1862 static u_char * | |
1863 ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1864 u_char *end) | |
1865 { | |
1866 ngx_uint_t id, value; | |
1867 | |
1868 while (h2c->state.length) { | |
1869 if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) { | |
1870 return ngx_http_v2_state_save(h2c, pos, end, | |
1871 ngx_http_v2_state_settings_params); | |
1872 } | |
1873 | |
1874 h2c->state.length -= NGX_HTTP_V2_SETTINGS_PARAM_SIZE; | |
1875 | |
1876 id = ngx_http_v2_parse_uint16(pos); | |
1877 value = ngx_http_v2_parse_uint32(&pos[2]); | |
1878 | |
1879 switch (id) { | |
1880 | |
1881 case NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING: | |
1882 | |
1883 if (value > NGX_HTTP_V2_MAX_WINDOW) { | |
1884 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1885 "client sent SETTINGS frame with incorrect " | |
1886 "INITIAL_WINDOW_SIZE value %ui", value); | |
1887 | |
1888 return ngx_http_v2_connection_error(h2c, | |
1889 NGX_HTTP_V2_FLOW_CTRL_ERROR); | |
1890 } | |
1891 | |
1892 if (ngx_http_v2_adjust_windows(h2c, value - h2c->init_window) | |
1893 != NGX_OK) | |
1894 { | |
1895 return ngx_http_v2_connection_error(h2c, | |
1896 NGX_HTTP_V2_INTERNAL_ERROR); | |
1897 } | |
1898 | |
1899 h2c->init_window = value; | |
1900 break; | |
1901 | |
1902 case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING: | |
1903 if (value > NGX_HTTP_V2_MAX_FRAME_SIZE | |
1904 || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE) | |
1905 { | |
1906 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1907 "client sent SETTINGS frame with incorrect " | |
1908 "MAX_FRAME_SIZE value %ui", value); | |
1909 | |
1910 return ngx_http_v2_connection_error(h2c, | |
1911 NGX_HTTP_V2_PROTOCOL_ERROR); | |
1912 } | |
1913 | |
1914 h2c->frame_size = value; | |
1915 break; | |
1916 | |
1917 default: | |
1918 break; | |
1919 } | |
1920 | |
1921 pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE; | |
1922 } | |
1923 | |
1924 return ngx_http_v2_state_complete(h2c, pos, end); | |
1925 } | |
1926 | |
1927 | |
1928 static u_char * | |
1929 ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1930 u_char *end) | |
1931 { | |
1932 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1933 "client sent PUSH_PROMISE frame"); | |
1934 | |
1935 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
1936 } | |
1937 | |
1938 | |
1939 static u_char * | |
1940 ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) | |
1941 { | |
1942 ngx_buf_t *buf; | |
1943 ngx_http_v2_out_frame_t *frame; | |
1944 | |
1945 if (h2c->state.length != NGX_HTTP_V2_PING_SIZE) { | |
1946 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1947 "client sent PING frame with incorrect length %uz", | |
1948 h2c->state.length); | |
1949 | |
1950 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1951 } | |
1952 | |
1953 if (end - pos < NGX_HTTP_V2_PING_SIZE) { | |
1954 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_ping); | |
1955 } | |
1956 | |
1957 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1958 "http2 PING frame, flags: %ui", h2c->state.flags); | |
1959 | |
1960 if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) { | |
1961 return ngx_http_v2_state_skip(h2c, pos, end); | |
1962 } | |
1963 | |
1964 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_PING_SIZE, | |
1965 NGX_HTTP_V2_PING_FRAME, | |
1966 NGX_HTTP_V2_ACK_FLAG, 0); | |
1967 if (frame == NULL) { | |
1968 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1969 } | |
1970 | |
1971 buf = frame->first->buf; | |
1972 | |
1973 buf->last = ngx_cpymem(buf->last, pos, NGX_HTTP_V2_PING_SIZE); | |
1974 | |
1975 ngx_http_v2_queue_blocked_frame(h2c, frame); | |
1976 | |
1977 return ngx_http_v2_state_complete(h2c, pos + NGX_HTTP_V2_PING_SIZE, end); | |
1978 } | |
1979 | |
1980 | |
1981 static u_char * | |
1982 ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, u_char *pos, | |
1983 u_char *end) | |
1984 { | |
1985 #if (NGX_DEBUG) | |
1986 ngx_uint_t last_sid, error; | |
1987 #endif | |
1988 | |
1989 if (h2c->state.length < NGX_HTTP_V2_GOAWAY_SIZE) { | |
1990 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
1991 "client sent GOAWAY frame " | |
1992 "with incorrect length %uz", h2c->state.length); | |
1993 | |
1994 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
1995 } | |
1996 | |
1997 if (end - pos < NGX_HTTP_V2_GOAWAY_SIZE) { | |
1998 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway); | |
1999 } | |
2000 | |
2001 #if (NGX_DEBUG) | |
2002 h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE; | |
2003 | |
2004 last_sid = ngx_http_v2_parse_sid(pos); | |
2005 error = ngx_http_v2_parse_uint32(&pos[4]); | |
2006 | |
2007 pos += NGX_HTTP_V2_GOAWAY_SIZE; | |
2008 | |
2009 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2010 "http2 GOAWAY frame: last sid %ui, error %ui", | |
2011 last_sid, error); | |
2012 #endif | |
2013 | |
2014 return ngx_http_v2_state_skip(h2c, pos, end); | |
2015 } | |
2016 | |
2017 | |
2018 static u_char * | |
2019 ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2020 u_char *end) | |
2021 { | |
2022 size_t window; | |
2023 ngx_event_t *wev; | |
2024 ngx_queue_t *q; | |
2025 ngx_http_v2_node_t *node; | |
2026 ngx_http_v2_stream_t *stream; | |
2027 | |
2028 if (h2c->state.length != NGX_HTTP_V2_WINDOW_UPDATE_SIZE) { | |
2029 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
2030 "client sent WINDOW_UPDATE frame " | |
2031 "with incorrect length %uz", h2c->state.length); | |
2032 | |
2033 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
2034 } | |
2035 | |
2036 if (end - pos < NGX_HTTP_V2_WINDOW_UPDATE_SIZE) { | |
2037 return ngx_http_v2_state_save(h2c, pos, end, | |
2038 ngx_http_v2_state_window_update); | |
2039 } | |
2040 | |
2041 window = ngx_http_v2_parse_window(pos); | |
2042 | |
2043 pos += NGX_HTTP_V2_WINDOW_UPDATE_SIZE; | |
2044 | |
2045 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2046 "http2 WINDOW_UPDATE frame sid:%ui window:%uz", | |
2047 h2c->state.sid, window); | |
2048 | |
2049 if (h2c->state.sid) { | |
2050 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); | |
2051 | |
2052 if (node == NULL || node->stream == NULL) { | |
2053 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2054 "unknown http2 stream"); | |
2055 | |
2056 return ngx_http_v2_state_complete(h2c, pos, end); | |
2057 } | |
2058 | |
2059 stream = node->stream; | |
2060 | |
2061 if (window > (size_t) (NGX_HTTP_V2_MAX_WINDOW - stream->send_window)) { | |
2062 | |
2063 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
2064 "client violated flow control for stream %ui: " | |
2065 "received WINDOW_UPDATE frame " | |
2066 "with window increment %uz " | |
2067 "not allowed for window %z", | |
2068 h2c->state.sid, window, stream->send_window); | |
2069 | |
2070 if (ngx_http_v2_terminate_stream(h2c, stream, | |
2071 NGX_HTTP_V2_FLOW_CTRL_ERROR) | |
2072 == NGX_ERROR) | |
2073 { | |
2074 return ngx_http_v2_connection_error(h2c, | |
2075 NGX_HTTP_V2_INTERNAL_ERROR); | |
2076 } | |
2077 | |
2078 return ngx_http_v2_state_complete(h2c, pos, end); | |
2079 } | |
2080 | |
2081 stream->send_window += window; | |
2082 | |
2083 if (stream->exhausted) { | |
2084 stream->exhausted = 0; | |
2085 | |
2086 wev = stream->request->connection->write; | |
2087 | |
2088 if (!wev->timer_set) { | |
2089 wev->delayed = 0; | |
2090 wev->handler(wev); | |
2091 } | |
2092 } | |
2093 | |
2094 return ngx_http_v2_state_complete(h2c, pos, end); | |
2095 } | |
2096 | |
2097 if (window > NGX_HTTP_V2_MAX_WINDOW - h2c->send_window) { | |
2098 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
2099 "client violated connection flow control: " | |
2100 "received WINDOW_UPDATE frame " | |
2101 "with window increment %uz " | |
2102 "not allowed for window %uz", | |
2103 window, h2c->send_window); | |
2104 | |
2105 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR); | |
2106 } | |
2107 | |
2108 h2c->send_window += window; | |
2109 | |
2110 while (!ngx_queue_empty(&h2c->waiting)) { | |
2111 q = ngx_queue_head(&h2c->waiting); | |
2112 | |
2113 ngx_queue_remove(q); | |
2114 | |
2115 stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue); | |
2116 | |
2117 stream->handled = 0; | |
2118 | |
2119 wev = stream->request->connection->write; | |
2120 | |
2121 if (!wev->timer_set) { | |
2122 wev->delayed = 0; | |
2123 wev->handler(wev); | |
2124 | |
2125 if (h2c->send_window == 0) { | |
2126 break; | |
2127 } | |
2128 } | |
2129 } | |
2130 | |
2131 return ngx_http_v2_state_complete(h2c, pos, end); | |
2132 } | |
2133 | |
2134 | |
2135 static u_char * | |
2136 ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2137 u_char *end) | |
2138 { | |
2139 ngx_http_v2_node_t *node; | |
2140 ngx_http_v2_stream_t *stream; | |
2141 ngx_http_v2_srv_conf_t *h2scf; | |
2142 | |
2143 if (h2c->state.length == 0) { | |
2144 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
2145 "client sent CONTINUATION with empty header block"); | |
2146 | |
2147 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | |
2148 } | |
2149 | |
2150 if (h2c->state.sid == 0) { | |
2151 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
2152 "client sent CONTINUATION frame with incorrect identifier"); | |
2153 | |
2154 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
2155 } | |
2156 | |
2157 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); | |
2158 | |
2159 if (node == NULL || node->stream == NULL) { | |
2160 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
2161 ngx_http_v2_module); | |
2162 | |
2163 h2c->state.header_limit = h2scf->max_header_size; | |
2164 | |
2165 return ngx_http_v2_state_skip_headers(h2c, pos, end); | |
2166 } | |
2167 | |
2168 stream = node->stream; | |
2169 | |
2170 if (stream->end_headers) { | |
2171 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | |
2172 "client sent unexpected CONTINUATION frame"); | |
2173 | |
2174 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | |
2175 } | |
2176 | |
2177 h2c->state.stream = stream; | |
2178 h2c->state.header_limit = stream->header_limit; | |
2179 h2c->state.pool = stream->request->pool; | |
2180 | |
2181 return ngx_http_v2_state_header_block(h2c, pos, end); | |
2182 } | |
2183 | |
2184 | |
2185 static u_char * | |
2186 ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2187 u_char *end) | |
2188 { | |
2189 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2190 "http2 frame complete pos:%p end:%p", pos, end); | |
2191 | |
2192 if (pos > end) { | |
2193 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
2194 "receive buffer overrun"); | |
2195 | |
2196 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
2197 } | |
2198 | |
2199 h2c->state.stream = NULL; | |
2200 h2c->state.handler = ngx_http_v2_state_head; | |
2201 | |
2202 return pos; | |
2203 } | |
2204 | |
2205 | |
2206 static u_char * | |
2207 ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2208 u_char *end) | |
2209 { | |
2210 h2c->state.length += h2c->state.padding; | |
2211 h2c->state.padding = 0; | |
2212 | |
2213 return ngx_http_v2_state_skip(h2c, pos, end); | |
2214 } | |
2215 | |
2216 | |
2217 static u_char * | |
2218 ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) | |
2219 { | |
2220 size_t size; | |
2221 | |
2222 size = end - pos; | |
2223 | |
2224 if (size < h2c->state.length) { | |
2225 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2226 "http2 frame skip %uz of %uz", size, h2c->state.length); | |
2227 | |
2228 h2c->state.length -= size; | |
2229 return ngx_http_v2_state_save(h2c, end, end, ngx_http_v2_state_skip); | |
2230 } | |
2231 | |
2232 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2233 "http2 frame skip %uz", h2c->state.length); | |
2234 | |
2235 return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end); | |
2236 } | |
2237 | |
2238 | |
2239 static u_char * | |
2240 ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2241 u_char *end) | |
2242 { | |
2243 h2c->state.pool = ngx_create_pool(1024, h2c->connection->log); | |
2244 if (h2c->state.pool == NULL) { | |
2245 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
2246 } | |
2247 | |
2248 return ngx_http_v2_state_header_block(h2c, pos, end); | |
2249 } | |
2250 | |
2251 | |
2252 static u_char * | |
2253 ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, | |
2254 ngx_http_v2_handler_pt handler) | |
2255 { | |
2256 size_t size; | |
2257 | |
2258 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2259 "http2 frame state save pos:%p end:%p handler:%p", | |
2260 pos, end, handler); | |
2261 | |
2262 size = end - pos; | |
2263 | |
2264 if (size > NGX_HTTP_V2_STATE_BUFFER_SIZE) { | |
2265 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
2266 "state buffer overflow: %uz bytes required", size); | |
2267 | |
2268 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
2269 } | |
2270 | |
2271 ngx_memcpy(h2c->state.buffer, pos, NGX_HTTP_V2_STATE_BUFFER_SIZE); | |
2272 | |
2273 h2c->state.buffer_used = size; | |
2274 h2c->state.handler = handler; | |
2275 h2c->state.incomplete = 1; | |
2276 | |
2277 return end; | |
2278 } | |
2279 | |
2280 | |
2281 static u_char * | |
2282 ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, | |
2283 ngx_uint_t err) | |
2284 { | |
2285 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2286 "http2 state connection error"); | |
2287 | |
2288 if (err == NGX_HTTP_V2_INTERNAL_ERROR) { | |
2289 ngx_debug_point(); | |
2290 } | |
2291 | |
2292 if (h2c->state.stream) { | |
2293 h2c->state.stream->out_closed = 1; | |
2294 h2c->state.pool = NULL; | |
2295 ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); | |
2296 } | |
2297 | |
2298 ngx_http_v2_finalize_connection(h2c, err); | |
2299 | |
2300 return NULL; | |
2301 } | |
2302 | |
2303 | |
2304 static ngx_int_t | |
2305 ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, | |
2306 ngx_uint_t prefix) | |
2307 { | |
2308 u_char *start, *p; | |
2309 ngx_uint_t value, octet, shift; | |
2310 | |
2311 start = *pos; | |
2312 p = start; | |
2313 | |
2314 value = *p++ & prefix; | |
2315 | |
2316 if (value != prefix) { | |
2317 if (h2c->state.length == 0) { | |
2318 return NGX_ERROR; | |
2319 } | |
2320 | |
2321 h2c->state.length--; | |
2322 | |
2323 *pos = p; | |
2324 return value; | |
2325 } | |
2326 | |
2327 if (end - p > NGX_HTTP_V2_INT_OCTETS - 1) { | |
2328 end = p + NGX_HTTP_V2_INT_OCTETS - 1; | |
2329 } | |
2330 | |
2331 for (shift = 0; p != end; shift += 7) { | |
2332 octet = *p++; | |
2333 | |
2334 value += (octet & 0x7f) << shift; | |
2335 | |
2336 if (octet < 128) { | |
2337 if ((size_t) (p - start) > h2c->state.length) { | |
2338 return NGX_ERROR; | |
2339 } | |
2340 | |
2341 h2c->state.length -= p - start; | |
2342 | |
2343 *pos = p; | |
2344 return value; | |
2345 } | |
2346 } | |
2347 | |
2348 if ((size_t) (end - start) >= NGX_HTTP_V2_INT_OCTETS) { | |
2349 return NGX_DECLINED; | |
2350 } | |
2351 | |
2352 if ((size_t) (end - start) >= h2c->state.length) { | |
2353 return NGX_ERROR; | |
2354 } | |
2355 | |
2356 return NGX_AGAIN; | |
2357 } | |
2358 | |
2359 | |
2360 static ngx_int_t | |
2361 ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) | |
2362 { | |
2363 size_t len; | |
2364 ngx_buf_t *buf; | |
2365 ngx_chain_t *cl; | |
2366 ngx_http_v2_srv_conf_t *h2scf; | |
2367 ngx_http_v2_out_frame_t *frame; | |
2368 | |
2369 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
2370 "http2 send SETTINGS frame"); | |
2371 | |
2372 frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t)); | |
2373 if (frame == NULL) { | |
2374 return NGX_ERROR; | |
2375 } | |
2376 | |
2377 cl = ngx_alloc_chain_link(h2c->pool); | |
2378 if (cl == NULL) { | |
2379 return NGX_ERROR; | |
2380 } | |
2381 | |
2382 len = ack ? 0 : (sizeof(uint16_t) + sizeof(uint32_t)) * 3; | |
2383 | |
2384 buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len); | |
2385 if (buf == NULL) { | |
2386 return NGX_ERROR; | |
2387 } | |
2388 | |
2389 buf->last_buf = 1; | |
2390 | |
2391 cl->buf = buf; | |
2392 cl->next = NULL; | |
2393 | |
2394 frame->first = cl; | |
2395 frame->last = cl; | |
2396 frame->handler = ngx_http_v2_settings_frame_handler; | |
2397 frame->stream = NULL; | |
2398 #if (NGX_DEBUG) | |
2399 frame->length = len; | |
2400 #endif | |
2401 frame->blocked = 0; | |
2402 | |
2403 buf->last = ngx_http_v2_write_len_and_type(buf->last, len, | |
2404 NGX_HTTP_V2_SETTINGS_FRAME); | |
2405 | |
2406 *buf->last++ = ack ? NGX_HTTP_V2_ACK_FLAG : NGX_HTTP_V2_NO_FLAG; | |
2407 | |
2408 buf->last = ngx_http_v2_write_sid(buf->last, 0); | |
2409 | |
2410 if (!ack) { | |
2411 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
2412 ngx_http_v2_module); | |
2413 | |
2414 buf->last = ngx_http_v2_write_uint16(buf->last, | |
2415 NGX_HTTP_V2_MAX_STREAMS_SETTING); | |
2416 buf->last = ngx_http_v2_write_uint32(buf->last, | |
2417 h2scf->concurrent_streams); | |
2418 | |
2419 buf->last = ngx_http_v2_write_uint16(buf->last, | |
2420 NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); | |
2421 buf->last = ngx_http_v2_write_uint32(buf->last, | |
2422 NGX_HTTP_V2_MAX_WINDOW); | |
2423 | |
2424 buf->last = ngx_http_v2_write_uint16(buf->last, | |
2425 NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); | |
2426 buf->last = ngx_http_v2_write_uint32(buf->last, | |
2427 NGX_HTTP_V2_MAX_FRAME_SIZE); | |
2428 } | |
2429 | |
2430 ngx_http_v2_queue_blocked_frame(h2c, frame); | |
2431 | |
2432 return NGX_OK; | |
2433 } | |
2434 | |
2435 | |
2436 static ngx_int_t | |
2437 ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t *h2c, | |
2438 ngx_http_v2_out_frame_t *frame) | |
2439 { | |
2440 ngx_buf_t *buf; | |
2441 | |
2442 buf = frame->first->buf; | |
2443 | |
2444 if (buf->pos != buf->last) { | |
2445 return NGX_AGAIN; | |
2446 } | |
2447 | |
2448 ngx_free_chain(h2c->pool, frame->first); | |
2449 | |
2450 return NGX_OK; | |
2451 } | |
2452 | |
2453 | |
2454 static ngx_int_t | |
2455 ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, | |
2456 size_t window) | |
2457 { | |
2458 ngx_buf_t *buf; | |
2459 ngx_http_v2_out_frame_t *frame; | |
2460 | |
2461 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE, | |
2462 NGX_HTTP_V2_WINDOW_UPDATE_FRAME, | |
2463 NGX_HTTP_V2_NO_FLAG, sid); | |
2464 if (frame == NULL) { | |
2465 return NGX_ERROR; | |
2466 } | |
2467 | |
2468 buf = frame->first->buf; | |
2469 | |
2470 buf->last = ngx_http_v2_write_uint32(buf->last, window); | |
2471 | |
2472 ngx_http_v2_queue_blocked_frame(h2c, frame); | |
2473 | |
2474 return NGX_OK; | |
2475 } | |
2476 | |
2477 | |
2478 static ngx_int_t | |
2479 ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, | |
2480 ngx_uint_t status) | |
2481 { | |
2482 ngx_buf_t *buf; | |
2483 ngx_http_v2_out_frame_t *frame; | |
2484 | |
2485 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE, | |
2486 NGX_HTTP_V2_RST_STREAM_FRAME, | |
2487 NGX_HTTP_V2_NO_FLAG, sid); | |
2488 if (frame == NULL) { | |
2489 return NGX_ERROR; | |
2490 } | |
2491 | |
2492 buf = frame->first->buf; | |
2493 | |
2494 buf->last = ngx_http_v2_write_uint32(buf->last, status); | |
2495 | |
2496 ngx_http_v2_queue_blocked_frame(h2c, frame); | |
2497 | |
2498 return NGX_OK; | |
2499 } | |
2500 | |
2501 | |
2502 static ngx_int_t | |
2503 ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status) | |
2504 { | |
2505 ngx_buf_t *buf; | |
2506 ngx_http_v2_out_frame_t *frame; | |
2507 | |
2508 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE, | |
2509 NGX_HTTP_V2_GOAWAY_FRAME, | |
2510 NGX_HTTP_V2_NO_FLAG, 0); | |
2511 if (frame == NULL) { | |
2512 return NGX_ERROR; | |
2513 } | |
2514 | |
2515 buf = frame->first->buf; | |
2516 | |
2517 buf->last = ngx_http_v2_write_sid(buf->last, h2c->last_sid); | |
2518 buf->last = ngx_http_v2_write_uint32(buf->last, status); | |
2519 | |
2520 ngx_http_v2_queue_blocked_frame(h2c, frame); | |
2521 | |
2522 return NGX_OK; | |
2523 } | |
2524 | |
2525 | |
2526 static ngx_http_v2_out_frame_t * | |
2527 ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length, | |
2528 ngx_uint_t type, u_char flags, ngx_uint_t sid) | |
2529 { | |
2530 ngx_buf_t *buf; | |
2531 ngx_pool_t *pool; | |
2532 ngx_http_v2_out_frame_t *frame; | |
2533 | |
2534 frame = h2c->free_frames; | |
2535 | |
2536 if (frame) { | |
2537 h2c->free_frames = frame->next; | |
2538 | |
2539 buf = frame->first->buf; | |
2540 buf->pos = buf->start; | |
2541 | |
2542 frame->blocked = 0; | |
2543 | |
2544 } else { | |
2545 pool = h2c->pool ? h2c->pool : h2c->connection->pool; | |
2546 | |
2547 frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t)); | |
2548 if (frame == NULL) { | |
2549 return NULL; | |
2550 } | |
2551 | |
2552 frame->first = ngx_alloc_chain_link(pool); | |
2553 if (frame->first == NULL) { | |
2554 return NULL; | |
2555 } | |
2556 | |
2557 buf = ngx_create_temp_buf(pool, NGX_HTTP_V2_FRAME_BUFFER_SIZE); | |
2558 if (buf == NULL) { | |
2559 return NULL; | |
2560 } | |
2561 | |
2562 buf->last_buf = 1; | |
2563 | |
2564 frame->first->buf = buf; | |
2565 frame->last = frame->first; | |
2566 | |
2567 frame->handler = ngx_http_v2_frame_handler; | |
2568 } | |
2569 | |
2570 #if (NGX_DEBUG) | |
2571 if (length > NGX_HTTP_V2_FRAME_BUFFER_SIZE - NGX_HTTP_V2_FRAME_HEADER_SIZE) | |
2572 { | |
2573 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
2574 "requested control frame is too large: %uz", length); | |
2575 return NULL; | |
2576 } | |
2577 | |
2578 frame->length = length; | |
2579 #endif | |
2580 | |
2581 buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type); | |
2582 | |
2583 *buf->last++ = flags; | |
2584 | |
2585 buf->last = ngx_http_v2_write_sid(buf->last, sid); | |
2586 | |
2587 return frame; | |
2588 } | |
2589 | |
2590 | |
2591 static ngx_int_t | |
2592 ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, | |
2593 ngx_http_v2_out_frame_t *frame) | |
2594 { | |
2595 ngx_buf_t *buf; | |
2596 | |
2597 buf = frame->first->buf; | |
2598 | |
2599 if (buf->pos != buf->last) { | |
2600 return NGX_AGAIN; | |
2601 } | |
2602 | |
2603 frame->next = h2c->free_frames; | |
2604 h2c->free_frames = frame; | |
2605 | |
2606 return NGX_OK; | |
2607 } | |
2608 | |
2609 | |
2610 static ngx_http_v2_stream_t * | |
2611 ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c) | |
2612 { | |
2613 ngx_log_t *log; | |
2614 ngx_event_t *rev, *wev; | |
2615 ngx_connection_t *fc; | |
2616 ngx_http_log_ctx_t *ctx; | |
2617 ngx_http_request_t *r; | |
2618 ngx_http_v2_stream_t *stream; | |
2619 ngx_http_core_srv_conf_t *cscf; | |
2620 | |
2621 fc = h2c->free_fake_connections; | |
2622 | |
2623 if (fc) { | |
2624 h2c->free_fake_connections = fc->data; | |
2625 | |
2626 rev = fc->read; | |
2627 wev = fc->write; | |
2628 log = fc->log; | |
2629 ctx = log->data; | |
2630 | |
2631 } else { | |
2632 fc = ngx_palloc(h2c->pool, sizeof(ngx_connection_t)); | |
2633 if (fc == NULL) { | |
2634 return NULL; | |
2635 } | |
2636 | |
2637 rev = ngx_palloc(h2c->pool, sizeof(ngx_event_t)); | |
2638 if (rev == NULL) { | |
2639 return NULL; | |
2640 } | |
2641 | |
2642 wev = ngx_palloc(h2c->pool, sizeof(ngx_event_t)); | |
2643 if (wev == NULL) { | |
2644 return NULL; | |
2645 } | |
2646 | |
2647 log = ngx_palloc(h2c->pool, sizeof(ngx_log_t)); | |
2648 if (log == NULL) { | |
2649 return NULL; | |
2650 } | |
2651 | |
2652 ctx = ngx_palloc(h2c->pool, sizeof(ngx_http_log_ctx_t)); | |
2653 if (ctx == NULL) { | |
2654 return NULL; | |
2655 } | |
2656 | |
2657 ctx->connection = fc; | |
2658 ctx->request = NULL; | |
2659 ctx->current_request = NULL; | |
2660 } | |
2661 | |
2662 ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t)); | |
2663 | |
2664 log->data = ctx; | |
2665 | |
2666 ngx_memzero(rev, sizeof(ngx_event_t)); | |
2667 | |
2668 rev->data = fc; | |
2669 rev->ready = 1; | |
2670 rev->handler = ngx_http_v2_close_stream_handler; | |
2671 rev->log = log; | |
2672 | |
2673 ngx_memcpy(wev, rev, sizeof(ngx_event_t)); | |
2674 | |
2675 wev->write = 1; | |
2676 | |
2677 ngx_memcpy(fc, h2c->connection, sizeof(ngx_connection_t)); | |
2678 | |
2679 fc->data = h2c->http_connection; | |
2680 fc->read = rev; | |
2681 fc->write = wev; | |
2682 fc->sent = 0; | |
2683 fc->log = log; | |
2684 fc->buffered = 0; | |
2685 fc->sndlowat = 1; | |
2686 fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; | |
2687 | |
2688 r = ngx_http_create_request(fc); | |
2689 if (r == NULL) { | |
2690 return NULL; | |
2691 } | |
2692 | |
2693 r->http_version = NGX_HTTP_VERSION_20; | |
2694 r->valid_location = 1; | |
2695 | |
2696 fc->data = r; | |
2697 h2c->connection->requests++; | |
2698 | |
2699 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
2700 | |
2701 r->header_in = ngx_create_temp_buf(r->pool, | |
2702 cscf->client_header_buffer_size); | |
2703 if (r->header_in == NULL) { | |
2704 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
2705 return NULL; | |
2706 } | |
2707 | |
2708 if (ngx_list_init(&r->headers_in.headers, r->pool, 20, | |
2709 sizeof(ngx_table_elt_t)) | |
2710 != NGX_OK) | |
2711 { | |
2712 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
2713 return NULL; | |
2714 } | |
2715 | |
2716 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; | |
2717 | |
2718 stream = ngx_pcalloc(r->pool, sizeof(ngx_http_v2_stream_t)); | |
2719 if (stream == NULL) { | |
2720 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
2721 return NULL; | |
2722 } | |
2723 | |
2724 r->stream = stream; | |
2725 | |
2726 stream->request = r; | |
2727 stream->connection = h2c; | |
2728 | |
2729 stream->send_window = h2c->init_window; | |
2730 stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
2731 | |
2732 h2c->processing++; | |
2733 | |
2734 return stream; | |
2735 } | |
2736 | |
2737 | |
2738 static ngx_http_v2_node_t * | |
2739 ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t *h2c, ngx_uint_t sid, | |
2740 ngx_uint_t alloc) | |
2741 { | |
2742 ngx_uint_t index; | |
2743 ngx_http_v2_node_t *node; | |
2744 ngx_http_v2_srv_conf_t *h2scf; | |
2745 | |
2746 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
2747 ngx_http_v2_module); | |
2748 | |
2749 index = ngx_http_v2_index(h2scf, sid); | |
2750 | |
2751 for (node = h2c->streams_index[index]; node; node = node->index) { | |
2752 | |
2753 if (node->id == sid) { | |
2754 return node; | |
2755 } | |
2756 } | |
2757 | |
2758 if (!alloc) { | |
2759 return NULL; | |
2760 } | |
2761 | |
2762 if (h2c->closed_nodes < 32) { | |
2763 node = ngx_pcalloc(h2c->connection->pool, sizeof(ngx_http_v2_node_t)); | |
2764 if (node == NULL) { | |
2765 return NULL; | |
2766 } | |
2767 | |
2768 } else { | |
2769 node = ngx_http_v2_get_closed_node(h2c); | |
2770 } | |
2771 | |
2772 node->id = sid; | |
2773 | |
2774 ngx_queue_init(&node->children); | |
2775 | |
2776 node->index = h2c->streams_index[index]; | |
2777 h2c->streams_index[index] = node; | |
2778 | |
2779 return node; | |
2780 } | |
2781 | |
2782 | |
2783 static ngx_http_v2_node_t * | |
2784 ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c) | |
2785 { | |
2786 ngx_uint_t weight; | |
2787 ngx_queue_t *q, *children; | |
2788 ngx_http_v2_node_t *node, **next, *n, *parent, *child; | |
2789 ngx_http_v2_srv_conf_t *h2scf; | |
2790 | |
2791 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
2792 ngx_http_v2_module); | |
2793 | |
2794 h2c->closed_nodes--; | |
2795 | |
2796 q = ngx_queue_head(&h2c->closed); | |
2797 | |
2798 ngx_queue_remove(q); | |
2799 | |
2800 node = ngx_queue_data(q, ngx_http_v2_node_t, reuse); | |
2801 | |
2802 next = &h2c->streams_index[ngx_http_v2_index(h2scf, node->id)]; | |
2803 | |
2804 for ( ;; ) { | |
2805 n = *next; | |
2806 | |
2807 if (n == node) { | |
2808 *next = n->index; | |
2809 break; | |
2810 } | |
2811 | |
2812 next = &n->index; | |
2813 } | |
2814 | |
2815 ngx_queue_remove(&node->queue); | |
2816 | |
2817 weight = 0; | |
2818 | |
2819 for (q = ngx_queue_head(&node->children); | |
2820 q != ngx_queue_sentinel(&node->children); | |
2821 q = ngx_queue_next(q)) | |
2822 { | |
2823 child = ngx_queue_data(q, ngx_http_v2_node_t, queue); | |
2824 weight += child->weight; | |
2825 } | |
2826 | |
2827 for (q = ngx_queue_head(&node->children); | |
2828 q != ngx_queue_sentinel(&node->children); | |
2829 q = ngx_queue_next(q)) | |
2830 { | |
2831 child = ngx_queue_data(q, ngx_http_v2_node_t, queue); | |
2832 child->weight = node->weight * child->weight / weight; | |
2833 | |
2834 if (child->weight == 0) { | |
2835 child->weight = 1; | |
2836 } | |
2837 } | |
2838 | |
2839 parent = node->parent; | |
2840 | |
2841 if (parent == NGX_HTTP_V2_ROOT) { | |
2842 node->rank = 0; | |
2843 node->rel_weight = 1.0; | |
2844 | |
2845 children = &h2c->dependencies; | |
2846 | |
2847 } else { | |
2848 node->rank = parent->rank; | |
2849 node->rel_weight = parent->rel_weight; | |
2850 | |
2851 children = &parent->children; | |
2852 } | |
2853 | |
2854 ngx_http_v2_node_children_update(node); | |
2855 ngx_queue_add(children, &node->children); | |
2856 | |
2857 ngx_memzero(node, sizeof(ngx_http_v2_node_t)); | |
2858 | |
2859 return node; | |
2860 } | |
2861 | |
2862 | |
2863 static ngx_int_t | |
2864 ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
2865 { | |
2866 u_char ch; | |
2867 ngx_uint_t i; | |
2868 ngx_http_core_srv_conf_t *cscf; | |
2869 | |
2870 if (header->name.len == 0) { | |
2871 return NGX_ERROR; | |
2872 } | |
2873 | |
2874 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
2875 | |
2876 for (i = (header->name.data[0] == ':'); i != header->name.len; i++) { | |
2877 ch = header->name.data[i]; | |
2878 | |
2879 if ((ch >= 'a' && ch <= 'z') | |
2880 || (ch == '-') | |
2881 || (ch >= '0' && ch <= '9') | |
2882 || (ch == '_' && cscf->underscores_in_headers)) | |
2883 { | |
2884 continue; | |
2885 } | |
2886 | |
2887 switch (ch) { | |
2888 case '\0': | |
2889 case LF: | |
2890 case CR: | |
2891 case ':': | |
2892 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
2893 "client sent invalid header name: \"%V\"", | |
2894 &header->name); | |
2895 | |
2896 return NGX_ERROR; | |
2897 } | |
2898 | |
2899 if (ch >= 'A' && ch <= 'Z') { | |
2900 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
2901 "client sent invalid header name: \"%V\"", | |
2902 &header->name); | |
2903 | |
2904 return NGX_ERROR; | |
2905 } | |
2906 | |
2907 r->invalid_header = 1; | |
2908 } | |
2909 | |
2910 for (i = 0; i != header->value.len; i++) { | |
2911 ch = header->value.data[i]; | |
2912 | |
2913 switch (ch) { | |
2914 case '\0': | |
2915 case LF: | |
2916 case CR: | |
2917 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
2918 "client sent header \"%V\" with " | |
2919 "invalid value: \"%V\"", | |
2920 &header->name, &header->value); | |
2921 | |
2922 return NGX_ERROR; | |
2923 } | |
2924 } | |
2925 | |
2926 return NGX_OK; | |
2927 } | |
2928 | |
2929 | |
2930 static ngx_int_t | |
2931 ngx_http_v2_pseudo_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
2932 { | |
2933 header->name.len--; | |
2934 header->name.data++; | |
2935 | |
2936 switch (header->name.len) { | |
2937 case 4: | |
2938 if (ngx_memcmp(header->name.data, "path", sizeof("path") - 1) | |
2939 == 0) | |
2940 { | |
2941 return ngx_http_v2_parse_path(r, header); | |
2942 } | |
2943 | |
2944 break; | |
2945 | |
2946 case 6: | |
2947 if (ngx_memcmp(header->name.data, "method", sizeof("method") - 1) | |
2948 == 0) | |
2949 { | |
2950 return ngx_http_v2_parse_method(r, header); | |
2951 } | |
2952 | |
2953 if (ngx_memcmp(header->name.data, "scheme", sizeof("scheme") - 1) | |
2954 == 0) | |
2955 { | |
2956 return ngx_http_v2_parse_scheme(r, header); | |
2957 } | |
2958 | |
2959 break; | |
2960 | |
2961 case 9: | |
2962 if (ngx_memcmp(header->name.data, "authority", sizeof("authority") - 1) | |
2963 == 0) | |
2964 { | |
2965 return ngx_http_v2_parse_authority(r, header); | |
2966 } | |
2967 | |
2968 break; | |
2969 } | |
2970 | |
2971 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
2972 "client sent unknown pseudo header \"%V\"", | |
2973 &header->name); | |
2974 | |
2975 return NGX_DECLINED; | |
2976 } | |
2977 | |
2978 | |
2979 static ngx_int_t | |
2980 ngx_http_v2_parse_path(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
2981 { | |
2982 if (r->unparsed_uri.len) { | |
2983 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
2984 "client sent duplicate :path header"); | |
2985 | |
2986 return NGX_DECLINED; | |
2987 } | |
2988 | |
2989 if (header->value.len == 0) { | |
2990 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
2991 "client sent empty :path header"); | |
2992 | |
2993 return NGX_DECLINED; | |
2994 } | |
2995 | |
2996 r->uri_start = header->value.data; | |
2997 r->uri_end = header->value.data + header->value.len; | |
2998 | |
2999 if (ngx_http_parse_uri(r) != NGX_OK) { | |
3000 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3001 "client sent invalid :path header: \"%V\"", | |
3002 &header->value); | |
3003 | |
3004 return NGX_DECLINED; | |
3005 } | |
3006 | |
3007 if (ngx_http_process_request_uri(r) != NGX_OK) { | |
3008 /* | |
3009 * request has been finalized already | |
3010 * in ngx_http_process_request_uri() | |
3011 */ | |
3012 return NGX_ABORT; | |
3013 } | |
3014 | |
3015 return NGX_OK; | |
3016 } | |
3017 | |
3018 | |
3019 static ngx_int_t | |
3020 ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
3021 { | |
3022 size_t k, len; | |
3023 ngx_uint_t n; | |
3024 const u_char *p, *m; | |
3025 | |
3026 /* | |
3027 * This array takes less than 256 sequential bytes, | |
3028 * and if typical CPU cache line size is 64 bytes, | |
3029 * it is prefetched for 4 load operations. | |
3030 */ | |
3031 static const struct { | |
3032 u_char len; | |
3033 const u_char method[11]; | |
3034 uint32_t value; | |
3035 } tests[] = { | |
3036 { 3, "GET", NGX_HTTP_GET }, | |
3037 { 4, "POST", NGX_HTTP_POST }, | |
3038 { 4, "HEAD", NGX_HTTP_HEAD }, | |
3039 { 7, "OPTIONS", NGX_HTTP_OPTIONS }, | |
3040 { 8, "PROPFIND", NGX_HTTP_PROPFIND }, | |
3041 { 3, "PUT", NGX_HTTP_PUT }, | |
3042 { 5, "MKCOL", NGX_HTTP_MKCOL }, | |
3043 { 6, "DELETE", NGX_HTTP_DELETE }, | |
3044 { 4, "COPY", NGX_HTTP_COPY }, | |
3045 { 4, "MOVE", NGX_HTTP_MOVE }, | |
3046 { 9, "PROPPATCH", NGX_HTTP_PROPPATCH }, | |
3047 { 4, "LOCK", NGX_HTTP_LOCK }, | |
3048 { 6, "UNLOCK", NGX_HTTP_UNLOCK }, | |
3049 { 5, "PATCH", NGX_HTTP_PATCH }, | |
3050 { 5, "TRACE", NGX_HTTP_TRACE } | |
3051 }, *test; | |
3052 | |
3053 if (r->method_name.len) { | |
3054 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3055 "client sent duplicate :method header"); | |
3056 | |
3057 return NGX_DECLINED; | |
3058 } | |
3059 | |
3060 if (header->value.len == 0) { | |
3061 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3062 "client sent empty :method header"); | |
3063 | |
3064 return NGX_DECLINED; | |
3065 } | |
3066 | |
3067 r->method_name.len = header->value.len; | |
3068 r->method_name.data = header->value.data; | |
3069 | |
3070 len = r->method_name.len; | |
3071 n = sizeof(tests) / sizeof(tests[0]); | |
3072 test = tests; | |
3073 | |
3074 do { | |
3075 if (len == test->len) { | |
3076 p = r->method_name.data; | |
3077 m = test->method; | |
3078 k = len; | |
3079 | |
3080 do { | |
3081 if (*p++ != *m++) { | |
3082 goto next; | |
3083 } | |
3084 } while (--k); | |
3085 | |
3086 r->method = test->value; | |
3087 return NGX_OK; | |
3088 } | |
3089 | |
3090 next: | |
3091 test++; | |
3092 | |
3093 } while (--n); | |
3094 | |
3095 p = r->method_name.data; | |
3096 | |
3097 do { | |
3098 if ((*p < 'A' || *p > 'Z') && *p != '_') { | |
3099 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3100 "client sent invalid method: \"%V\"", | |
3101 &r->method_name); | |
3102 | |
3103 return NGX_DECLINED; | |
3104 } | |
3105 | |
3106 p++; | |
3107 | |
3108 } while (--len); | |
3109 | |
3110 return NGX_OK; | |
3111 } | |
3112 | |
3113 | |
3114 static ngx_int_t | |
3115 ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
3116 { | |
3117 if (r->schema_start) { | |
3118 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3119 "client sent duplicate :schema header"); | |
3120 | |
3121 return NGX_DECLINED; | |
3122 } | |
3123 | |
3124 if (header->value.len == 0) { | |
3125 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3126 "client sent empty :schema header"); | |
3127 | |
3128 return NGX_DECLINED; | |
3129 } | |
3130 | |
3131 r->schema_start = header->value.data; | |
3132 r->schema_end = header->value.data + header->value.len; | |
3133 | |
3134 return NGX_OK; | |
3135 } | |
3136 | |
3137 | |
3138 static ngx_int_t | |
3139 ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
3140 { | |
3141 ngx_table_elt_t *h; | |
3142 ngx_http_header_t *hh; | |
3143 ngx_http_core_main_conf_t *cmcf; | |
3144 | |
3145 static ngx_str_t host = ngx_string("host"); | |
3146 | |
3147 h = ngx_list_push(&r->headers_in.headers); | |
3148 if (h == NULL) { | |
3149 return NGX_ERROR; | |
3150 } | |
3151 | |
3152 h->hash = ngx_hash_key(host.data, host.len); | |
3153 | |
3154 h->key.len = host.len; | |
3155 h->key.data = host.data; | |
3156 | |
3157 h->value.len = header->value.len; | |
3158 h->value.data = header->value.data; | |
3159 | |
3160 h->lowcase_key = host.data; | |
3161 | |
3162 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
3163 | |
3164 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, | |
3165 h->lowcase_key, h->key.len); | |
3166 | |
3167 if (hh == NULL) { | |
3168 return NGX_ERROR; | |
3169 } | |
3170 | |
3171 if (hh->handler(r, h, hh->offset) != NGX_OK) { | |
3172 /* | |
3173 * request has been finalized already | |
3174 * in ngx_http_process_host() | |
3175 */ | |
3176 return NGX_ABORT; | |
3177 } | |
3178 | |
3179 return NGX_OK; | |
3180 } | |
3181 | |
3182 | |
3183 static ngx_int_t | |
3184 ngx_http_v2_construct_request_line(ngx_http_request_t *r) | |
3185 { | |
3186 u_char *p; | |
3187 | |
3188 static const u_char ending[] = " HTTP/2.0"; | |
3189 | |
3190 if (r->method_name.len == 0 | |
3191 || r->unparsed_uri.len == 0) | |
3192 { | |
3193 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
3194 return NGX_ERROR; | |
3195 } | |
3196 | |
3197 r->request_line.len = r->method_name.len + 1 | |
3198 + r->unparsed_uri.len | |
3199 + sizeof(ending) - 1; | |
3200 | |
3201 p = ngx_pnalloc(r->pool, r->request_line.len + 1); | |
3202 if (p == NULL) { | |
3203 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
3204 return NGX_ERROR; | |
3205 } | |
3206 | |
3207 r->request_line.data = p; | |
3208 | |
3209 p = ngx_cpymem(p, r->method_name.data, r->method_name.len); | |
3210 | |
3211 *p++ = ' '; | |
3212 | |
3213 p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len); | |
3214 | |
3215 ngx_memcpy(p, ending, sizeof(ending)); | |
3216 | |
3217 /* some modules expect the space character after method name */ | |
3218 r->method_name.data = r->request_line.data; | |
3219 | |
3220 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3221 "http2 http request line: \"%V\"", &r->request_line); | |
3222 | |
3223 return NGX_OK; | |
3224 } | |
3225 | |
3226 | |
3227 static ngx_int_t | |
3228 ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header) | |
3229 { | |
3230 ngx_str_t *val; | |
3231 ngx_array_t *cookies; | |
3232 | |
3233 cookies = r->stream->cookies; | |
3234 | |
3235 if (cookies == NULL) { | |
3236 cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t)); | |
3237 if (cookies == NULL) { | |
3238 return NGX_ERROR; | |
3239 } | |
3240 | |
3241 r->stream->cookies = cookies; | |
3242 } | |
3243 | |
3244 val = ngx_array_push(cookies); | |
3245 if (val == NULL) { | |
3246 return NGX_ERROR; | |
3247 } | |
3248 | |
3249 val->len = header->value.len; | |
3250 val->data = header->value.data; | |
3251 | |
3252 return NGX_OK; | |
3253 } | |
3254 | |
3255 | |
3256 static ngx_int_t | |
3257 ngx_http_v2_construct_cookie_header(ngx_http_request_t *r) | |
3258 { | |
3259 u_char *buf, *p, *end; | |
3260 size_t len; | |
3261 ngx_str_t *vals; | |
3262 ngx_uint_t i; | |
3263 ngx_array_t *cookies; | |
3264 ngx_table_elt_t *h; | |
3265 ngx_http_header_t *hh; | |
3266 ngx_http_core_main_conf_t *cmcf; | |
3267 | |
3268 static ngx_str_t cookie = ngx_string("cookie"); | |
3269 | |
3270 cookies = r->stream->cookies; | |
3271 | |
3272 if (cookies == NULL) { | |
3273 return NGX_OK; | |
3274 } | |
3275 | |
3276 vals = cookies->elts; | |
3277 | |
3278 i = 0; | |
3279 len = 0; | |
3280 | |
3281 do { | |
3282 len += vals[i].len + 2; | |
3283 } while (++i != cookies->nelts); | |
3284 | |
3285 len -= 2; | |
3286 | |
3287 buf = ngx_pnalloc(r->pool, len + 1); | |
3288 if (buf == NULL) { | |
3289 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
3290 return NGX_ERROR; | |
3291 } | |
3292 | |
3293 p = buf; | |
3294 end = buf + len; | |
3295 | |
3296 for (i = 0; /* void */ ; i++) { | |
3297 | |
3298 p = ngx_cpymem(p, vals[i].data, vals[i].len); | |
3299 | |
3300 if (p == end) { | |
3301 *p = '\0'; | |
3302 break; | |
3303 } | |
3304 | |
3305 *p++ = ';'; *p++ = ' '; | |
3306 } | |
3307 | |
3308 h = ngx_list_push(&r->headers_in.headers); | |
3309 if (h == NULL) { | |
3310 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
3311 return NGX_ERROR; | |
3312 } | |
3313 | |
3314 h->hash = ngx_hash_key(cookie.data, cookie.len); | |
3315 | |
3316 h->key.len = cookie.len; | |
3317 h->key.data = cookie.data; | |
3318 | |
3319 h->value.len = len; | |
3320 h->value.data = buf; | |
3321 | |
3322 h->lowcase_key = cookie.data; | |
3323 | |
3324 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); | |
3325 | |
3326 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, | |
3327 h->lowcase_key, h->key.len); | |
3328 | |
3329 if (hh == NULL) { | |
3330 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
3331 return NGX_ERROR; | |
3332 } | |
3333 | |
3334 if (hh->handler(r, h, hh->offset) != NGX_OK) { | |
3335 /* | |
3336 * request has been finalized already | |
3337 * in ngx_http_process_multi_header_lines() | |
3338 */ | |
3339 return NGX_ERROR; | |
3340 } | |
3341 | |
3342 return NGX_OK; | |
3343 } | |
3344 | |
3345 | |
3346 static void | |
3347 ngx_http_v2_run_request(ngx_http_request_t *r) | |
3348 { | |
3349 if (ngx_http_v2_construct_request_line(r) != NGX_OK) { | |
3350 return; | |
3351 } | |
3352 | |
3353 if (ngx_http_v2_construct_cookie_header(r) != NGX_OK) { | |
3354 return; | |
3355 } | |
3356 | |
3357 r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; | |
3358 | |
3359 if (ngx_http_process_request_header(r) != NGX_OK) { | |
3360 return; | |
3361 } | |
3362 | |
3363 if (r->headers_in.content_length_n > 0 && r->stream->in_closed) { | |
3364 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
3365 "client prematurely closed stream"); | |
3366 | |
3367 r->stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | |
3368 | |
3369 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); | |
3370 return; | |
3371 } | |
3372 | |
3373 ngx_http_process_request(r); | |
3374 } | |
3375 | |
3376 | |
3377 static ngx_int_t | |
3378 ngx_http_v2_init_request_body(ngx_http_request_t *r) | |
3379 { | |
3380 ngx_buf_t *buf; | |
3381 ngx_temp_file_t *tf; | |
3382 ngx_http_request_body_t *rb; | |
3383 ngx_http_core_loc_conf_t *clcf; | |
3384 | |
3385 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); | |
3386 if (rb == NULL) { | |
3387 return NGX_ERROR; | |
3388 } | |
3389 | |
3390 r->request_body = rb; | |
3391 | |
3392 if (r->stream->in_closed) { | |
3393 return NGX_OK; | |
3394 } | |
3395 | |
3396 rb->rest = r->headers_in.content_length_n; | |
3397 | |
3398 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
3399 | |
3400 if (r->request_body_in_file_only | |
3401 || rb->rest > (off_t) clcf->client_body_buffer_size | |
3402 || rb->rest < 0) | |
3403 { | |
3404 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); | |
3405 if (tf == NULL) { | |
3406 return NGX_ERROR; | |
3407 } | |
3408 | |
3409 tf->file.fd = NGX_INVALID_FILE; | |
3410 tf->file.log = r->connection->log; | |
3411 tf->path = clcf->client_body_temp_path; | |
3412 tf->pool = r->pool; | |
3413 tf->warn = "a client request body is buffered to a temporary file"; | |
3414 tf->log_level = r->request_body_file_log_level; | |
3415 tf->persistent = r->request_body_in_persistent_file; | |
3416 tf->clean = r->request_body_in_clean_file; | |
3417 | |
3418 if (r->request_body_file_group_access) { | |
3419 tf->access = 0660; | |
3420 } | |
3421 | |
3422 rb->temp_file = tf; | |
3423 | |
3424 if (r->stream->in_closed | |
3425 && ngx_create_temp_file(&tf->file, tf->path, tf->pool, | |
3426 tf->persistent, tf->clean, tf->access) | |
3427 != NGX_OK) | |
3428 { | |
3429 return NGX_ERROR; | |
3430 } | |
3431 | |
3432 buf = ngx_calloc_buf(r->pool); | |
3433 if (buf == NULL) { | |
3434 return NGX_ERROR; | |
3435 } | |
3436 | |
3437 } else { | |
3438 | |
3439 if (rb->rest == 0) { | |
3440 return NGX_OK; | |
3441 } | |
3442 | |
3443 buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest); | |
3444 if (buf == NULL) { | |
3445 return NGX_ERROR; | |
3446 } | |
3447 } | |
3448 | |
3449 rb->buf = buf; | |
3450 | |
3451 rb->bufs = ngx_alloc_chain_link(r->pool); | |
3452 if (rb->bufs == NULL) { | |
3453 return NGX_ERROR; | |
3454 } | |
3455 | |
3456 rb->bufs->buf = buf; | |
3457 rb->bufs->next = NULL; | |
3458 | |
3459 rb->rest = 0; | |
3460 | |
3461 return NGX_OK; | |
3462 } | |
3463 | |
3464 | |
3465 ngx_int_t | |
3466 ngx_http_v2_read_request_body(ngx_http_request_t *r, | |
3467 ngx_http_client_body_handler_pt post_handler) | |
3468 { | |
3469 ngx_http_v2_stream_t *stream; | |
3470 | |
3471 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3472 "http2 read request body"); | |
3473 | |
3474 stream = r->stream; | |
3475 | |
3476 switch (stream->skip_data) { | |
3477 | |
3478 case NGX_HTTP_V2_DATA_DISCARD: | |
3479 post_handler(r); | |
3480 return NGX_OK; | |
3481 | |
3482 case NGX_HTTP_V2_DATA_ERROR: | |
3483 if (r->headers_in.content_length_n == -1) { | |
3484 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; | |
3485 } else { | |
3486 return NGX_HTTP_BAD_REQUEST; | |
3487 } | |
3488 | |
3489 case NGX_HTTP_V2_DATA_INTERNAL_ERROR: | |
3490 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
3491 } | |
3492 | |
3493 if (!r->request_body && ngx_http_v2_init_request_body(r) != NGX_OK) { | |
3494 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; | |
3495 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
3496 } | |
3497 | |
3498 if (stream->in_closed) { | |
3499 post_handler(r); | |
3500 return NGX_OK; | |
3501 } | |
3502 | |
3503 r->request_body->post_handler = post_handler; | |
3504 | |
3505 r->read_event_handler = ngx_http_test_reading; | |
3506 r->write_event_handler = ngx_http_request_empty_handler; | |
3507 | |
3508 return NGX_AGAIN; | |
3509 } | |
3510 | |
3511 | |
3512 static ngx_int_t | |
3513 ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, | |
3514 ngx_http_v2_stream_t *stream, ngx_uint_t status) | |
3515 { | |
3516 ngx_event_t *rev; | |
3517 ngx_connection_t *fc; | |
3518 | |
3519 if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status) | |
3520 == NGX_ERROR) | |
3521 { | |
3522 return NGX_ERROR; | |
3523 } | |
3524 | |
3525 stream->out_closed = 1; | |
3526 | |
3527 fc = stream->request->connection; | |
3528 fc->error = 1; | |
3529 | |
3530 rev = fc->read; | |
3531 rev->handler(rev); | |
3532 | |
3533 return NGX_OK; | |
3534 } | |
3535 | |
3536 | |
3537 void | |
3538 ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) | |
3539 { | |
3540 ngx_event_t *ev; | |
3541 ngx_connection_t *fc; | |
3542 ngx_http_v2_node_t *node; | |
3543 ngx_http_v2_connection_t *h2c; | |
3544 | |
3545 h2c = stream->connection; | |
3546 node = stream->node; | |
3547 | |
3548 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
3549 "http2 close stream %ui, queued %ui, processing %ui", | |
3550 node->id, stream->queued, h2c->processing); | |
3551 | |
3552 fc = stream->request->connection; | |
3553 | |
3554 if (stream->queued) { | |
3555 fc->write->handler = ngx_http_v2_close_stream_handler; | |
3556 return; | |
3557 } | |
3558 | |
3559 if (!stream->out_closed) { | |
3560 if (ngx_http_v2_send_rst_stream(h2c, node->id, | |
3561 NGX_HTTP_V2_INTERNAL_ERROR) | |
3562 != NGX_OK) | |
3563 { | |
3564 h2c->connection->error = 1; | |
3565 } | |
3566 } | |
3567 | |
3568 node->stream = NULL; | |
3569 | |
3570 ngx_queue_insert_tail(&h2c->closed, &node->reuse); | |
3571 h2c->closed_nodes++; | |
3572 | |
3573 ngx_http_free_request(stream->request, rc); | |
3574 | |
3575 ev = fc->read; | |
3576 | |
3577 if (ev->active || ev->disabled) { | |
3578 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
3579 "fake read event was activated"); | |
3580 } | |
3581 | |
3582 if (ev->timer_set) { | |
3583 ngx_del_timer(ev); | |
3584 } | |
3585 | |
3586 if (ev->posted) { | |
3587 ngx_delete_posted_event(ev); | |
3588 } | |
3589 | |
3590 ev = fc->write; | |
3591 | |
3592 if (ev->active || ev->disabled) { | |
3593 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
3594 "fake write event was activated"); | |
3595 } | |
3596 | |
3597 if (ev->timer_set) { | |
3598 ngx_del_timer(ev); | |
3599 } | |
3600 | |
3601 if (ev->posted) { | |
3602 ngx_delete_posted_event(ev); | |
3603 } | |
3604 | |
3605 fc->data = h2c->free_fake_connections; | |
3606 h2c->free_fake_connections = fc; | |
3607 | |
3608 h2c->processing--; | |
3609 | |
3610 if (h2c->processing || h2c->blocked) { | |
3611 return; | |
3612 } | |
3613 | |
3614 ev = h2c->connection->read; | |
3615 | |
3616 ev->handler = ngx_http_v2_handle_connection_handler; | |
3617 ngx_post_event(ev, &ngx_posted_events); | |
3618 } | |
3619 | |
3620 | |
3621 static void | |
3622 ngx_http_v2_close_stream_handler(ngx_event_t *ev) | |
3623 { | |
3624 ngx_connection_t *fc; | |
3625 ngx_http_request_t *r; | |
3626 | |
3627 fc = ev->data; | |
3628 r = fc->data; | |
3629 | |
3630 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3631 "http2 close stream handler"); | |
3632 | |
3633 ngx_http_v2_close_stream(r->stream, 0); | |
3634 } | |
3635 | |
3636 | |
3637 static void | |
3638 ngx_http_v2_handle_connection_handler(ngx_event_t *rev) | |
3639 { | |
3640 ngx_connection_t *c; | |
3641 | |
3642 rev->handler = ngx_http_v2_read_handler; | |
3643 | |
3644 if (rev->ready) { | |
3645 ngx_http_v2_read_handler(rev); | |
3646 return; | |
3647 } | |
3648 | |
3649 c = rev->data; | |
3650 | |
3651 ngx_http_v2_handle_connection(c->data); | |
3652 } | |
3653 | |
3654 | |
3655 static void | |
3656 ngx_http_v2_idle_handler(ngx_event_t *rev) | |
3657 { | |
3658 ngx_connection_t *c; | |
3659 ngx_http_v2_srv_conf_t *h2scf; | |
3660 ngx_http_v2_connection_t *h2c; | |
3661 | |
3662 c = rev->data; | |
3663 h2c = c->data; | |
3664 | |
3665 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 idle handler"); | |
3666 | |
3667 if (rev->timedout || c->close) { | |
3668 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); | |
3669 return; | |
3670 } | |
3671 | |
3672 #if (NGX_HAVE_KQUEUE) | |
3673 | |
3674 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { | |
3675 if (rev->pending_eof) { | |
3676 c->log->handler = NULL; | |
3677 ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, | |
3678 "kevent() reported that client %V closed " | |
3679 "idle connection", &c->addr_text); | |
3680 #if (NGX_HTTP_SSL) | |
3681 if (c->ssl) { | |
3682 c->ssl->no_send_shutdown = 1; | |
3683 } | |
3684 #endif | |
3685 ngx_http_close_connection(c); | |
3686 return; | |
3687 } | |
3688 } | |
3689 | |
3690 #endif | |
3691 | |
3692 c->destroyed = 0; | |
3693 c->idle = 0; | |
3694 ngx_reusable_connection(c, 0); | |
3695 | |
3696 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
3697 ngx_http_v2_module); | |
3698 | |
3699 h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); | |
3700 if (h2c->pool == NULL) { | |
3701 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
3702 return; | |
3703 } | |
3704 | |
3705 c->write->handler = ngx_http_v2_write_handler; | |
3706 | |
3707 rev->handler = ngx_http_v2_read_handler; | |
3708 ngx_http_v2_read_handler(rev); | |
3709 } | |
3710 | |
3711 | |
3712 static void | |
3713 ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, | |
3714 ngx_uint_t status) | |
3715 { | |
3716 ngx_uint_t i, size; | |
3717 ngx_event_t *ev; | |
3718 ngx_connection_t *c, *fc; | |
3719 ngx_http_request_t *r; | |
3720 ngx_http_v2_node_t *node; | |
3721 ngx_http_v2_stream_t *stream; | |
3722 ngx_http_v2_srv_conf_t *h2scf; | |
3723 | |
3724 c = h2c->connection; | |
3725 | |
3726 h2c->blocked = 1; | |
3727 | |
3728 if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { | |
3729 (void) ngx_http_v2_send_output_queue(h2c); | |
3730 } | |
3731 | |
3732 if (!h2c->processing) { | |
3733 ngx_http_close_connection(c); | |
3734 return; | |
3735 } | |
3736 | |
3737 c->error = 1; | |
3738 c->read->handler = ngx_http_empty_handler; | |
3739 c->write->handler = ngx_http_empty_handler; | |
3740 | |
3741 h2c->last_out = NULL; | |
3742 | |
3743 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
3744 ngx_http_v2_module); | |
3745 | |
3746 size = ngx_http_v2_index_size(h2scf); | |
3747 | |
3748 for (i = 0; i < size; i++) { | |
3749 | |
3750 for (node = h2c->streams_index[i]; node; node = node->index) { | |
3751 stream = node->stream; | |
3752 | |
3753 if (stream == NULL) { | |
3754 continue; | |
3755 } | |
3756 | |
3757 stream->handled = 0; | |
3758 | |
3759 r = stream->request; | |
3760 fc = r->connection; | |
3761 | |
3762 fc->error = 1; | |
3763 | |
3764 if (stream->queued) { | |
3765 stream->queued = 0; | |
3766 | |
3767 ev = fc->write; | |
3768 ev->delayed = 0; | |
3769 | |
3770 } else { | |
3771 ev = fc->read; | |
3772 } | |
3773 | |
3774 ev->eof = 1; | |
3775 ev->handler(ev); | |
3776 } | |
3777 } | |
3778 | |
3779 h2c->blocked = 0; | |
3780 | |
3781 if (h2c->processing) { | |
3782 return; | |
3783 } | |
3784 | |
3785 ngx_http_close_connection(c); | |
3786 } | |
3787 | |
3788 | |
3789 static ngx_int_t | |
3790 ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, ssize_t delta) | |
3791 { | |
3792 ngx_uint_t i, size; | |
3793 ngx_event_t *wev; | |
3794 ngx_http_v2_node_t *node; | |
3795 ngx_http_v2_stream_t *stream; | |
3796 ngx_http_v2_srv_conf_t *h2scf; | |
3797 | |
3798 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | |
3799 ngx_http_v2_module); | |
3800 | |
3801 size = ngx_http_v2_index_size(h2scf); | |
3802 | |
3803 for (i = 0; i < size; i++) { | |
3804 | |
3805 for (node = h2c->streams_index[i]; node; node = node->index) { | |
3806 stream = node->stream; | |
3807 | |
3808 if (stream == NULL) { | |
3809 continue; | |
3810 } | |
3811 | |
3812 if (delta > 0 | |
3813 && stream->send_window | |
3814 > (ssize_t) (NGX_HTTP_V2_MAX_WINDOW - delta)) | |
3815 { | |
3816 if (ngx_http_v2_terminate_stream(h2c, stream, | |
3817 NGX_HTTP_V2_FLOW_CTRL_ERROR) | |
3818 == NGX_ERROR) | |
3819 { | |
3820 return NGX_ERROR; | |
3821 } | |
3822 | |
3823 continue; | |
3824 } | |
3825 | |
3826 stream->send_window += delta; | |
3827 | |
3828 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
3829 "http2:%ui adjusted window: %z", | |
3830 node->id, stream->send_window); | |
3831 | |
3832 if (stream->send_window > 0 && stream->exhausted) { | |
3833 stream->exhausted = 0; | |
3834 | |
3835 wev = stream->request->connection->write; | |
3836 | |
3837 if (!wev->timer_set) { | |
3838 wev->delayed = 0; | |
3839 wev->handler(wev); | |
3840 } | |
3841 } | |
3842 } | |
3843 } | |
3844 | |
3845 return NGX_OK; | |
3846 } | |
3847 | |
3848 | |
3849 static void | |
3850 ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c, | |
3851 ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive) | |
3852 { | |
3853 ngx_queue_t *children; | |
3854 ngx_http_v2_node_t *parent, *next; | |
3855 | |
3856 parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL; | |
3857 | |
3858 if (parent == NULL) { | |
3859 parent = NGX_HTTP_V2_ROOT; | |
3860 | |
3861 if (depend != 0) { | |
3862 exclusive = 0; | |
3863 } | |
3864 | |
3865 node->rank = 1; | |
3866 node->rel_weight = (1.0 / 256) * node->weight; | |
3867 | |
3868 children = &h2c->dependencies; | |
3869 | |
3870 } else { | |
3871 if (node->parent != NULL) { | |
3872 | |
3873 for (next = parent->parent; | |
3874 next != NGX_HTTP_V2_ROOT && next->rank >= node->rank; | |
3875 next = next->parent) | |
3876 { | |
3877 if (next != node) { | |
3878 continue; | |
3879 } | |
3880 | |
3881 ngx_queue_remove(&parent->queue); | |
3882 ngx_queue_insert_after(&node->queue, &parent->queue); | |
3883 | |
3884 parent->parent = node->parent; | |
3885 | |
3886 if (node->parent == NGX_HTTP_V2_ROOT) { | |
3887 parent->rank = 1; | |
3888 parent->rel_weight = (1.0 / 256) * parent->weight; | |
3889 | |
3890 } else { | |
3891 parent->rank = node->parent->rank + 1; | |
3892 parent->rel_weight = (node->parent->rel_weight / 256) | |
3893 * parent->weight; | |
3894 } | |
3895 | |
3896 if (!exclusive) { | |
3897 ngx_http_v2_node_children_update(parent); | |
3898 } | |
3899 | |
3900 break; | |
3901 } | |
3902 } | |
3903 | |
3904 node->rank = parent->rank + 1; | |
3905 node->rel_weight = (parent->rel_weight / 256) * node->weight; | |
3906 | |
3907 if (parent->stream == NULL) { | |
3908 ngx_queue_remove(&parent->reuse); | |
3909 ngx_queue_insert_tail(&h2c->closed, &parent->reuse); | |
3910 } | |
3911 | |
3912 children = &parent->children; | |
3913 } | |
3914 | |
3915 if (exclusive) { | |
3916 ngx_queue_add(&node->children, children); | |
3917 ngx_queue_init(children); | |
3918 } | |
3919 | |
3920 if (node->parent != NULL) { | |
3921 ngx_queue_remove(&node->queue); | |
3922 } | |
3923 | |
3924 ngx_queue_insert_tail(children, &node->queue); | |
3925 | |
3926 node->parent = parent; | |
3927 | |
3928 ngx_http_v2_node_children_update(node); | |
3929 } | |
3930 | |
3931 | |
3932 static void | |
3933 ngx_http_v2_node_children_update(ngx_http_v2_node_t *node) | |
3934 { | |
3935 ngx_queue_t *q; | |
3936 ngx_http_v2_node_t *child; | |
3937 | |
3938 for (q = ngx_queue_head(&node->children); | |
3939 q != ngx_queue_sentinel(&node->children); | |
3940 q = ngx_queue_next(q)) | |
3941 { | |
3942 child = ngx_queue_data(q, ngx_http_v2_node_t, queue); | |
3943 | |
3944 child->rank = node->rank + 1; | |
3945 child->rel_weight = (node->rel_weight / 256) * child->weight; | |
3946 | |
3947 ngx_http_v2_node_children_update(child); | |
3948 } | |
3949 } | |
3950 | |
3951 | |
3952 static void | |
3953 ngx_http_v2_pool_cleanup(void *data) | |
3954 { | |
3955 ngx_http_v2_connection_t *h2c = data; | |
3956 | |
3957 if (h2c->state.pool) { | |
3958 ngx_destroy_pool(h2c->state.pool); | |
3959 } | |
3960 | |
3961 if (h2c->pool) { | |
3962 ngx_destroy_pool(h2c->pool); | |
3963 } | |
3964 } |