/src/nginx/src/http/ngx_http_request.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* |
3 | | * Copyright (C) Igor Sysoev |
4 | | * Copyright (C) Nginx, Inc. |
5 | | */ |
6 | | |
7 | | |
8 | | #include <ngx_config.h> |
9 | | #include <ngx_core.h> |
10 | | #include <ngx_http.h> |
11 | | |
12 | | |
13 | | static void ngx_http_wait_request_handler(ngx_event_t *ev); |
14 | | static ngx_http_request_t *ngx_http_alloc_request(ngx_connection_t *c); |
15 | | static void ngx_http_process_request_line(ngx_event_t *rev); |
16 | | static void ngx_http_process_request_headers(ngx_event_t *rev); |
17 | | static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); |
18 | | static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, |
19 | | ngx_uint_t request_line); |
20 | | |
21 | | static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, |
22 | | ngx_table_elt_t *h, ngx_uint_t offset); |
23 | | static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, |
24 | | ngx_table_elt_t *h, ngx_uint_t offset); |
25 | | static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, |
26 | | ngx_table_elt_t *h, ngx_uint_t offset); |
27 | | static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, |
28 | | ngx_table_elt_t *h, ngx_uint_t offset); |
29 | | static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, |
30 | | ngx_table_elt_t *h, ngx_uint_t offset); |
31 | | |
32 | | static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, |
33 | | ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, |
34 | | ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); |
35 | | |
36 | | static void ngx_http_request_handler(ngx_event_t *ev); |
37 | | static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc); |
38 | | static void ngx_http_terminate_handler(ngx_http_request_t *r); |
39 | | static void ngx_http_finalize_connection(ngx_http_request_t *r); |
40 | | static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); |
41 | | static void ngx_http_writer(ngx_http_request_t *r); |
42 | | static void ngx_http_request_finalizer(ngx_http_request_t *r); |
43 | | |
44 | | static void ngx_http_set_keepalive(ngx_http_request_t *r); |
45 | | static void ngx_http_keepalive_handler(ngx_event_t *ev); |
46 | | static void ngx_http_set_lingering_close(ngx_connection_t *c); |
47 | | static void ngx_http_lingering_close_handler(ngx_event_t *ev); |
48 | | static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); |
49 | | static void ngx_http_log_request(ngx_http_request_t *r); |
50 | | |
51 | | static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); |
52 | | static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, |
53 | | ngx_http_request_t *sr, u_char *buf, size_t len); |
54 | | |
55 | | #if (NGX_HTTP_SSL) |
56 | | static void ngx_http_ssl_handshake(ngx_event_t *rev); |
57 | | static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); |
58 | | #endif |
59 | | |
60 | | |
61 | | static char *ngx_http_client_errors[] = { |
62 | | |
63 | | /* NGX_HTTP_PARSE_INVALID_METHOD */ |
64 | | "client sent invalid method", |
65 | | |
66 | | /* NGX_HTTP_PARSE_INVALID_REQUEST */ |
67 | | "client sent invalid request", |
68 | | |
69 | | /* NGX_HTTP_PARSE_INVALID_VERSION */ |
70 | | "client sent invalid version", |
71 | | |
72 | | /* NGX_HTTP_PARSE_INVALID_09_METHOD */ |
73 | | "client sent invalid method in HTTP/0.9 request" |
74 | | }; |
75 | | |
76 | | |
77 | | ngx_http_header_t ngx_http_headers_in[] = { |
78 | | { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), |
79 | | ngx_http_process_host }, |
80 | | |
81 | | { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), |
82 | | ngx_http_process_connection }, |
83 | | |
84 | | { ngx_string("If-Modified-Since"), |
85 | | offsetof(ngx_http_headers_in_t, if_modified_since), |
86 | | ngx_http_process_unique_header_line }, |
87 | | |
88 | | { ngx_string("If-Unmodified-Since"), |
89 | | offsetof(ngx_http_headers_in_t, if_unmodified_since), |
90 | | ngx_http_process_unique_header_line }, |
91 | | |
92 | | { ngx_string("If-Match"), |
93 | | offsetof(ngx_http_headers_in_t, if_match), |
94 | | ngx_http_process_unique_header_line }, |
95 | | |
96 | | { ngx_string("If-None-Match"), |
97 | | offsetof(ngx_http_headers_in_t, if_none_match), |
98 | | ngx_http_process_unique_header_line }, |
99 | | |
100 | | { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), |
101 | | ngx_http_process_user_agent }, |
102 | | |
103 | | { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), |
104 | | ngx_http_process_header_line }, |
105 | | |
106 | | { ngx_string("Content-Length"), |
107 | | offsetof(ngx_http_headers_in_t, content_length), |
108 | | ngx_http_process_unique_header_line }, |
109 | | |
110 | | { ngx_string("Content-Range"), |
111 | | offsetof(ngx_http_headers_in_t, content_range), |
112 | | ngx_http_process_unique_header_line }, |
113 | | |
114 | | { ngx_string("Content-Type"), |
115 | | offsetof(ngx_http_headers_in_t, content_type), |
116 | | ngx_http_process_header_line }, |
117 | | |
118 | | { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range), |
119 | | ngx_http_process_header_line }, |
120 | | |
121 | | { ngx_string("If-Range"), |
122 | | offsetof(ngx_http_headers_in_t, if_range), |
123 | | ngx_http_process_unique_header_line }, |
124 | | |
125 | | { ngx_string("Transfer-Encoding"), |
126 | | offsetof(ngx_http_headers_in_t, transfer_encoding), |
127 | | ngx_http_process_unique_header_line }, |
128 | | |
129 | | { ngx_string("TE"), |
130 | | offsetof(ngx_http_headers_in_t, te), |
131 | | ngx_http_process_header_line }, |
132 | | |
133 | | { ngx_string("Expect"), |
134 | | offsetof(ngx_http_headers_in_t, expect), |
135 | | ngx_http_process_unique_header_line }, |
136 | | |
137 | | { ngx_string("Upgrade"), |
138 | | offsetof(ngx_http_headers_in_t, upgrade), |
139 | | ngx_http_process_header_line }, |
140 | | |
141 | | #if (NGX_HTTP_GZIP || NGX_HTTP_HEADERS) |
142 | | { ngx_string("Accept-Encoding"), |
143 | | offsetof(ngx_http_headers_in_t, accept_encoding), |
144 | | ngx_http_process_header_line }, |
145 | | |
146 | | { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via), |
147 | | ngx_http_process_header_line }, |
148 | | #endif |
149 | | |
150 | | { ngx_string("Authorization"), |
151 | | offsetof(ngx_http_headers_in_t, authorization), |
152 | | ngx_http_process_unique_header_line }, |
153 | | |
154 | | { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), |
155 | | ngx_http_process_header_line }, |
156 | | |
157 | | #if (NGX_HTTP_X_FORWARDED_FOR) |
158 | | { ngx_string("X-Forwarded-For"), |
159 | | offsetof(ngx_http_headers_in_t, x_forwarded_for), |
160 | | ngx_http_process_header_line }, |
161 | | #endif |
162 | | |
163 | | #if (NGX_HTTP_REALIP) |
164 | | { ngx_string("X-Real-IP"), |
165 | | offsetof(ngx_http_headers_in_t, x_real_ip), |
166 | | ngx_http_process_header_line }, |
167 | | #endif |
168 | | |
169 | | #if (NGX_HTTP_HEADERS) |
170 | | { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept), |
171 | | ngx_http_process_header_line }, |
172 | | |
173 | | { ngx_string("Accept-Language"), |
174 | | offsetof(ngx_http_headers_in_t, accept_language), |
175 | | ngx_http_process_header_line }, |
176 | | #endif |
177 | | |
178 | | #if (NGX_HTTP_DAV) |
179 | | { ngx_string("Depth"), offsetof(ngx_http_headers_in_t, depth), |
180 | | ngx_http_process_header_line }, |
181 | | |
182 | | { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination), |
183 | | ngx_http_process_header_line }, |
184 | | |
185 | | { ngx_string("Overwrite"), offsetof(ngx_http_headers_in_t, overwrite), |
186 | | ngx_http_process_header_line }, |
187 | | |
188 | | { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date), |
189 | | ngx_http_process_header_line }, |
190 | | #endif |
191 | | |
192 | | { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookie), |
193 | | ngx_http_process_header_line }, |
194 | | |
195 | | { ngx_null_string, 0, NULL } |
196 | | }; |
197 | | |
198 | | |
199 | | void |
200 | | ngx_http_init_connection(ngx_connection_t *c) |
201 | 16 | { |
202 | 16 | ngx_uint_t i; |
203 | 16 | ngx_event_t *rev; |
204 | 16 | struct sockaddr_in *sin; |
205 | 16 | ngx_http_port_t *port; |
206 | 16 | ngx_http_in_addr_t *addr; |
207 | 16 | ngx_http_log_ctx_t *ctx; |
208 | 16 | ngx_http_connection_t *hc; |
209 | 16 | ngx_http_core_srv_conf_t *cscf; |
210 | 16 | #if (NGX_HAVE_INET6) |
211 | 16 | struct sockaddr_in6 *sin6; |
212 | 16 | ngx_http_in6_addr_t *addr6; |
213 | 16 | #endif |
214 | | |
215 | 16 | hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); |
216 | 16 | if (hc == NULL) { |
217 | 0 | ngx_http_close_connection(c); |
218 | 0 | return; |
219 | 0 | } |
220 | | |
221 | 16 | c->data = hc; |
222 | | |
223 | | /* find the server configuration for the address:port */ |
224 | | |
225 | 16 | port = c->listening->servers; |
226 | | |
227 | 16 | if (port->naddrs > 1) { |
228 | | |
229 | | /* |
230 | | * there are several addresses on this port and one of them |
231 | | * is an "*:port" wildcard so getsockname() in ngx_http_server_addr() |
232 | | * is required to determine a server address |
233 | | */ |
234 | |
|
235 | 0 | if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { |
236 | 0 | ngx_http_close_connection(c); |
237 | 0 | return; |
238 | 0 | } |
239 | | |
240 | 0 | switch (c->local_sockaddr->sa_family) { |
241 | | |
242 | 0 | #if (NGX_HAVE_INET6) |
243 | 0 | case AF_INET6: |
244 | 0 | sin6 = (struct sockaddr_in6 *) c->local_sockaddr; |
245 | |
|
246 | 0 | addr6 = port->addrs; |
247 | | |
248 | | /* the last address is "*" */ |
249 | |
|
250 | 0 | for (i = 0; i < port->naddrs - 1; i++) { |
251 | 0 | if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { |
252 | 0 | break; |
253 | 0 | } |
254 | 0 | } |
255 | |
|
256 | 0 | hc->addr_conf = &addr6[i].conf; |
257 | |
|
258 | 0 | break; |
259 | 0 | #endif |
260 | | |
261 | 0 | default: /* AF_INET */ |
262 | 0 | sin = (struct sockaddr_in *) c->local_sockaddr; |
263 | |
|
264 | 0 | addr = port->addrs; |
265 | | |
266 | | /* the last address is "*" */ |
267 | |
|
268 | 0 | for (i = 0; i < port->naddrs - 1; i++) { |
269 | 0 | if (addr[i].addr == sin->sin_addr.s_addr) { |
270 | 0 | break; |
271 | 0 | } |
272 | 0 | } |
273 | |
|
274 | 0 | hc->addr_conf = &addr[i].conf; |
275 | |
|
276 | 0 | break; |
277 | 0 | } |
278 | |
|
279 | 16 | } else { |
280 | | |
281 | 16 | switch (c->local_sockaddr->sa_family) { |
282 | | |
283 | 0 | #if (NGX_HAVE_INET6) |
284 | 0 | case AF_INET6: |
285 | 0 | addr6 = port->addrs; |
286 | 0 | hc->addr_conf = &addr6[0].conf; |
287 | 0 | break; |
288 | 0 | #endif |
289 | | |
290 | 16 | default: /* AF_INET */ |
291 | 16 | addr = port->addrs; |
292 | 16 | hc->addr_conf = &addr[0].conf; |
293 | 16 | break; |
294 | 16 | } |
295 | 16 | } |
296 | | |
297 | | /* the default server configuration for the address:port */ |
298 | 16 | hc->conf_ctx = hc->addr_conf->default_server->ctx; |
299 | | |
300 | 16 | ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); |
301 | 16 | if (ctx == NULL) { |
302 | 0 | ngx_http_close_connection(c); |
303 | 0 | return; |
304 | 0 | } |
305 | | |
306 | 16 | ctx->connection = c; |
307 | 16 | ctx->request = NULL; |
308 | 16 | ctx->current_request = NULL; |
309 | | |
310 | 16 | c->log->connection = c->number; |
311 | 16 | c->log->handler = ngx_http_log_error; |
312 | 16 | c->log->data = ctx; |
313 | 16 | c->log->action = "waiting for request"; |
314 | | |
315 | 16 | c->log_error = NGX_ERROR_INFO; |
316 | | |
317 | 16 | rev = c->read; |
318 | 16 | rev->handler = ngx_http_wait_request_handler; |
319 | 16 | c->write->handler = ngx_http_empty_handler; |
320 | | |
321 | 16 | #if (NGX_HTTP_V2) |
322 | 16 | if (hc->addr_conf->http2) { |
323 | 0 | rev->handler = ngx_http_v2_init; |
324 | 0 | } |
325 | 16 | #endif |
326 | | |
327 | | #if (NGX_HTTP_V3) |
328 | | if (hc->addr_conf->quic) { |
329 | | ngx_http_v3_init_stream(c); |
330 | | return; |
331 | | } |
332 | | #endif |
333 | | |
334 | | #if (NGX_HTTP_SSL) |
335 | | { |
336 | | ngx_http_ssl_srv_conf_t *sscf; |
337 | | |
338 | | sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); |
339 | | |
340 | | if (sscf->enable || hc->addr_conf->ssl) { |
341 | | hc->ssl = 1; |
342 | | c->log->action = "SSL handshaking"; |
343 | | rev->handler = ngx_http_ssl_handshake; |
344 | | } |
345 | | } |
346 | | #endif |
347 | | |
348 | 16 | if (hc->addr_conf->proxy_protocol) { |
349 | 0 | hc->proxy_protocol = 1; |
350 | 0 | c->log->action = "reading PROXY protocol"; |
351 | 0 | } |
352 | | |
353 | 16 | if (rev->ready) { |
354 | | /* the deferred accept(), iocp */ |
355 | | |
356 | 16 | if (ngx_use_accept_mutex) { |
357 | 0 | ngx_post_event(rev, &ngx_posted_events); |
358 | 0 | return; |
359 | 0 | } |
360 | | |
361 | 16 | rev->handler(rev); |
362 | 16 | return; |
363 | 16 | } |
364 | | |
365 | 0 | cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); |
366 | |
|
367 | 0 | ngx_add_timer(rev, cscf->client_header_timeout); |
368 | 0 | ngx_reusable_connection(c, 1); |
369 | |
|
370 | 0 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
371 | 0 | ngx_http_close_connection(c); |
372 | 0 | return; |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | | |
377 | | static void |
378 | | ngx_http_wait_request_handler(ngx_event_t *rev) |
379 | 16 | { |
380 | 16 | u_char *p; |
381 | 16 | size_t size; |
382 | 16 | ssize_t n; |
383 | 16 | ngx_buf_t *b; |
384 | 16 | ngx_connection_t *c; |
385 | 16 | ngx_http_connection_t *hc; |
386 | 16 | ngx_http_core_srv_conf_t *cscf; |
387 | | |
388 | 16 | c = rev->data; |
389 | | |
390 | 16 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http wait request handler"); |
391 | | |
392 | 16 | if (rev->timedout) { |
393 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); |
394 | 0 | ngx_http_close_connection(c); |
395 | 0 | return; |
396 | 0 | } |
397 | | |
398 | 16 | if (c->close) { |
399 | 0 | ngx_http_close_connection(c); |
400 | 0 | return; |
401 | 0 | } |
402 | | |
403 | 16 | hc = c->data; |
404 | 16 | cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); |
405 | | |
406 | 16 | size = cscf->client_header_buffer_size; |
407 | | |
408 | 16 | b = c->buffer; |
409 | | |
410 | 16 | if (b == NULL) { |
411 | 16 | b = ngx_create_temp_buf(c->pool, size); |
412 | 16 | if (b == NULL) { |
413 | 0 | ngx_http_close_connection(c); |
414 | 0 | return; |
415 | 0 | } |
416 | | |
417 | 16 | c->buffer = b; |
418 | | |
419 | 16 | } else if (b->start == NULL) { |
420 | |
|
421 | 0 | b->start = ngx_palloc(c->pool, size); |
422 | 0 | if (b->start == NULL) { |
423 | 0 | ngx_http_close_connection(c); |
424 | 0 | return; |
425 | 0 | } |
426 | | |
427 | 0 | b->pos = b->start; |
428 | 0 | b->last = b->start; |
429 | 0 | b->end = b->last + size; |
430 | 0 | } |
431 | | |
432 | 16 | n = c->recv(c, b->last, size); |
433 | | |
434 | 16 | if (n == NGX_AGAIN) { |
435 | |
|
436 | 0 | if (!rev->timer_set) { |
437 | 0 | ngx_add_timer(rev, cscf->client_header_timeout); |
438 | 0 | ngx_reusable_connection(c, 1); |
439 | 0 | } |
440 | |
|
441 | 0 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
442 | 0 | ngx_http_close_connection(c); |
443 | 0 | return; |
444 | 0 | } |
445 | | |
446 | | /* |
447 | | * We are trying to not hold c->buffer's memory for an idle connection. |
448 | | */ |
449 | | |
450 | 0 | if (ngx_pfree(c->pool, b->start) == NGX_OK) { |
451 | 0 | b->start = NULL; |
452 | 0 | } |
453 | |
|
454 | 0 | return; |
455 | 0 | } |
456 | | |
457 | 16 | if (n == NGX_ERROR) { |
458 | 0 | ngx_http_close_connection(c); |
459 | 0 | return; |
460 | 0 | } |
461 | | |
462 | 16 | if (n == 0) { |
463 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
464 | 0 | "client closed connection"); |
465 | 0 | ngx_http_close_connection(c); |
466 | 0 | return; |
467 | 0 | } |
468 | | |
469 | 16 | b->last += n; |
470 | | |
471 | 16 | if (hc->proxy_protocol) { |
472 | 0 | hc->proxy_protocol = 0; |
473 | |
|
474 | 0 | p = ngx_proxy_protocol_read(c, b->pos, b->last); |
475 | |
|
476 | 0 | if (p == NULL) { |
477 | 0 | ngx_http_close_connection(c); |
478 | 0 | return; |
479 | 0 | } |
480 | | |
481 | 0 | b->pos = p; |
482 | |
|
483 | 0 | if (b->pos == b->last) { |
484 | 0 | c->log->action = "waiting for request"; |
485 | 0 | b->pos = b->start; |
486 | 0 | b->last = b->start; |
487 | 0 | ngx_post_event(rev, &ngx_posted_events); |
488 | 0 | return; |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | 16 | c->log->action = "reading client request line"; |
493 | | |
494 | 16 | ngx_reusable_connection(c, 0); |
495 | | |
496 | 16 | c->data = ngx_http_create_request(c); |
497 | 16 | if (c->data == NULL) { |
498 | 0 | ngx_http_close_connection(c); |
499 | 0 | return; |
500 | 0 | } |
501 | | |
502 | 16 | rev->handler = ngx_http_process_request_line; |
503 | 16 | ngx_http_process_request_line(rev); |
504 | 16 | } |
505 | | |
506 | | |
507 | | ngx_http_request_t * |
508 | | ngx_http_create_request(ngx_connection_t *c) |
509 | 16 | { |
510 | 16 | ngx_http_request_t *r; |
511 | 16 | ngx_http_log_ctx_t *ctx; |
512 | 16 | ngx_http_core_loc_conf_t *clcf; |
513 | | |
514 | 16 | r = ngx_http_alloc_request(c); |
515 | 16 | if (r == NULL) { |
516 | 0 | return NULL; |
517 | 0 | } |
518 | | |
519 | 16 | c->requests++; |
520 | | |
521 | 16 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
522 | | |
523 | 16 | ngx_set_connection_log(c, clcf->error_log); |
524 | | |
525 | 16 | ctx = c->log->data; |
526 | 16 | ctx->request = r; |
527 | 16 | ctx->current_request = r; |
528 | | |
529 | | #if (NGX_STAT_STUB) |
530 | | (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); |
531 | | r->stat_reading = 1; |
532 | | (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); |
533 | | #endif |
534 | | |
535 | 16 | return r; |
536 | 16 | } |
537 | | |
538 | | |
539 | | static ngx_http_request_t * |
540 | | ngx_http_alloc_request(ngx_connection_t *c) |
541 | 16 | { |
542 | 16 | ngx_pool_t *pool; |
543 | 16 | ngx_time_t *tp; |
544 | 16 | ngx_http_request_t *r; |
545 | 16 | ngx_http_connection_t *hc; |
546 | 16 | ngx_http_core_srv_conf_t *cscf; |
547 | 16 | ngx_http_core_main_conf_t *cmcf; |
548 | | |
549 | 16 | hc = c->data; |
550 | | |
551 | 16 | cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); |
552 | | |
553 | 16 | pool = ngx_create_pool(cscf->request_pool_size, c->log); |
554 | 16 | if (pool == NULL) { |
555 | 0 | return NULL; |
556 | 0 | } |
557 | | |
558 | 16 | r = ngx_pcalloc(pool, sizeof(ngx_http_request_t)); |
559 | 16 | if (r == NULL) { |
560 | 0 | ngx_destroy_pool(pool); |
561 | 0 | return NULL; |
562 | 0 | } |
563 | | |
564 | 16 | r->pool = pool; |
565 | | |
566 | 16 | r->http_connection = hc; |
567 | 16 | r->signature = NGX_HTTP_MODULE; |
568 | 16 | r->connection = c; |
569 | | |
570 | 16 | r->main_conf = hc->conf_ctx->main_conf; |
571 | 16 | r->srv_conf = hc->conf_ctx->srv_conf; |
572 | 16 | r->loc_conf = hc->conf_ctx->loc_conf; |
573 | | |
574 | 16 | r->read_event_handler = ngx_http_block_reading; |
575 | | |
576 | 16 | r->header_in = hc->busy ? hc->busy->buf : c->buffer; |
577 | | |
578 | 16 | if (ngx_list_init(&r->headers_out.headers, r->pool, 20, |
579 | 16 | sizeof(ngx_table_elt_t)) |
580 | 16 | != NGX_OK) |
581 | 0 | { |
582 | 0 | ngx_destroy_pool(r->pool); |
583 | 0 | return NULL; |
584 | 0 | } |
585 | | |
586 | 16 | if (ngx_list_init(&r->headers_out.trailers, r->pool, 4, |
587 | 16 | sizeof(ngx_table_elt_t)) |
588 | 16 | != NGX_OK) |
589 | 0 | { |
590 | 0 | ngx_destroy_pool(r->pool); |
591 | 0 | return NULL; |
592 | 0 | } |
593 | | |
594 | 16 | r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); |
595 | 16 | if (r->ctx == NULL) { |
596 | 0 | ngx_destroy_pool(r->pool); |
597 | 0 | return NULL; |
598 | 0 | } |
599 | | |
600 | 16 | cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); |
601 | | |
602 | 16 | r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts |
603 | 16 | * sizeof(ngx_http_variable_value_t)); |
604 | 16 | if (r->variables == NULL) { |
605 | 0 | ngx_destroy_pool(r->pool); |
606 | 0 | return NULL; |
607 | 0 | } |
608 | | |
609 | | #if (NGX_HTTP_SSL) |
610 | | if (c->ssl && !c->ssl->sendfile) { |
611 | | r->main_filter_need_in_memory = 1; |
612 | | } |
613 | | #endif |
614 | | |
615 | 16 | r->main = r; |
616 | 16 | r->count = 1; |
617 | | |
618 | 16 | tp = ngx_timeofday(); |
619 | 16 | r->start_sec = tp->sec; |
620 | 16 | r->start_msec = tp->msec; |
621 | | |
622 | 16 | r->method = NGX_HTTP_UNKNOWN; |
623 | 16 | r->http_version = NGX_HTTP_VERSION_10; |
624 | | |
625 | 16 | r->headers_in.content_length_n = -1; |
626 | 16 | r->headers_in.keep_alive_n = -1; |
627 | 16 | r->headers_out.content_length_n = -1; |
628 | 16 | r->headers_out.last_modified_time = -1; |
629 | | |
630 | 16 | r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; |
631 | 16 | r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1; |
632 | | |
633 | 16 | r->http_state = NGX_HTTP_READING_REQUEST_STATE; |
634 | | |
635 | 16 | r->log_handler = ngx_http_log_error_handler; |
636 | | |
637 | 16 | return r; |
638 | 16 | } |
639 | | |
640 | | |
641 | | #if (NGX_HTTP_SSL) |
642 | | |
643 | | static void |
644 | | ngx_http_ssl_handshake(ngx_event_t *rev) |
645 | | { |
646 | | u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1]; |
647 | | size_t size; |
648 | | ssize_t n; |
649 | | ngx_err_t err; |
650 | | ngx_int_t rc; |
651 | | ngx_connection_t *c; |
652 | | ngx_http_connection_t *hc; |
653 | | ngx_http_ssl_srv_conf_t *sscf; |
654 | | ngx_http_core_loc_conf_t *clcf; |
655 | | ngx_http_core_srv_conf_t *cscf; |
656 | | |
657 | | c = rev->data; |
658 | | hc = c->data; |
659 | | |
660 | | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, |
661 | | "http check ssl handshake"); |
662 | | |
663 | | if (rev->timedout) { |
664 | | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); |
665 | | ngx_http_close_connection(c); |
666 | | return; |
667 | | } |
668 | | |
669 | | if (c->close) { |
670 | | ngx_http_close_connection(c); |
671 | | return; |
672 | | } |
673 | | |
674 | | size = hc->proxy_protocol ? sizeof(buf) : 1; |
675 | | |
676 | | n = recv(c->fd, (char *) buf, size, MSG_PEEK); |
677 | | |
678 | | err = ngx_socket_errno; |
679 | | |
680 | | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %z", n); |
681 | | |
682 | | if (n == -1) { |
683 | | if (err == NGX_EAGAIN) { |
684 | | rev->ready = 0; |
685 | | |
686 | | if (!rev->timer_set) { |
687 | | cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, |
688 | | ngx_http_core_module); |
689 | | ngx_add_timer(rev, cscf->client_header_timeout); |
690 | | ngx_reusable_connection(c, 1); |
691 | | } |
692 | | |
693 | | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
694 | | ngx_http_close_connection(c); |
695 | | } |
696 | | |
697 | | return; |
698 | | } |
699 | | |
700 | | ngx_connection_error(c, err, "recv() failed"); |
701 | | ngx_http_close_connection(c); |
702 | | |
703 | | return; |
704 | | } |
705 | | |
706 | | if (hc->proxy_protocol) { |
707 | | hc->proxy_protocol = 0; |
708 | | |
709 | | p = ngx_proxy_protocol_read(c, buf, buf + n); |
710 | | |
711 | | if (p == NULL) { |
712 | | ngx_http_close_connection(c); |
713 | | return; |
714 | | } |
715 | | |
716 | | size = p - buf; |
717 | | |
718 | | if (c->recv(c, buf, size) != (ssize_t) size) { |
719 | | ngx_http_close_connection(c); |
720 | | return; |
721 | | } |
722 | | |
723 | | c->log->action = "SSL handshaking"; |
724 | | |
725 | | if (n == (ssize_t) size) { |
726 | | ngx_post_event(rev, &ngx_posted_events); |
727 | | return; |
728 | | } |
729 | | |
730 | | n = 1; |
731 | | buf[0] = *p; |
732 | | } |
733 | | |
734 | | if (n == 1) { |
735 | | if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) { |
736 | | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, |
737 | | "https ssl handshake: 0x%02Xd", buf[0]); |
738 | | |
739 | | clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, |
740 | | ngx_http_core_module); |
741 | | |
742 | | if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { |
743 | | ngx_http_close_connection(c); |
744 | | return; |
745 | | } |
746 | | |
747 | | sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, |
748 | | ngx_http_ssl_module); |
749 | | |
750 | | if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) |
751 | | != NGX_OK) |
752 | | { |
753 | | ngx_http_close_connection(c); |
754 | | return; |
755 | | } |
756 | | |
757 | | ngx_reusable_connection(c, 0); |
758 | | |
759 | | rc = ngx_ssl_handshake(c); |
760 | | |
761 | | if (rc == NGX_AGAIN) { |
762 | | |
763 | | if (!rev->timer_set) { |
764 | | cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, |
765 | | ngx_http_core_module); |
766 | | ngx_add_timer(rev, cscf->client_header_timeout); |
767 | | } |
768 | | |
769 | | c->ssl->handler = ngx_http_ssl_handshake_handler; |
770 | | return; |
771 | | } |
772 | | |
773 | | ngx_http_ssl_handshake_handler(c); |
774 | | |
775 | | return; |
776 | | } |
777 | | |
778 | | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "plain http"); |
779 | | |
780 | | c->log->action = "waiting for request"; |
781 | | |
782 | | rev->handler = ngx_http_wait_request_handler; |
783 | | ngx_http_wait_request_handler(rev); |
784 | | |
785 | | return; |
786 | | } |
787 | | |
788 | | ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); |
789 | | ngx_http_close_connection(c); |
790 | | } |
791 | | |
792 | | |
793 | | static void |
794 | | ngx_http_ssl_handshake_handler(ngx_connection_t *c) |
795 | | { |
796 | | if (c->ssl->handshaked) { |
797 | | |
798 | | /* |
799 | | * The majority of browsers do not send the "close notify" alert. |
800 | | * Among them are MSIE, old Mozilla, Netscape 4, Konqueror, |
801 | | * and Links. And what is more, MSIE ignores the server's alert. |
802 | | * |
803 | | * Opera and recent Mozilla send the alert. |
804 | | */ |
805 | | |
806 | | c->ssl->no_wait_shutdown = 1; |
807 | | |
808 | | #if (NGX_HTTP_V2 \ |
809 | | && defined TLSEXT_TYPE_application_layer_protocol_negotiation) |
810 | | { |
811 | | unsigned int len; |
812 | | const unsigned char *data; |
813 | | ngx_http_connection_t *hc; |
814 | | |
815 | | hc = c->data; |
816 | | |
817 | | if (hc->addr_conf->http2) { |
818 | | |
819 | | SSL_get0_alpn_selected(c->ssl->connection, &data, &len); |
820 | | |
821 | | if (len == 2 && data[0] == 'h' && data[1] == '2') { |
822 | | ngx_http_v2_init(c->read); |
823 | | return; |
824 | | } |
825 | | } |
826 | | } |
827 | | #endif |
828 | | |
829 | | c->log->action = "waiting for request"; |
830 | | |
831 | | c->read->handler = ngx_http_wait_request_handler; |
832 | | /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler; |
833 | | |
834 | | ngx_reusable_connection(c, 1); |
835 | | |
836 | | ngx_http_wait_request_handler(c->read); |
837 | | |
838 | | return; |
839 | | } |
840 | | |
841 | | if (c->read->timedout) { |
842 | | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); |
843 | | } |
844 | | |
845 | | ngx_http_close_connection(c); |
846 | | } |
847 | | |
848 | | |
849 | | #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
850 | | |
851 | | int |
852 | | ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) |
853 | | { |
854 | | ngx_int_t rc; |
855 | | ngx_str_t host; |
856 | | const char *servername; |
857 | | ngx_connection_t *c; |
858 | | ngx_http_connection_t *hc; |
859 | | ngx_http_ssl_srv_conf_t *sscf; |
860 | | ngx_http_core_loc_conf_t *clcf; |
861 | | ngx_http_core_srv_conf_t *cscf; |
862 | | |
863 | | c = ngx_ssl_get_connection(ssl_conn); |
864 | | |
865 | | if (c->ssl->handshaked) { |
866 | | *ad = SSL_AD_NO_RENEGOTIATION; |
867 | | return SSL_TLSEXT_ERR_ALERT_FATAL; |
868 | | } |
869 | | |
870 | | hc = c->data; |
871 | | |
872 | | servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); |
873 | | |
874 | | if (servername == NULL) { |
875 | | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
876 | | "SSL server name: null"); |
877 | | goto done; |
878 | | } |
879 | | |
880 | | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
881 | | "SSL server name: \"%s\"", servername); |
882 | | |
883 | | host.len = ngx_strlen(servername); |
884 | | |
885 | | if (host.len == 0) { |
886 | | goto done; |
887 | | } |
888 | | |
889 | | host.data = (u_char *) servername; |
890 | | |
891 | | rc = ngx_http_validate_host(&host, c->pool, 1); |
892 | | |
893 | | if (rc == NGX_ERROR) { |
894 | | goto error; |
895 | | } |
896 | | |
897 | | if (rc == NGX_DECLINED) { |
898 | | goto done; |
899 | | } |
900 | | |
901 | | rc = ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host, |
902 | | NULL, &cscf); |
903 | | |
904 | | if (rc == NGX_ERROR) { |
905 | | goto error; |
906 | | } |
907 | | |
908 | | if (rc == NGX_DECLINED) { |
909 | | goto done; |
910 | | } |
911 | | |
912 | | hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); |
913 | | if (hc->ssl_servername == NULL) { |
914 | | goto error; |
915 | | } |
916 | | |
917 | | *hc->ssl_servername = host; |
918 | | |
919 | | hc->conf_ctx = cscf->ctx; |
920 | | |
921 | | clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); |
922 | | |
923 | | ngx_set_connection_log(c, clcf->error_log); |
924 | | |
925 | | sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); |
926 | | |
927 | | c->ssl->buffer_size = sscf->buffer_size; |
928 | | |
929 | | if (sscf->ssl.ctx) { |
930 | | if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) { |
931 | | goto error; |
932 | | } |
933 | | |
934 | | /* |
935 | | * SSL_set_SSL_CTX() only changes certs as of 1.0.0d |
936 | | * adjust other things we care about |
937 | | */ |
938 | | |
939 | | SSL_set_verify(ssl_conn, SSL_CTX_get_verify_mode(sscf->ssl.ctx), |
940 | | SSL_CTX_get_verify_callback(sscf->ssl.ctx)); |
941 | | |
942 | | SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx)); |
943 | | |
944 | | #if OPENSSL_VERSION_NUMBER >= 0x009080dfL |
945 | | /* only in 0.9.8m+ */ |
946 | | SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) & |
947 | | ~SSL_CTX_get_options(sscf->ssl.ctx)); |
948 | | #endif |
949 | | |
950 | | SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx)); |
951 | | |
952 | | #ifdef SSL_OP_NO_RENEGOTIATION |
953 | | SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION); |
954 | | #endif |
955 | | |
956 | | #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT |
957 | | #if (NGX_HTTP_V3) |
958 | | if (c->listening->quic) { |
959 | | SSL_clear_options(ssl_conn, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); |
960 | | } |
961 | | #endif |
962 | | #endif |
963 | | } |
964 | | |
965 | | done: |
966 | | |
967 | | sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); |
968 | | |
969 | | if (sscf->reject_handshake) { |
970 | | c->ssl->handshake_rejected = 1; |
971 | | *ad = SSL_AD_UNRECOGNIZED_NAME; |
972 | | return SSL_TLSEXT_ERR_ALERT_FATAL; |
973 | | } |
974 | | |
975 | | return SSL_TLSEXT_ERR_OK; |
976 | | |
977 | | error: |
978 | | |
979 | | *ad = SSL_AD_INTERNAL_ERROR; |
980 | | return SSL_TLSEXT_ERR_ALERT_FATAL; |
981 | | } |
982 | | |
983 | | #endif |
984 | | |
985 | | |
986 | | #ifdef SSL_R_CERT_CB_ERROR |
987 | | |
988 | | int |
989 | | ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) |
990 | | { |
991 | | ngx_str_t cert, key; |
992 | | ngx_uint_t i, nelts; |
993 | | ngx_connection_t *c; |
994 | | ngx_http_request_t *r; |
995 | | ngx_http_ssl_srv_conf_t *sscf; |
996 | | ngx_http_complex_value_t *certs, *keys; |
997 | | |
998 | | c = ngx_ssl_get_connection(ssl_conn); |
999 | | |
1000 | | if (c->ssl->handshaked) { |
1001 | | return 0; |
1002 | | } |
1003 | | |
1004 | | r = ngx_http_alloc_request(c); |
1005 | | if (r == NULL) { |
1006 | | return 0; |
1007 | | } |
1008 | | |
1009 | | r->logged = 1; |
1010 | | |
1011 | | sscf = arg; |
1012 | | |
1013 | | nelts = sscf->certificate_values->nelts; |
1014 | | certs = sscf->certificate_values->elts; |
1015 | | keys = sscf->certificate_key_values->elts; |
1016 | | |
1017 | | for (i = 0; i < nelts; i++) { |
1018 | | |
1019 | | if (ngx_http_complex_value(r, &certs[i], &cert) != NGX_OK) { |
1020 | | goto failed; |
1021 | | } |
1022 | | |
1023 | | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
1024 | | "ssl cert: \"%s\"", cert.data); |
1025 | | |
1026 | | if (ngx_http_complex_value(r, &keys[i], &key) != NGX_OK) { |
1027 | | goto failed; |
1028 | | } |
1029 | | |
1030 | | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
1031 | | "ssl key: \"%s\"", key.data); |
1032 | | |
1033 | | if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, |
1034 | | sscf->passwords) |
1035 | | != NGX_OK) |
1036 | | { |
1037 | | goto failed; |
1038 | | } |
1039 | | } |
1040 | | |
1041 | | ngx_http_free_request(r, 0); |
1042 | | c->log->action = "SSL handshaking"; |
1043 | | c->destroyed = 0; |
1044 | | return 1; |
1045 | | |
1046 | | failed: |
1047 | | |
1048 | | ngx_http_free_request(r, 0); |
1049 | | c->log->action = "SSL handshaking"; |
1050 | | c->destroyed = 0; |
1051 | | return 0; |
1052 | | } |
1053 | | |
1054 | | #endif |
1055 | | |
1056 | | #endif |
1057 | | |
1058 | | |
1059 | | static void |
1060 | | ngx_http_process_request_line(ngx_event_t *rev) |
1061 | 16 | { |
1062 | 16 | ssize_t n; |
1063 | 16 | ngx_int_t rc, rv; |
1064 | 16 | ngx_str_t host; |
1065 | 16 | ngx_connection_t *c; |
1066 | 16 | ngx_http_request_t *r; |
1067 | | |
1068 | 16 | c = rev->data; |
1069 | 16 | r = c->data; |
1070 | | |
1071 | 16 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, |
1072 | 16 | "http process request line"); |
1073 | | |
1074 | 16 | if (rev->timedout) { |
1075 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); |
1076 | 0 | c->timedout = 1; |
1077 | 0 | ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); |
1078 | 0 | return; |
1079 | 0 | } |
1080 | | |
1081 | 16 | rc = NGX_AGAIN; |
1082 | | |
1083 | 114 | for ( ;; ) { |
1084 | | |
1085 | 114 | if (rc == NGX_AGAIN) { |
1086 | 114 | n = ngx_http_read_request_header(r); |
1087 | | |
1088 | 114 | if (n == NGX_AGAIN || n == NGX_ERROR) { |
1089 | 3 | break; |
1090 | 3 | } |
1091 | 114 | } |
1092 | | |
1093 | 111 | rc = ngx_http_parse_request_line(r, r->header_in); |
1094 | | |
1095 | 111 | if (rc == NGX_OK) { |
1096 | | |
1097 | | /* the request line has been parsed successfully */ |
1098 | | |
1099 | 12 | r->request_line.len = r->request_end - r->request_start; |
1100 | 12 | r->request_line.data = r->request_start; |
1101 | 12 | r->request_length = r->header_in->pos - r->request_start; |
1102 | | |
1103 | 12 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
1104 | 12 | "http request line: \"%V\"", &r->request_line); |
1105 | | |
1106 | 12 | r->method_name.len = r->method_end - r->request_start + 1; |
1107 | 12 | r->method_name.data = r->request_line.data; |
1108 | | |
1109 | 12 | if (r->http_protocol.data) { |
1110 | 8 | r->http_protocol.len = r->request_end - r->http_protocol.data; |
1111 | 8 | } |
1112 | | |
1113 | 12 | if (ngx_http_process_request_uri(r) != NGX_OK) { |
1114 | 0 | break; |
1115 | 0 | } |
1116 | | |
1117 | 12 | if (r->schema_end) { |
1118 | 2 | r->schema.len = r->schema_end - r->schema_start; |
1119 | 2 | r->schema.data = r->schema_start; |
1120 | 2 | } |
1121 | | |
1122 | 12 | if (r->host_end) { |
1123 | | |
1124 | 2 | host.len = r->host_end - r->host_start; |
1125 | 2 | host.data = r->host_start; |
1126 | | |
1127 | 2 | rc = ngx_http_validate_host(&host, r->pool, 0); |
1128 | | |
1129 | 2 | if (rc == NGX_DECLINED) { |
1130 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1131 | 0 | "client sent invalid host in request line"); |
1132 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1133 | 0 | break; |
1134 | 0 | } |
1135 | | |
1136 | 2 | if (rc == NGX_ERROR) { |
1137 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1138 | 0 | break; |
1139 | 0 | } |
1140 | | |
1141 | 2 | if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { |
1142 | 0 | break; |
1143 | 0 | } |
1144 | | |
1145 | 2 | r->headers_in.server = host; |
1146 | 2 | } |
1147 | | |
1148 | 12 | if (r->http_version < NGX_HTTP_VERSION_10) { |
1149 | | |
1150 | 4 | if (r->headers_in.server.len == 0 |
1151 | 4 | && ngx_http_set_virtual_server(r, &r->headers_in.server) |
1152 | 4 | == NGX_ERROR) |
1153 | 0 | { |
1154 | 0 | break; |
1155 | 0 | } |
1156 | | |
1157 | 4 | ngx_http_process_request(r); |
1158 | 4 | break; |
1159 | 4 | } |
1160 | | |
1161 | | |
1162 | 8 | if (ngx_list_init(&r->headers_in.headers, r->pool, 20, |
1163 | 8 | sizeof(ngx_table_elt_t)) |
1164 | 8 | != NGX_OK) |
1165 | 0 | { |
1166 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1167 | 0 | break; |
1168 | 0 | } |
1169 | | |
1170 | 8 | c->log->action = "reading client request headers"; |
1171 | | |
1172 | 8 | rev->handler = ngx_http_process_request_headers; |
1173 | 8 | ngx_http_process_request_headers(rev); |
1174 | | |
1175 | 8 | break; |
1176 | 8 | } |
1177 | | |
1178 | 99 | if (rc != NGX_AGAIN) { |
1179 | | |
1180 | | /* there was error while a request line parsing */ |
1181 | | |
1182 | 1 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1183 | 1 | ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]); |
1184 | | |
1185 | 1 | if (rc == NGX_HTTP_PARSE_INVALID_VERSION) { |
1186 | 0 | ngx_http_finalize_request(r, NGX_HTTP_VERSION_NOT_SUPPORTED); |
1187 | |
|
1188 | 1 | } else { |
1189 | 1 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1190 | 1 | } |
1191 | | |
1192 | 1 | break; |
1193 | 1 | } |
1194 | | |
1195 | | /* NGX_AGAIN: a request line parsing is still incomplete */ |
1196 | | |
1197 | 98 | if (r->header_in->pos == r->header_in->end) { |
1198 | | |
1199 | 95 | rv = ngx_http_alloc_large_header_buffer(r, 1); |
1200 | | |
1201 | 95 | if (rv == NGX_ERROR) { |
1202 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1203 | 0 | break; |
1204 | 0 | } |
1205 | | |
1206 | 95 | if (rv == NGX_DECLINED) { |
1207 | 0 | r->request_line.len = r->header_in->end - r->request_start; |
1208 | 0 | r->request_line.data = r->request_start; |
1209 | |
|
1210 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1211 | 0 | "client sent too long URI"); |
1212 | 0 | ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); |
1213 | 0 | break; |
1214 | 0 | } |
1215 | 95 | } |
1216 | 98 | } |
1217 | | |
1218 | 16 | ngx_http_run_posted_requests(c); |
1219 | 16 | } |
1220 | | |
1221 | | |
1222 | | ngx_int_t |
1223 | | ngx_http_process_request_uri(ngx_http_request_t *r) |
1224 | 12 | { |
1225 | 12 | ngx_http_core_srv_conf_t *cscf; |
1226 | | |
1227 | 12 | if (r->args_start) { |
1228 | 0 | r->uri.len = r->args_start - 1 - r->uri_start; |
1229 | 12 | } else { |
1230 | 12 | r->uri.len = r->uri_end - r->uri_start; |
1231 | 12 | } |
1232 | | |
1233 | 12 | if (r->complex_uri || r->quoted_uri || r->empty_path_in_uri) { |
1234 | | |
1235 | 4 | if (r->empty_path_in_uri) { |
1236 | 0 | r->uri.len++; |
1237 | 0 | } |
1238 | | |
1239 | 4 | r->uri.data = ngx_pnalloc(r->pool, r->uri.len); |
1240 | 4 | if (r->uri.data == NULL) { |
1241 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1242 | 0 | return NGX_ERROR; |
1243 | 0 | } |
1244 | | |
1245 | 4 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
1246 | | |
1247 | 4 | if (ngx_http_parse_complex_uri(r, cscf->merge_slashes) != NGX_OK) { |
1248 | 0 | r->uri.len = 0; |
1249 | |
|
1250 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1251 | 0 | "client sent invalid request"); |
1252 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1253 | 0 | return NGX_ERROR; |
1254 | 0 | } |
1255 | | |
1256 | 8 | } else { |
1257 | 8 | r->uri.data = r->uri_start; |
1258 | 8 | } |
1259 | | |
1260 | 12 | r->unparsed_uri.len = r->uri_end - r->uri_start; |
1261 | 12 | r->unparsed_uri.data = r->uri_start; |
1262 | | |
1263 | 12 | r->valid_unparsed_uri = r->empty_path_in_uri ? 0 : 1; |
1264 | | |
1265 | 12 | if (r->uri_ext) { |
1266 | 0 | if (r->args_start) { |
1267 | 0 | r->exten.len = r->args_start - 1 - r->uri_ext; |
1268 | 0 | } else { |
1269 | 0 | r->exten.len = r->uri_end - r->uri_ext; |
1270 | 0 | } |
1271 | |
|
1272 | 0 | r->exten.data = r->uri_ext; |
1273 | 0 | } |
1274 | | |
1275 | 12 | if (r->args_start && r->uri_end > r->args_start) { |
1276 | 0 | r->args.len = r->uri_end - r->args_start; |
1277 | 0 | r->args.data = r->args_start; |
1278 | 0 | } |
1279 | | |
1280 | | #if (NGX_WIN32) |
1281 | | { |
1282 | | u_char *p, *last; |
1283 | | |
1284 | | p = r->uri.data; |
1285 | | last = r->uri.data + r->uri.len; |
1286 | | |
1287 | | while (p < last) { |
1288 | | |
1289 | | if (*p++ == ':') { |
1290 | | |
1291 | | /* |
1292 | | * this check covers "::$data", "::$index_allocation" and |
1293 | | * ":$i30:$index_allocation" |
1294 | | */ |
1295 | | |
1296 | | if (p < last && *p == '$') { |
1297 | | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1298 | | "client sent unsafe win32 URI"); |
1299 | | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1300 | | return NGX_ERROR; |
1301 | | } |
1302 | | } |
1303 | | } |
1304 | | |
1305 | | p = r->uri.data + r->uri.len - 1; |
1306 | | |
1307 | | while (p > r->uri.data) { |
1308 | | |
1309 | | if (*p == ' ') { |
1310 | | p--; |
1311 | | continue; |
1312 | | } |
1313 | | |
1314 | | if (*p == '.') { |
1315 | | p--; |
1316 | | continue; |
1317 | | } |
1318 | | |
1319 | | break; |
1320 | | } |
1321 | | |
1322 | | if (p != r->uri.data + r->uri.len - 1) { |
1323 | | r->uri.len = p + 1 - r->uri.data; |
1324 | | ngx_http_set_exten(r); |
1325 | | } |
1326 | | |
1327 | | } |
1328 | | #endif |
1329 | | |
1330 | 12 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1331 | 12 | "http uri: \"%V\"", &r->uri); |
1332 | | |
1333 | 12 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1334 | 12 | "http args: \"%V\"", &r->args); |
1335 | | |
1336 | 12 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1337 | 12 | "http exten: \"%V\"", &r->exten); |
1338 | | |
1339 | 12 | return NGX_OK; |
1340 | 12 | } |
1341 | | |
1342 | | |
1343 | | static void |
1344 | | ngx_http_process_request_headers(ngx_event_t *rev) |
1345 | 8 | { |
1346 | 8 | u_char *p; |
1347 | 8 | size_t len; |
1348 | 8 | ssize_t n; |
1349 | 8 | ngx_int_t rc, rv; |
1350 | 8 | ngx_table_elt_t *h; |
1351 | 8 | ngx_connection_t *c; |
1352 | 8 | ngx_http_header_t *hh; |
1353 | 8 | ngx_http_request_t *r; |
1354 | 8 | ngx_http_core_srv_conf_t *cscf; |
1355 | 8 | ngx_http_core_main_conf_t *cmcf; |
1356 | | |
1357 | 8 | c = rev->data; |
1358 | 8 | r = c->data; |
1359 | | |
1360 | 8 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, |
1361 | 8 | "http process request header line"); |
1362 | | |
1363 | 8 | if (rev->timedout) { |
1364 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); |
1365 | 0 | c->timedout = 1; |
1366 | 0 | ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); |
1367 | 0 | return; |
1368 | 0 | } |
1369 | | |
1370 | 8 | cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); |
1371 | | |
1372 | 8 | rc = NGX_AGAIN; |
1373 | | |
1374 | 21 | for ( ;; ) { |
1375 | | |
1376 | 21 | if (rc == NGX_AGAIN) { |
1377 | | |
1378 | 8 | if (r->header_in->pos == r->header_in->end) { |
1379 | |
|
1380 | 0 | rv = ngx_http_alloc_large_header_buffer(r, 0); |
1381 | |
|
1382 | 0 | if (rv == NGX_ERROR) { |
1383 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1384 | 0 | break; |
1385 | 0 | } |
1386 | | |
1387 | 0 | if (rv == NGX_DECLINED) { |
1388 | 0 | p = r->header_name_start; |
1389 | |
|
1390 | 0 | r->lingering_close = 1; |
1391 | |
|
1392 | 0 | if (p == NULL) { |
1393 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1394 | 0 | "client sent too large request"); |
1395 | 0 | ngx_http_finalize_request(r, |
1396 | 0 | NGX_HTTP_REQUEST_HEADER_TOO_LARGE); |
1397 | 0 | break; |
1398 | 0 | } |
1399 | | |
1400 | 0 | len = r->header_in->end - p; |
1401 | |
|
1402 | 0 | if (len > NGX_MAX_ERROR_STR - 300) { |
1403 | 0 | len = NGX_MAX_ERROR_STR - 300; |
1404 | 0 | } |
1405 | |
|
1406 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1407 | 0 | "client sent too long header line: \"%*s...\"", |
1408 | 0 | len, r->header_name_start); |
1409 | |
|
1410 | 0 | ngx_http_finalize_request(r, |
1411 | 0 | NGX_HTTP_REQUEST_HEADER_TOO_LARGE); |
1412 | 0 | break; |
1413 | 0 | } |
1414 | 0 | } |
1415 | | |
1416 | 8 | n = ngx_http_read_request_header(r); |
1417 | | |
1418 | 8 | if (n == NGX_AGAIN || n == NGX_ERROR) { |
1419 | 0 | break; |
1420 | 0 | } |
1421 | 8 | } |
1422 | | |
1423 | | /* the host header could change the server configuration context */ |
1424 | 21 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
1425 | | |
1426 | 21 | rc = ngx_http_parse_header_line(r, r->header_in, |
1427 | 21 | cscf->underscores_in_headers); |
1428 | | |
1429 | 21 | if (rc == NGX_OK) { |
1430 | | |
1431 | 13 | r->request_length += r->header_in->pos - r->header_name_start; |
1432 | | |
1433 | 13 | if (r->invalid_header && cscf->ignore_invalid_headers) { |
1434 | | |
1435 | | /* there was error while a header line parsing */ |
1436 | | |
1437 | 1 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1438 | 1 | "client sent invalid header line: \"%*s\"", |
1439 | 1 | r->header_end - r->header_name_start, |
1440 | 1 | r->header_name_start); |
1441 | 1 | continue; |
1442 | 1 | } |
1443 | | |
1444 | | /* a header line has been parsed successfully */ |
1445 | | |
1446 | 12 | h = ngx_list_push(&r->headers_in.headers); |
1447 | 12 | if (h == NULL) { |
1448 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1449 | 0 | break; |
1450 | 0 | } |
1451 | | |
1452 | 12 | h->hash = r->header_hash; |
1453 | | |
1454 | 12 | h->key.len = r->header_name_end - r->header_name_start; |
1455 | 12 | h->key.data = r->header_name_start; |
1456 | 12 | h->key.data[h->key.len] = '\0'; |
1457 | | |
1458 | 12 | h->value.len = r->header_end - r->header_start; |
1459 | 12 | h->value.data = r->header_start; |
1460 | 12 | h->value.data[h->value.len] = '\0'; |
1461 | | |
1462 | 12 | h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); |
1463 | 12 | if (h->lowcase_key == NULL) { |
1464 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1465 | 0 | break; |
1466 | 0 | } |
1467 | | |
1468 | 12 | if (h->key.len == r->lowcase_index) { |
1469 | 12 | ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); |
1470 | | |
1471 | 12 | } else { |
1472 | 0 | ngx_strlow(h->lowcase_key, h->key.data, h->key.len); |
1473 | 0 | } |
1474 | | |
1475 | 12 | hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, |
1476 | 12 | h->lowcase_key, h->key.len); |
1477 | | |
1478 | 12 | if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { |
1479 | 0 | break; |
1480 | 0 | } |
1481 | | |
1482 | 12 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1483 | 12 | "http header: \"%V: %V\"", |
1484 | 12 | &h->key, &h->value); |
1485 | | |
1486 | 12 | continue; |
1487 | 12 | } |
1488 | | |
1489 | 8 | if (rc == NGX_HTTP_PARSE_HEADER_DONE) { |
1490 | | |
1491 | | /* a whole header has been parsed successfully */ |
1492 | | |
1493 | 8 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1494 | 8 | "http header done"); |
1495 | | |
1496 | 8 | r->request_length += r->header_in->pos - r->header_name_start; |
1497 | | |
1498 | 8 | r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; |
1499 | | |
1500 | 8 | rc = ngx_http_process_request_header(r); |
1501 | | |
1502 | 8 | if (rc != NGX_OK) { |
1503 | 1 | break; |
1504 | 1 | } |
1505 | | |
1506 | 7 | ngx_http_process_request(r); |
1507 | | |
1508 | 7 | break; |
1509 | 8 | } |
1510 | | |
1511 | 0 | if (rc == NGX_AGAIN) { |
1512 | | |
1513 | | /* a header line parsing is still not complete */ |
1514 | |
|
1515 | 0 | continue; |
1516 | 0 | } |
1517 | | |
1518 | | /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ |
1519 | | |
1520 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1521 | 0 | "client sent invalid header line: \"%*s\\x%02xd...\"", |
1522 | 0 | r->header_end - r->header_name_start, |
1523 | 0 | r->header_name_start, *r->header_end); |
1524 | |
|
1525 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1526 | 0 | break; |
1527 | 0 | } |
1528 | | |
1529 | 8 | ngx_http_run_posted_requests(c); |
1530 | 8 | } |
1531 | | |
1532 | | |
1533 | | static ssize_t |
1534 | | ngx_http_read_request_header(ngx_http_request_t *r) |
1535 | 122 | { |
1536 | 122 | ssize_t n; |
1537 | 122 | ngx_event_t *rev; |
1538 | 122 | ngx_connection_t *c; |
1539 | 122 | ngx_http_core_srv_conf_t *cscf; |
1540 | | |
1541 | 122 | c = r->connection; |
1542 | 122 | rev = c->read; |
1543 | | |
1544 | 122 | n = r->header_in->last - r->header_in->pos; |
1545 | | |
1546 | 122 | if (n > 0) { |
1547 | 24 | return n; |
1548 | 24 | } |
1549 | | |
1550 | 98 | if (rev->ready) { |
1551 | 98 | n = c->recv(c, r->header_in->last, |
1552 | 98 | r->header_in->end - r->header_in->last); |
1553 | 98 | } else { |
1554 | 0 | n = NGX_AGAIN; |
1555 | 0 | } |
1556 | | |
1557 | 98 | if (n == NGX_AGAIN) { |
1558 | 0 | if (!rev->timer_set) { |
1559 | 0 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
1560 | 0 | ngx_add_timer(rev, cscf->client_header_timeout); |
1561 | 0 | } |
1562 | |
|
1563 | 0 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
1564 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1565 | 0 | return NGX_ERROR; |
1566 | 0 | } |
1567 | | |
1568 | 0 | return NGX_AGAIN; |
1569 | 0 | } |
1570 | | |
1571 | 98 | if (n == 0) { |
1572 | 3 | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1573 | 3 | "client prematurely closed connection"); |
1574 | 3 | } |
1575 | | |
1576 | 98 | if (n == 0 || n == NGX_ERROR) { |
1577 | 3 | c->error = 1; |
1578 | 3 | c->log->action = "reading client request headers"; |
1579 | | |
1580 | 3 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1581 | 3 | return NGX_ERROR; |
1582 | 3 | } |
1583 | | |
1584 | 95 | r->header_in->last += n; |
1585 | | |
1586 | 95 | return n; |
1587 | 98 | } |
1588 | | |
1589 | | |
1590 | | static ngx_int_t |
1591 | | ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, |
1592 | | ngx_uint_t request_line) |
1593 | 95 | { |
1594 | 95 | u_char *old, *new; |
1595 | 95 | ngx_buf_t *b; |
1596 | 95 | ngx_chain_t *cl; |
1597 | 95 | ngx_http_connection_t *hc; |
1598 | 95 | ngx_http_core_srv_conf_t *cscf; |
1599 | | |
1600 | 95 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1601 | 95 | "http alloc large header buffer"); |
1602 | | |
1603 | 95 | if (request_line && r->state == 0) { |
1604 | | |
1605 | | /* the client fills up the buffer with "\r\n" */ |
1606 | | |
1607 | 93 | r->header_in->pos = r->header_in->start; |
1608 | 93 | r->header_in->last = r->header_in->start; |
1609 | | |
1610 | 93 | return NGX_OK; |
1611 | 93 | } |
1612 | | |
1613 | 2 | old = request_line ? r->request_start : r->header_name_start; |
1614 | | |
1615 | 2 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
1616 | | |
1617 | 2 | if (r->state != 0 |
1618 | 2 | && (size_t) (r->header_in->pos - old) |
1619 | 2 | >= cscf->large_client_header_buffers.size) |
1620 | 0 | { |
1621 | 0 | return NGX_DECLINED; |
1622 | 0 | } |
1623 | | |
1624 | 2 | hc = r->http_connection; |
1625 | | |
1626 | 2 | if (hc->free) { |
1627 | 0 | cl = hc->free; |
1628 | 0 | hc->free = cl->next; |
1629 | |
|
1630 | 0 | b = cl->buf; |
1631 | |
|
1632 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1633 | 0 | "http large header free: %p %uz", |
1634 | 0 | b->pos, b->end - b->last); |
1635 | |
|
1636 | 2 | } else if (hc->nbusy < cscf->large_client_header_buffers.num) { |
1637 | | |
1638 | 2 | b = ngx_create_temp_buf(r->connection->pool, |
1639 | 2 | cscf->large_client_header_buffers.size); |
1640 | 2 | if (b == NULL) { |
1641 | 0 | return NGX_ERROR; |
1642 | 0 | } |
1643 | | |
1644 | 2 | cl = ngx_alloc_chain_link(r->connection->pool); |
1645 | 2 | if (cl == NULL) { |
1646 | 0 | return NGX_ERROR; |
1647 | 0 | } |
1648 | | |
1649 | 2 | cl->buf = b; |
1650 | | |
1651 | 2 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1652 | 2 | "http large header alloc: %p %uz", |
1653 | 2 | b->pos, b->end - b->last); |
1654 | | |
1655 | 2 | } else { |
1656 | 0 | return NGX_DECLINED; |
1657 | 0 | } |
1658 | | |
1659 | 2 | cl->next = hc->busy; |
1660 | 2 | hc->busy = cl; |
1661 | 2 | hc->nbusy++; |
1662 | | |
1663 | 2 | if (r->state == 0) { |
1664 | | /* |
1665 | | * r->state == 0 means that a header line was parsed successfully |
1666 | | * and we do not need to copy incomplete header line and |
1667 | | * to relocate the parser header pointers |
1668 | | */ |
1669 | |
|
1670 | 0 | r->header_in = b; |
1671 | |
|
1672 | 0 | return NGX_OK; |
1673 | 0 | } |
1674 | | |
1675 | 2 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1676 | 2 | "http large header copy: %uz", r->header_in->pos - old); |
1677 | | |
1678 | 2 | if (r->header_in->pos - old > b->end - b->start) { |
1679 | 0 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
1680 | 0 | "too large header to copy"); |
1681 | 0 | return NGX_ERROR; |
1682 | 0 | } |
1683 | | |
1684 | 2 | new = b->start; |
1685 | | |
1686 | 2 | ngx_memcpy(new, old, r->header_in->pos - old); |
1687 | | |
1688 | 2 | b->pos = new + (r->header_in->pos - old); |
1689 | 2 | b->last = new + (r->header_in->pos - old); |
1690 | | |
1691 | 2 | if (request_line) { |
1692 | 2 | r->request_start = new; |
1693 | | |
1694 | 2 | if (r->request_end) { |
1695 | 0 | r->request_end = new + (r->request_end - old); |
1696 | 0 | } |
1697 | | |
1698 | 2 | r->method_end = new + (r->method_end - old); |
1699 | | |
1700 | 2 | r->uri_start = new + (r->uri_start - old); |
1701 | 2 | r->uri_end = new + (r->uri_end - old); |
1702 | | |
1703 | 2 | if (r->schema_start) { |
1704 | 0 | r->schema_start = new + (r->schema_start - old); |
1705 | 0 | r->schema_end = new + (r->schema_end - old); |
1706 | 0 | } |
1707 | | |
1708 | 2 | if (r->host_start) { |
1709 | 0 | r->host_start = new + (r->host_start - old); |
1710 | 0 | if (r->host_end) { |
1711 | 0 | r->host_end = new + (r->host_end - old); |
1712 | 0 | } |
1713 | 0 | } |
1714 | | |
1715 | 2 | if (r->port_start) { |
1716 | 0 | r->port_start = new + (r->port_start - old); |
1717 | 0 | r->port_end = new + (r->port_end - old); |
1718 | 0 | } |
1719 | | |
1720 | 2 | if (r->uri_ext) { |
1721 | 0 | r->uri_ext = new + (r->uri_ext - old); |
1722 | 0 | } |
1723 | | |
1724 | 2 | if (r->args_start) { |
1725 | 0 | r->args_start = new + (r->args_start - old); |
1726 | 0 | } |
1727 | | |
1728 | 2 | if (r->http_protocol.data) { |
1729 | 0 | r->http_protocol.data = new + (r->http_protocol.data - old); |
1730 | 0 | } |
1731 | | |
1732 | 2 | } else { |
1733 | 0 | r->header_name_start = new; |
1734 | 0 | r->header_name_end = new + (r->header_name_end - old); |
1735 | 0 | r->header_start = new + (r->header_start - old); |
1736 | 0 | r->header_end = new + (r->header_end - old); |
1737 | 0 | } |
1738 | | |
1739 | 2 | r->header_in = b; |
1740 | | |
1741 | 2 | return NGX_OK; |
1742 | 2 | } |
1743 | | |
1744 | | |
1745 | | static ngx_int_t |
1746 | | ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, |
1747 | | ngx_uint_t offset) |
1748 | 0 | { |
1749 | 0 | ngx_table_elt_t **ph; |
1750 | |
|
1751 | 0 | ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); |
1752 | |
|
1753 | 0 | while (*ph) { ph = &(*ph)->next; } |
1754 | |
|
1755 | 0 | *ph = h; |
1756 | 0 | h->next = NULL; |
1757 | |
|
1758 | 0 | return NGX_OK; |
1759 | 0 | } |
1760 | | |
1761 | | |
1762 | | static ngx_int_t |
1763 | | ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, |
1764 | | ngx_uint_t offset) |
1765 | 8 | { |
1766 | 8 | ngx_table_elt_t **ph; |
1767 | | |
1768 | 8 | ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); |
1769 | | |
1770 | 8 | if (*ph == NULL) { |
1771 | 8 | *ph = h; |
1772 | 8 | h->next = NULL; |
1773 | 8 | return NGX_OK; |
1774 | 8 | } |
1775 | | |
1776 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1777 | 0 | "client sent duplicate header line: \"%V: %V\", " |
1778 | 0 | "previous value: \"%V: %V\"", |
1779 | 0 | &h->key, &h->value, &(*ph)->key, &(*ph)->value); |
1780 | |
|
1781 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1782 | |
|
1783 | 0 | return NGX_ERROR; |
1784 | 8 | } |
1785 | | |
1786 | | |
1787 | | static ngx_int_t |
1788 | | ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, |
1789 | | ngx_uint_t offset) |
1790 | 3 | { |
1791 | 3 | ngx_int_t rc; |
1792 | 3 | ngx_str_t host; |
1793 | | |
1794 | 3 | if (r->headers_in.host) { |
1795 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1796 | 0 | "client sent duplicate host header: \"%V: %V\", " |
1797 | 0 | "previous value: \"%V: %V\"", |
1798 | 0 | &h->key, &h->value, &r->headers_in.host->key, |
1799 | 0 | &r->headers_in.host->value); |
1800 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1801 | 0 | return NGX_ERROR; |
1802 | 0 | } |
1803 | | |
1804 | 3 | r->headers_in.host = h; |
1805 | 3 | h->next = NULL; |
1806 | | |
1807 | 3 | host = h->value; |
1808 | | |
1809 | 3 | rc = ngx_http_validate_host(&host, r->pool, 0); |
1810 | | |
1811 | 3 | if (rc == NGX_DECLINED) { |
1812 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1813 | 0 | "client sent invalid host header"); |
1814 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1815 | 0 | return NGX_ERROR; |
1816 | 0 | } |
1817 | | |
1818 | 3 | if (rc == NGX_ERROR) { |
1819 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1820 | 0 | return NGX_ERROR; |
1821 | 0 | } |
1822 | | |
1823 | 3 | if (r->headers_in.server.len) { |
1824 | 2 | return NGX_OK; |
1825 | 2 | } |
1826 | | |
1827 | 1 | if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { |
1828 | 0 | return NGX_ERROR; |
1829 | 0 | } |
1830 | | |
1831 | 1 | r->headers_in.server = host; |
1832 | | |
1833 | 1 | return NGX_OK; |
1834 | 1 | } |
1835 | | |
1836 | | |
1837 | | static ngx_int_t |
1838 | | ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, |
1839 | | ngx_uint_t offset) |
1840 | 0 | { |
1841 | 0 | if (ngx_http_process_header_line(r, h, offset) != NGX_OK) { |
1842 | 0 | return NGX_ERROR; |
1843 | 0 | } |
1844 | | |
1845 | 0 | if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { |
1846 | 0 | r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; |
1847 | |
|
1848 | 0 | } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) { |
1849 | 0 | r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; |
1850 | 0 | } |
1851 | |
|
1852 | 0 | return NGX_OK; |
1853 | 0 | } |
1854 | | |
1855 | | |
1856 | | static ngx_int_t |
1857 | | ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, |
1858 | | ngx_uint_t offset) |
1859 | 0 | { |
1860 | 0 | u_char *user_agent, *msie; |
1861 | |
|
1862 | 0 | if (ngx_http_process_header_line(r, h, offset) != NGX_OK) { |
1863 | 0 | return NGX_ERROR; |
1864 | 0 | } |
1865 | | |
1866 | | /* check some widespread browsers while the header is in CPU cache */ |
1867 | | |
1868 | 0 | user_agent = h->value.data; |
1869 | |
|
1870 | 0 | msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1); |
1871 | |
|
1872 | 0 | if (msie && msie + 7 < user_agent + h->value.len) { |
1873 | |
|
1874 | 0 | r->headers_in.msie = 1; |
1875 | |
|
1876 | 0 | if (msie[6] == '.') { |
1877 | |
|
1878 | 0 | switch (msie[5]) { |
1879 | 0 | case '4': |
1880 | 0 | case '5': |
1881 | 0 | r->headers_in.msie6 = 1; |
1882 | 0 | break; |
1883 | 0 | case '6': |
1884 | 0 | if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { |
1885 | 0 | r->headers_in.msie6 = 1; |
1886 | 0 | } |
1887 | 0 | break; |
1888 | 0 | } |
1889 | 0 | } |
1890 | |
|
1891 | | #if 0 |
1892 | | /* MSIE ignores the SSL "close notify" alert */ |
1893 | | if (c->ssl) { |
1894 | | c->ssl->no_send_shutdown = 1; |
1895 | | } |
1896 | | #endif |
1897 | 0 | } |
1898 | | |
1899 | 0 | if (ngx_strstrn(user_agent, "Opera", 5 - 1)) { |
1900 | 0 | r->headers_in.opera = 1; |
1901 | 0 | r->headers_in.msie = 0; |
1902 | 0 | r->headers_in.msie6 = 0; |
1903 | 0 | } |
1904 | |
|
1905 | 0 | if (!r->headers_in.msie && !r->headers_in.opera) { |
1906 | |
|
1907 | 0 | if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { |
1908 | 0 | r->headers_in.gecko = 1; |
1909 | |
|
1910 | 0 | } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) { |
1911 | 0 | r->headers_in.chrome = 1; |
1912 | |
|
1913 | 0 | } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1) |
1914 | 0 | && ngx_strstrn(user_agent, "Mac OS X", 8 - 1)) |
1915 | 0 | { |
1916 | 0 | r->headers_in.safari = 1; |
1917 | |
|
1918 | 0 | } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { |
1919 | 0 | r->headers_in.konqueror = 1; |
1920 | 0 | } |
1921 | 0 | } |
1922 | |
|
1923 | 0 | return NGX_OK; |
1924 | 0 | } |
1925 | | |
1926 | | |
1927 | | ngx_int_t |
1928 | | ngx_http_process_request_header(ngx_http_request_t *r) |
1929 | 8 | { |
1930 | 8 | if (r->headers_in.server.len == 0 |
1931 | 8 | && ngx_http_set_virtual_server(r, &r->headers_in.server) |
1932 | 5 | == NGX_ERROR) |
1933 | 0 | { |
1934 | 0 | return NGX_ERROR; |
1935 | 0 | } |
1936 | | |
1937 | 8 | if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) { |
1938 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1939 | 0 | "client sent HTTP/1.1 request without \"Host\" header"); |
1940 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1941 | 0 | return NGX_ERROR; |
1942 | 0 | } |
1943 | | |
1944 | 8 | if (r->headers_in.content_length) { |
1945 | 4 | r->headers_in.content_length_n = |
1946 | 4 | ngx_atoof(r->headers_in.content_length->value.data, |
1947 | 4 | r->headers_in.content_length->value.len); |
1948 | | |
1949 | 4 | if (r->headers_in.content_length_n == NGX_ERROR) { |
1950 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1951 | 0 | "client sent invalid \"Content-Length\" header"); |
1952 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1953 | 0 | return NGX_ERROR; |
1954 | 0 | } |
1955 | 4 | } |
1956 | | |
1957 | 8 | if (r->headers_in.transfer_encoding) { |
1958 | 3 | if (r->http_version < NGX_HTTP_VERSION_11) { |
1959 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1960 | 0 | "client sent HTTP/1.0 request with " |
1961 | 0 | "\"Transfer-Encoding\" header"); |
1962 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1963 | 0 | return NGX_ERROR; |
1964 | 0 | } |
1965 | | |
1966 | 3 | if (r->headers_in.transfer_encoding->value.len == 7 |
1967 | 3 | && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, |
1968 | 3 | (u_char *) "chunked", 7) == 0) |
1969 | 3 | { |
1970 | 3 | if (r->headers_in.content_length) { |
1971 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1972 | 0 | "client sent \"Content-Length\" and " |
1973 | 0 | "\"Transfer-Encoding\" headers " |
1974 | 0 | "at the same time"); |
1975 | 0 | ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); |
1976 | 0 | return NGX_ERROR; |
1977 | 0 | } |
1978 | | |
1979 | 3 | r->headers_in.chunked = 1; |
1980 | | |
1981 | 3 | } else { |
1982 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
1983 | 0 | "client sent unknown \"Transfer-Encoding\": \"%V\"", |
1984 | 0 | &r->headers_in.transfer_encoding->value); |
1985 | 0 | ngx_http_finalize_request(r, NGX_HTTP_NOT_IMPLEMENTED); |
1986 | 0 | return NGX_ERROR; |
1987 | 0 | } |
1988 | 3 | } |
1989 | | |
1990 | 8 | if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) { |
1991 | 0 | if (r->headers_in.keep_alive) { |
1992 | 0 | r->headers_in.keep_alive_n = |
1993 | 0 | ngx_atotm(r->headers_in.keep_alive->value.data, |
1994 | 0 | r->headers_in.keep_alive->value.len); |
1995 | 0 | } |
1996 | 0 | } |
1997 | | |
1998 | 8 | if (r->method == NGX_HTTP_CONNECT) { |
1999 | 0 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
2000 | 0 | "client sent CONNECT method"); |
2001 | 0 | ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); |
2002 | 0 | return NGX_ERROR; |
2003 | 0 | } |
2004 | | |
2005 | 8 | if (r->method == NGX_HTTP_TRACE) { |
2006 | 1 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
2007 | 1 | "client sent TRACE method"); |
2008 | 1 | ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); |
2009 | 1 | return NGX_ERROR; |
2010 | 1 | } |
2011 | | |
2012 | 7 | return NGX_OK; |
2013 | 8 | } |
2014 | | |
2015 | | |
2016 | | void |
2017 | | ngx_http_process_request(ngx_http_request_t *r) |
2018 | 11 | { |
2019 | 11 | ngx_connection_t *c; |
2020 | | |
2021 | 11 | c = r->connection; |
2022 | | |
2023 | | #if (NGX_HTTP_SSL) |
2024 | | |
2025 | | if (r->http_connection->ssl) { |
2026 | | long rc; |
2027 | | X509 *cert; |
2028 | | const char *s; |
2029 | | ngx_http_ssl_srv_conf_t *sscf; |
2030 | | |
2031 | | if (c->ssl == NULL) { |
2032 | | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
2033 | | "client sent plain HTTP request to HTTPS port"); |
2034 | | ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); |
2035 | | return; |
2036 | | } |
2037 | | |
2038 | | sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); |
2039 | | |
2040 | | if (sscf->verify) { |
2041 | | rc = SSL_get_verify_result(c->ssl->connection); |
2042 | | |
2043 | | if (rc != X509_V_OK |
2044 | | && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) |
2045 | | { |
2046 | | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
2047 | | "client SSL certificate verify error: (%l:%s)", |
2048 | | rc, X509_verify_cert_error_string(rc)); |
2049 | | |
2050 | | ngx_ssl_remove_cached_session(c->ssl->session_ctx, |
2051 | | (SSL_get0_session(c->ssl->connection))); |
2052 | | |
2053 | | ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); |
2054 | | return; |
2055 | | } |
2056 | | |
2057 | | if (sscf->verify == 1) { |
2058 | | cert = SSL_get_peer_certificate(c->ssl->connection); |
2059 | | |
2060 | | if (cert == NULL) { |
2061 | | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
2062 | | "client sent no required SSL certificate"); |
2063 | | |
2064 | | ngx_ssl_remove_cached_session(c->ssl->session_ctx, |
2065 | | (SSL_get0_session(c->ssl->connection))); |
2066 | | |
2067 | | ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); |
2068 | | return; |
2069 | | } |
2070 | | |
2071 | | X509_free(cert); |
2072 | | } |
2073 | | |
2074 | | if (ngx_ssl_ocsp_get_status(c, &s) != NGX_OK) { |
2075 | | ngx_log_error(NGX_LOG_INFO, c->log, 0, |
2076 | | "client SSL certificate verify error: %s", s); |
2077 | | |
2078 | | ngx_ssl_remove_cached_session(c->ssl->session_ctx, |
2079 | | (SSL_get0_session(c->ssl->connection))); |
2080 | | |
2081 | | ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); |
2082 | | return; |
2083 | | } |
2084 | | } |
2085 | | } |
2086 | | |
2087 | | #endif |
2088 | | |
2089 | 11 | if (c->read->timer_set) { |
2090 | 0 | ngx_del_timer(c->read); |
2091 | 0 | } |
2092 | | |
2093 | | #if (NGX_STAT_STUB) |
2094 | | (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); |
2095 | | r->stat_reading = 0; |
2096 | | (void) ngx_atomic_fetch_add(ngx_stat_writing, 1); |
2097 | | r->stat_writing = 1; |
2098 | | #endif |
2099 | | |
2100 | 11 | c->read->handler = ngx_http_request_handler; |
2101 | 11 | c->write->handler = ngx_http_request_handler; |
2102 | 11 | r->read_event_handler = ngx_http_block_reading; |
2103 | | |
2104 | 11 | ngx_http_handler(r); |
2105 | 11 | } |
2106 | | |
2107 | | |
2108 | | ngx_int_t |
2109 | | ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) |
2110 | 5 | { |
2111 | 5 | u_char *h, ch; |
2112 | 5 | size_t i, dot_pos, host_len; |
2113 | | |
2114 | 5 | enum { |
2115 | 5 | sw_usual = 0, |
2116 | 5 | sw_literal, |
2117 | 5 | sw_rest |
2118 | 5 | } state; |
2119 | | |
2120 | 5 | dot_pos = host->len; |
2121 | 5 | host_len = host->len; |
2122 | | |
2123 | 5 | h = host->data; |
2124 | | |
2125 | 5 | state = sw_usual; |
2126 | | |
2127 | 84 | for (i = 0; i < host->len; i++) { |
2128 | 79 | ch = h[i]; |
2129 | | |
2130 | 79 | switch (ch) { |
2131 | | |
2132 | 0 | case '.': |
2133 | 0 | if (dot_pos == i - 1) { |
2134 | 0 | return NGX_DECLINED; |
2135 | 0 | } |
2136 | 0 | dot_pos = i; |
2137 | 0 | break; |
2138 | | |
2139 | 2 | case ':': |
2140 | 2 | if (state == sw_usual) { |
2141 | 1 | host_len = i; |
2142 | 1 | state = sw_rest; |
2143 | 1 | } |
2144 | 2 | break; |
2145 | | |
2146 | 0 | case '[': |
2147 | 0 | if (i == 0) { |
2148 | 0 | state = sw_literal; |
2149 | 0 | } |
2150 | 0 | break; |
2151 | | |
2152 | 0 | case ']': |
2153 | 0 | if (state == sw_literal) { |
2154 | 0 | host_len = i + 1; |
2155 | 0 | state = sw_rest; |
2156 | 0 | } |
2157 | 0 | break; |
2158 | | |
2159 | 77 | default: |
2160 | | |
2161 | 77 | if (ngx_path_separator(ch)) { |
2162 | 0 | return NGX_DECLINED; |
2163 | 0 | } |
2164 | | |
2165 | 77 | if (ch <= 0x20 || ch == 0x7f) { |
2166 | 0 | return NGX_DECLINED; |
2167 | 0 | } |
2168 | | |
2169 | 77 | if (ch >= 'A' && ch <= 'Z') { |
2170 | 15 | alloc = 1; |
2171 | 15 | } |
2172 | | |
2173 | 77 | break; |
2174 | 79 | } |
2175 | 79 | } |
2176 | | |
2177 | 5 | if (dot_pos == host_len - 1) { |
2178 | 0 | host_len--; |
2179 | 0 | } |
2180 | | |
2181 | 5 | if (host_len == 0) { |
2182 | 0 | return NGX_DECLINED; |
2183 | 0 | } |
2184 | | |
2185 | 5 | if (alloc) { |
2186 | 5 | host->data = ngx_pnalloc(pool, host_len); |
2187 | 5 | if (host->data == NULL) { |
2188 | 0 | return NGX_ERROR; |
2189 | 0 | } |
2190 | | |
2191 | 5 | ngx_strlow(host->data, h, host_len); |
2192 | 5 | } |
2193 | | |
2194 | 5 | host->len = host_len; |
2195 | | |
2196 | 5 | return NGX_OK; |
2197 | 5 | } |
2198 | | |
2199 | | |
2200 | | ngx_int_t |
2201 | | ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) |
2202 | 12 | { |
2203 | 12 | ngx_int_t rc; |
2204 | 12 | ngx_http_connection_t *hc; |
2205 | 12 | ngx_http_core_loc_conf_t *clcf; |
2206 | 12 | ngx_http_core_srv_conf_t *cscf; |
2207 | | |
2208 | 12 | #if (NGX_SUPPRESS_WARN) |
2209 | 12 | cscf = NULL; |
2210 | 12 | #endif |
2211 | | |
2212 | 12 | hc = r->http_connection; |
2213 | | |
2214 | | #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) |
2215 | | |
2216 | | if (hc->ssl_servername) { |
2217 | | if (hc->ssl_servername->len == host->len |
2218 | | && ngx_strncmp(hc->ssl_servername->data, |
2219 | | host->data, host->len) == 0) |
2220 | | { |
2221 | | #if (NGX_PCRE) |
2222 | | if (hc->ssl_servername_regex |
2223 | | && ngx_http_regex_exec(r, hc->ssl_servername_regex, |
2224 | | hc->ssl_servername) != NGX_OK) |
2225 | | { |
2226 | | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
2227 | | return NGX_ERROR; |
2228 | | } |
2229 | | #endif |
2230 | | return NGX_OK; |
2231 | | } |
2232 | | } |
2233 | | |
2234 | | #endif |
2235 | | |
2236 | 12 | rc = ngx_http_find_virtual_server(r->connection, |
2237 | 12 | hc->addr_conf->virtual_names, |
2238 | 12 | host, r, &cscf); |
2239 | | |
2240 | 12 | if (rc == NGX_ERROR) { |
2241 | 0 | ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
2242 | 0 | return NGX_ERROR; |
2243 | 0 | } |
2244 | | |
2245 | | #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) |
2246 | | |
2247 | | if (hc->ssl_servername) { |
2248 | | ngx_http_ssl_srv_conf_t *sscf; |
2249 | | |
2250 | | if (rc == NGX_DECLINED) { |
2251 | | cscf = hc->addr_conf->default_server; |
2252 | | rc = NGX_OK; |
2253 | | } |
2254 | | |
2255 | | sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module); |
2256 | | |
2257 | | if (sscf->verify) { |
2258 | | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
2259 | | "client attempted to request the server name " |
2260 | | "different from the one that was negotiated"); |
2261 | | ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST); |
2262 | | return NGX_ERROR; |
2263 | | } |
2264 | | } |
2265 | | |
2266 | | #endif |
2267 | | |
2268 | 12 | if (rc == NGX_DECLINED) { |
2269 | 12 | return NGX_OK; |
2270 | 12 | } |
2271 | | |
2272 | 0 | r->srv_conf = cscf->ctx->srv_conf; |
2273 | 0 | r->loc_conf = cscf->ctx->loc_conf; |
2274 | |
|
2275 | 0 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
2276 | |
|
2277 | 0 | ngx_set_connection_log(r->connection, clcf->error_log); |
2278 | |
|
2279 | 0 | return NGX_OK; |
2280 | 12 | } |
2281 | | |
2282 | | |
2283 | | static ngx_int_t |
2284 | | ngx_http_find_virtual_server(ngx_connection_t *c, |
2285 | | ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, |
2286 | | ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp) |
2287 | 12 | { |
2288 | 12 | ngx_http_core_srv_conf_t *cscf; |
2289 | | |
2290 | 12 | if (virtual_names == NULL) { |
2291 | 0 | return NGX_DECLINED; |
2292 | 0 | } |
2293 | | |
2294 | 12 | cscf = ngx_hash_find_combined(&virtual_names->names, |
2295 | 12 | ngx_hash_key(host->data, host->len), |
2296 | 12 | host->data, host->len); |
2297 | | |
2298 | 12 | if (cscf) { |
2299 | 0 | *cscfp = cscf; |
2300 | 0 | return NGX_OK; |
2301 | 0 | } |
2302 | | |
2303 | 12 | #if (NGX_PCRE) |
2304 | | |
2305 | 12 | if (host->len && virtual_names->nregex) { |
2306 | 3 | ngx_int_t n; |
2307 | 3 | ngx_uint_t i; |
2308 | 3 | ngx_http_server_name_t *sn; |
2309 | | |
2310 | 3 | sn = virtual_names->regex; |
2311 | | |
2312 | | #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) |
2313 | | |
2314 | | if (r == NULL) { |
2315 | | ngx_http_connection_t *hc; |
2316 | | |
2317 | | for (i = 0; i < virtual_names->nregex; i++) { |
2318 | | |
2319 | | n = ngx_regex_exec(sn[i].regex->regex, host, NULL, 0); |
2320 | | |
2321 | | if (n == NGX_REGEX_NO_MATCHED) { |
2322 | | continue; |
2323 | | } |
2324 | | |
2325 | | if (n >= 0) { |
2326 | | hc = c->data; |
2327 | | hc->ssl_servername_regex = sn[i].regex; |
2328 | | |
2329 | | *cscfp = sn[i].server; |
2330 | | return NGX_OK; |
2331 | | } |
2332 | | |
2333 | | ngx_log_error(NGX_LOG_ALERT, c->log, 0, |
2334 | | ngx_regex_exec_n " failed: %i " |
2335 | | "on \"%V\" using \"%V\"", |
2336 | | n, host, &sn[i].regex->name); |
2337 | | |
2338 | | return NGX_ERROR; |
2339 | | } |
2340 | | |
2341 | | return NGX_DECLINED; |
2342 | | } |
2343 | | |
2344 | | #endif /* NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME */ |
2345 | | |
2346 | 6 | for (i = 0; i < virtual_names->nregex; i++) { |
2347 | | |
2348 | 3 | n = ngx_http_regex_exec(r, sn[i].regex, host); |
2349 | | |
2350 | 3 | if (n == NGX_DECLINED) { |
2351 | 3 | continue; |
2352 | 3 | } |
2353 | | |
2354 | 0 | if (n == NGX_OK) { |
2355 | 0 | *cscfp = sn[i].server; |
2356 | 0 | return NGX_OK; |
2357 | 0 | } |
2358 | | |
2359 | 0 | return NGX_ERROR; |
2360 | 0 | } |
2361 | 3 | } |
2362 | | |
2363 | 12 | #endif /* NGX_PCRE */ |
2364 | | |
2365 | 12 | return NGX_DECLINED; |
2366 | 12 | } |
2367 | | |
2368 | | |
2369 | | static void |
2370 | | ngx_http_request_handler(ngx_event_t *ev) |
2371 | 0 | { |
2372 | 0 | ngx_connection_t *c; |
2373 | 0 | ngx_http_request_t *r; |
2374 | |
|
2375 | 0 | c = ev->data; |
2376 | 0 | r = c->data; |
2377 | |
|
2378 | 0 | ngx_http_set_log_request(c->log, r); |
2379 | |
|
2380 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
2381 | 0 | "http run request: \"%V?%V\"", &r->uri, &r->args); |
2382 | |
|
2383 | 0 | if (c->close) { |
2384 | 0 | r->main->count++; |
2385 | 0 | ngx_http_terminate_request(r, 0); |
2386 | 0 | ngx_http_run_posted_requests(c); |
2387 | 0 | return; |
2388 | 0 | } |
2389 | | |
2390 | 0 | if (ev->delayed && ev->timedout) { |
2391 | 0 | ev->delayed = 0; |
2392 | 0 | ev->timedout = 0; |
2393 | 0 | } |
2394 | |
|
2395 | 0 | if (ev->write) { |
2396 | 0 | r->write_event_handler(r); |
2397 | |
|
2398 | 0 | } else { |
2399 | 0 | r->read_event_handler(r); |
2400 | 0 | } |
2401 | |
|
2402 | 0 | ngx_http_run_posted_requests(c); |
2403 | 0 | } |
2404 | | |
2405 | | |
2406 | | void |
2407 | | ngx_http_run_posted_requests(ngx_connection_t *c) |
2408 | 24 | { |
2409 | 24 | ngx_http_request_t *r; |
2410 | 24 | ngx_http_posted_request_t *pr; |
2411 | | |
2412 | 30 | for ( ;; ) { |
2413 | | |
2414 | 30 | if (c->destroyed) { |
2415 | 15 | return; |
2416 | 15 | } |
2417 | | |
2418 | 15 | r = c->data; |
2419 | 15 | pr = r->main->posted_requests; |
2420 | | |
2421 | 15 | if (pr == NULL) { |
2422 | 9 | return; |
2423 | 9 | } |
2424 | | |
2425 | 6 | r->main->posted_requests = pr->next; |
2426 | | |
2427 | 6 | r = pr->request; |
2428 | | |
2429 | 6 | ngx_http_set_log_request(c->log, r); |
2430 | | |
2431 | 6 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
2432 | 6 | "http posted request: \"%V?%V\"", &r->uri, &r->args); |
2433 | | |
2434 | 6 | r->write_event_handler(r); |
2435 | 6 | } |
2436 | 24 | } |
2437 | | |
2438 | | |
2439 | | ngx_int_t |
2440 | | ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr) |
2441 | 6 | { |
2442 | 6 | ngx_http_posted_request_t **p; |
2443 | | |
2444 | 6 | if (pr == NULL) { |
2445 | 0 | pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); |
2446 | 0 | if (pr == NULL) { |
2447 | 0 | return NGX_ERROR; |
2448 | 0 | } |
2449 | 0 | } |
2450 | | |
2451 | 6 | pr->request = r; |
2452 | 6 | pr->next = NULL; |
2453 | | |
2454 | 6 | for (p = &r->main->posted_requests; *p; p = &(*p)->next) { /* void */ } |
2455 | | |
2456 | 6 | *p = pr; |
2457 | | |
2458 | 6 | return NGX_OK; |
2459 | 6 | } |
2460 | | |
2461 | | |
2462 | | void |
2463 | | ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) |
2464 | 25 | { |
2465 | 25 | ngx_connection_t *c; |
2466 | 25 | ngx_http_request_t *pr; |
2467 | 25 | ngx_http_core_loc_conf_t *clcf; |
2468 | | |
2469 | 25 | c = r->connection; |
2470 | | |
2471 | 25 | ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, |
2472 | 25 | "http finalize request: %i, \"%V?%V\" a:%d, c:%d", |
2473 | 25 | rc, &r->uri, &r->args, r == c->data, r->main->count); |
2474 | | |
2475 | 25 | if (rc == NGX_DONE) { |
2476 | 12 | ngx_http_finalize_connection(r); |
2477 | 12 | return; |
2478 | 12 | } |
2479 | | |
2480 | 13 | if (rc == NGX_OK && r->filter_finalize) { |
2481 | 0 | c->error = 1; |
2482 | 0 | } |
2483 | | |
2484 | 13 | if (rc == NGX_DECLINED) { |
2485 | 0 | r->content_handler = NULL; |
2486 | 0 | r->write_event_handler = ngx_http_core_run_phases; |
2487 | 0 | ngx_http_core_run_phases(r); |
2488 | 0 | return; |
2489 | 0 | } |
2490 | | |
2491 | 13 | if (r != r->main && r->post_subrequest) { |
2492 | 0 | rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc); |
2493 | 0 | } |
2494 | | |
2495 | 13 | if (rc == NGX_ERROR |
2496 | 13 | || rc == NGX_HTTP_REQUEST_TIME_OUT |
2497 | 13 | || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST |
2498 | 13 | || c->error) |
2499 | 9 | { |
2500 | 9 | if (ngx_http_post_action(r) == NGX_OK) { |
2501 | 0 | return; |
2502 | 0 | } |
2503 | | |
2504 | 9 | ngx_http_terminate_request(r, rc); |
2505 | 9 | return; |
2506 | 9 | } |
2507 | | |
2508 | 4 | if (rc >= NGX_HTTP_SPECIAL_RESPONSE |
2509 | 4 | || rc == NGX_HTTP_CREATED |
2510 | 4 | || rc == NGX_HTTP_NO_CONTENT) |
2511 | 2 | { |
2512 | 2 | if (rc == NGX_HTTP_CLOSE) { |
2513 | 0 | c->timedout = 1; |
2514 | 0 | ngx_http_terminate_request(r, rc); |
2515 | 0 | return; |
2516 | 0 | } |
2517 | | |
2518 | 2 | if (r == r->main) { |
2519 | 2 | if (c->read->timer_set) { |
2520 | 0 | ngx_del_timer(c->read); |
2521 | 0 | } |
2522 | | |
2523 | 2 | if (c->write->timer_set) { |
2524 | 0 | ngx_del_timer(c->write); |
2525 | 0 | } |
2526 | 2 | } |
2527 | | |
2528 | 2 | c->read->handler = ngx_http_request_handler; |
2529 | 2 | c->write->handler = ngx_http_request_handler; |
2530 | | |
2531 | 2 | ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc)); |
2532 | 2 | return; |
2533 | 2 | } |
2534 | | |
2535 | 2 | if (r != r->main) { |
2536 | |
|
2537 | 0 | if (r->buffered || r->postponed) { |
2538 | |
|
2539 | 0 | if (ngx_http_set_write_handler(r) != NGX_OK) { |
2540 | 0 | ngx_http_terminate_request(r, 0); |
2541 | 0 | } |
2542 | |
|
2543 | 0 | return; |
2544 | 0 | } |
2545 | | |
2546 | 0 | pr = r->parent; |
2547 | |
|
2548 | 0 | if (r == c->data || r->background) { |
2549 | |
|
2550 | 0 | if (!r->logged) { |
2551 | |
|
2552 | 0 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
2553 | |
|
2554 | 0 | if (clcf->log_subrequest) { |
2555 | 0 | ngx_http_log_request(r); |
2556 | 0 | } |
2557 | |
|
2558 | 0 | r->logged = 1; |
2559 | |
|
2560 | 0 | } else { |
2561 | 0 | ngx_log_error(NGX_LOG_ALERT, c->log, 0, |
2562 | 0 | "subrequest: \"%V?%V\" logged again", |
2563 | 0 | &r->uri, &r->args); |
2564 | 0 | } |
2565 | |
|
2566 | 0 | r->done = 1; |
2567 | |
|
2568 | 0 | if (r->background) { |
2569 | 0 | ngx_http_finalize_connection(r); |
2570 | 0 | return; |
2571 | 0 | } |
2572 | | |
2573 | 0 | r->main->count--; |
2574 | |
|
2575 | 0 | if (pr->postponed && pr->postponed->request == r) { |
2576 | 0 | pr->postponed = pr->postponed->next; |
2577 | 0 | } |
2578 | |
|
2579 | 0 | c->data = pr; |
2580 | |
|
2581 | 0 | } else { |
2582 | |
|
2583 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
2584 | 0 | "http finalize non-active request: \"%V?%V\"", |
2585 | 0 | &r->uri, &r->args); |
2586 | |
|
2587 | 0 | r->write_event_handler = ngx_http_request_finalizer; |
2588 | |
|
2589 | 0 | if (r->waited) { |
2590 | 0 | r->done = 1; |
2591 | 0 | } |
2592 | 0 | } |
2593 | | |
2594 | 0 | if (ngx_http_post_request(pr, NULL) != NGX_OK) { |
2595 | 0 | r->main->count++; |
2596 | 0 | ngx_http_terminate_request(r, 0); |
2597 | 0 | return; |
2598 | 0 | } |
2599 | | |
2600 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
2601 | 0 | "http wake parent request: \"%V?%V\"", |
2602 | 0 | &pr->uri, &pr->args); |
2603 | |
|
2604 | 0 | return; |
2605 | 0 | } |
2606 | | |
2607 | 2 | if (r->buffered || c->buffered || r->postponed) { |
2608 | | |
2609 | 2 | if (ngx_http_set_write_handler(r) != NGX_OK) { |
2610 | 0 | ngx_http_terminate_request(r, 0); |
2611 | 0 | } |
2612 | | |
2613 | 2 | return; |
2614 | 2 | } |
2615 | | |
2616 | 0 | if (r != c->data) { |
2617 | 0 | ngx_log_error(NGX_LOG_ALERT, c->log, 0, |
2618 | 0 | "http finalize non-active request: \"%V?%V\"", |
2619 | 0 | &r->uri, &r->args); |
2620 | 0 | return; |
2621 | 0 | } |
2622 | | |
2623 | 0 | r->done = 1; |
2624 | |
|
2625 | 0 | r->read_event_handler = ngx_http_block_reading; |
2626 | 0 | r->write_event_handler = ngx_http_request_empty_handler; |
2627 | |
|
2628 | 0 | if (!r->post_action) { |
2629 | 0 | r->request_complete = 1; |
2630 | 0 | } |
2631 | |
|
2632 | 0 | if (ngx_http_post_action(r) == NGX_OK) { |
2633 | 0 | return; |
2634 | 0 | } |
2635 | | |
2636 | 0 | if (c->read->timer_set) { |
2637 | 0 | ngx_del_timer(c->read); |
2638 | 0 | } |
2639 | |
|
2640 | 0 | if (c->write->timer_set) { |
2641 | 0 | c->write->delayed = 0; |
2642 | 0 | ngx_del_timer(c->write); |
2643 | 0 | } |
2644 | |
|
2645 | 0 | ngx_http_finalize_connection(r); |
2646 | 0 | } |
2647 | | |
2648 | | |
2649 | | static void |
2650 | | ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc) |
2651 | 9 | { |
2652 | 9 | ngx_http_cleanup_t *cln; |
2653 | 9 | ngx_http_request_t *mr; |
2654 | 9 | ngx_http_ephemeral_t *e; |
2655 | | |
2656 | 9 | mr = r->main; |
2657 | | |
2658 | 9 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2659 | 9 | "http terminate request count:%d", mr->count); |
2660 | | |
2661 | 9 | if (rc > 0 && (mr->headers_out.status == 0 || mr->connection->sent == 0)) { |
2662 | 9 | mr->headers_out.status = rc; |
2663 | 9 | } |
2664 | | |
2665 | 9 | cln = mr->cleanup; |
2666 | 9 | mr->cleanup = NULL; |
2667 | | |
2668 | 9 | while (cln) { |
2669 | 0 | if (cln->handler) { |
2670 | 0 | cln->handler(cln->data); |
2671 | 0 | } |
2672 | |
|
2673 | 0 | cln = cln->next; |
2674 | 0 | } |
2675 | | |
2676 | 9 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2677 | 9 | "http terminate cleanup count:%d blk:%d", |
2678 | 9 | mr->count, mr->blocked); |
2679 | | |
2680 | 9 | if (mr->write_event_handler) { |
2681 | | |
2682 | 6 | if (mr->blocked) { |
2683 | 0 | r->connection->error = 1; |
2684 | 0 | r->write_event_handler = ngx_http_request_finalizer; |
2685 | 0 | return; |
2686 | 0 | } |
2687 | | |
2688 | 6 | e = ngx_http_ephemeral(mr); |
2689 | 6 | mr->posted_requests = NULL; |
2690 | 6 | mr->write_event_handler = ngx_http_terminate_handler; |
2691 | 6 | (void) ngx_http_post_request(mr, &e->terminal_posted_request); |
2692 | 6 | return; |
2693 | 6 | } |
2694 | | |
2695 | 3 | ngx_http_close_request(mr, rc); |
2696 | 3 | } |
2697 | | |
2698 | | |
2699 | | static void |
2700 | | ngx_http_terminate_handler(ngx_http_request_t *r) |
2701 | 6 | { |
2702 | 6 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2703 | 6 | "http terminate handler count:%d", r->count); |
2704 | | |
2705 | 6 | r->count = 1; |
2706 | | |
2707 | 6 | ngx_http_close_request(r, 0); |
2708 | 6 | } |
2709 | | |
2710 | | |
2711 | | static void |
2712 | | ngx_http_finalize_connection(ngx_http_request_t *r) |
2713 | 12 | { |
2714 | 12 | ngx_http_core_loc_conf_t *clcf; |
2715 | | |
2716 | 12 | #if (NGX_HTTP_V2) |
2717 | 12 | if (r->stream) { |
2718 | 0 | ngx_http_close_request(r, 0); |
2719 | 0 | return; |
2720 | 0 | } |
2721 | 12 | #endif |
2722 | | |
2723 | | #if (NGX_HTTP_V3) |
2724 | | if (r->connection->quic) { |
2725 | | ngx_http_close_request(r, 0); |
2726 | | return; |
2727 | | } |
2728 | | #endif |
2729 | | |
2730 | 12 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
2731 | | |
2732 | 12 | if (r->main->count != 1) { |
2733 | | |
2734 | 5 | if (r->discard_body) { |
2735 | 0 | r->read_event_handler = ngx_http_discarded_request_body_handler; |
2736 | 0 | ngx_add_timer(r->connection->read, clcf->lingering_timeout); |
2737 | |
|
2738 | 0 | if (r->lingering_time == 0) { |
2739 | 0 | r->lingering_time = ngx_time() |
2740 | 0 | + (time_t) (clcf->lingering_time / 1000); |
2741 | 0 | } |
2742 | 0 | } |
2743 | | |
2744 | 5 | ngx_http_close_request(r, 0); |
2745 | 5 | return; |
2746 | 5 | } |
2747 | | |
2748 | 7 | r = r->main; |
2749 | | |
2750 | 7 | if (r->connection->read->eof) { |
2751 | 0 | ngx_http_close_request(r, 0); |
2752 | 0 | return; |
2753 | 0 | } |
2754 | | |
2755 | 7 | if (r->reading_body) { |
2756 | 0 | r->keepalive = 0; |
2757 | 0 | r->lingering_close = 1; |
2758 | 0 | } |
2759 | | |
2760 | 7 | if (!ngx_terminate |
2761 | 7 | && !ngx_exiting |
2762 | 7 | && r->keepalive |
2763 | 7 | && clcf->keepalive_timeout > 0) |
2764 | 0 | { |
2765 | 0 | ngx_http_set_keepalive(r); |
2766 | 0 | return; |
2767 | 0 | } |
2768 | | |
2769 | 7 | if (clcf->lingering_close == NGX_HTTP_LINGERING_ALWAYS |
2770 | 7 | || (clcf->lingering_close == NGX_HTTP_LINGERING_ON |
2771 | 7 | && (r->lingering_close |
2772 | 7 | || r->header_in->pos < r->header_in->last |
2773 | 7 | || r->connection->read->ready |
2774 | 7 | || r->connection->pipeline))) |
2775 | 7 | { |
2776 | 7 | ngx_http_set_lingering_close(r->connection); |
2777 | 7 | return; |
2778 | 7 | } |
2779 | | |
2780 | 0 | ngx_http_close_request(r, 0); |
2781 | 0 | } |
2782 | | |
2783 | | |
2784 | | static ngx_int_t |
2785 | | ngx_http_set_write_handler(ngx_http_request_t *r) |
2786 | 2 | { |
2787 | 2 | ngx_event_t *wev; |
2788 | 2 | ngx_http_core_loc_conf_t *clcf; |
2789 | | |
2790 | 2 | r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; |
2791 | | |
2792 | 2 | r->read_event_handler = r->discard_body ? |
2793 | 0 | ngx_http_discarded_request_body_handler: |
2794 | 2 | ngx_http_test_reading; |
2795 | 2 | r->write_event_handler = ngx_http_writer; |
2796 | | |
2797 | 2 | wev = r->connection->write; |
2798 | | |
2799 | 2 | if (wev->ready && wev->delayed) { |
2800 | 2 | return NGX_OK; |
2801 | 2 | } |
2802 | | |
2803 | 0 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
2804 | 0 | if (!wev->delayed) { |
2805 | 0 | ngx_add_timer(wev, clcf->send_timeout); |
2806 | 0 | } |
2807 | |
|
2808 | 0 | if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { |
2809 | 0 | ngx_http_close_request(r, 0); |
2810 | 0 | return NGX_ERROR; |
2811 | 0 | } |
2812 | | |
2813 | 0 | return NGX_OK; |
2814 | 0 | } |
2815 | | |
2816 | | |
2817 | | static void |
2818 | | ngx_http_writer(ngx_http_request_t *r) |
2819 | 0 | { |
2820 | 0 | ngx_int_t rc; |
2821 | 0 | ngx_event_t *wev; |
2822 | 0 | ngx_connection_t *c; |
2823 | 0 | ngx_http_core_loc_conf_t *clcf; |
2824 | |
|
2825 | 0 | c = r->connection; |
2826 | 0 | wev = c->write; |
2827 | |
|
2828 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, |
2829 | 0 | "http writer handler: \"%V?%V\"", &r->uri, &r->args); |
2830 | |
|
2831 | 0 | clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); |
2832 | |
|
2833 | 0 | if (wev->timedout) { |
2834 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, |
2835 | 0 | "client timed out"); |
2836 | 0 | c->timedout = 1; |
2837 | |
|
2838 | 0 | ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); |
2839 | 0 | return; |
2840 | 0 | } |
2841 | | |
2842 | 0 | if (wev->delayed || r->aio) { |
2843 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, |
2844 | 0 | "http writer delayed"); |
2845 | |
|
2846 | 0 | if (!wev->delayed) { |
2847 | 0 | ngx_add_timer(wev, clcf->send_timeout); |
2848 | 0 | } |
2849 | |
|
2850 | 0 | if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { |
2851 | 0 | ngx_http_close_request(r, 0); |
2852 | 0 | } |
2853 | |
|
2854 | 0 | return; |
2855 | 0 | } |
2856 | | |
2857 | 0 | rc = ngx_http_output_filter(r, NULL); |
2858 | |
|
2859 | 0 | ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, |
2860 | 0 | "http writer output filter: %i, \"%V?%V\"", |
2861 | 0 | rc, &r->uri, &r->args); |
2862 | |
|
2863 | 0 | if (rc == NGX_ERROR) { |
2864 | 0 | ngx_http_finalize_request(r, rc); |
2865 | 0 | return; |
2866 | 0 | } |
2867 | | |
2868 | 0 | if (r->buffered || r->postponed || (r == r->main && c->buffered)) { |
2869 | |
|
2870 | 0 | if (!wev->delayed) { |
2871 | 0 | ngx_add_timer(wev, clcf->send_timeout); |
2872 | 0 | } |
2873 | |
|
2874 | 0 | if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { |
2875 | 0 | ngx_http_close_request(r, 0); |
2876 | 0 | } |
2877 | |
|
2878 | 0 | return; |
2879 | 0 | } |
2880 | | |
2881 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, |
2882 | 0 | "http writer done: \"%V?%V\"", &r->uri, &r->args); |
2883 | |
|
2884 | 0 | r->write_event_handler = ngx_http_request_empty_handler; |
2885 | |
|
2886 | 0 | ngx_http_finalize_request(r, rc); |
2887 | 0 | } |
2888 | | |
2889 | | |
2890 | | static void |
2891 | | ngx_http_request_finalizer(ngx_http_request_t *r) |
2892 | 0 | { |
2893 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2894 | 0 | "http finalizer done: \"%V?%V\"", &r->uri, &r->args); |
2895 | |
|
2896 | 0 | ngx_http_finalize_request(r, 0); |
2897 | 0 | } |
2898 | | |
2899 | | |
2900 | | void |
2901 | | ngx_http_block_reading(ngx_http_request_t *r) |
2902 | 0 | { |
2903 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2904 | 0 | "http reading blocked"); |
2905 | | |
2906 | | /* aio does not call this handler */ |
2907 | |
|
2908 | 0 | if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) |
2909 | 0 | && r->connection->read->active) |
2910 | 0 | { |
2911 | 0 | if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0) != NGX_OK) { |
2912 | 0 | ngx_http_close_request(r, 0); |
2913 | 0 | } |
2914 | 0 | } |
2915 | 0 | } |
2916 | | |
2917 | | |
2918 | | void |
2919 | | ngx_http_test_reading(ngx_http_request_t *r) |
2920 | 0 | { |
2921 | 0 | int n; |
2922 | 0 | char buf[1]; |
2923 | 0 | ngx_err_t err; |
2924 | 0 | ngx_event_t *rev; |
2925 | 0 | ngx_connection_t *c; |
2926 | |
|
2927 | 0 | c = r->connection; |
2928 | 0 | rev = c->read; |
2929 | |
|
2930 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test reading"); |
2931 | |
|
2932 | 0 | #if (NGX_HTTP_V2) |
2933 | |
|
2934 | 0 | if (r->stream) { |
2935 | 0 | if (c->error) { |
2936 | 0 | err = 0; |
2937 | 0 | goto closed; |
2938 | 0 | } |
2939 | | |
2940 | 0 | return; |
2941 | 0 | } |
2942 | | |
2943 | 0 | #endif |
2944 | | |
2945 | | #if (NGX_HTTP_V3) |
2946 | | |
2947 | | if (c->quic) { |
2948 | | if (rev->error) { |
2949 | | c->error = 1; |
2950 | | err = 0; |
2951 | | goto closed; |
2952 | | } |
2953 | | |
2954 | | return; |
2955 | | } |
2956 | | |
2957 | | #endif |
2958 | | |
2959 | | #if (NGX_HAVE_KQUEUE) |
2960 | | |
2961 | | if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { |
2962 | | |
2963 | | if (!rev->pending_eof) { |
2964 | | return; |
2965 | | } |
2966 | | |
2967 | | rev->eof = 1; |
2968 | | c->error = 1; |
2969 | | err = rev->kq_errno; |
2970 | | |
2971 | | goto closed; |
2972 | | } |
2973 | | |
2974 | | #endif |
2975 | | |
2976 | 0 | #if (NGX_HAVE_EPOLLRDHUP) |
2977 | | |
2978 | 0 | if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) { |
2979 | 0 | socklen_t len; |
2980 | |
|
2981 | 0 | if (!rev->pending_eof) { |
2982 | 0 | return; |
2983 | 0 | } |
2984 | | |
2985 | 0 | rev->eof = 1; |
2986 | 0 | c->error = 1; |
2987 | |
|
2988 | 0 | err = 0; |
2989 | 0 | len = sizeof(ngx_err_t); |
2990 | | |
2991 | | /* |
2992 | | * BSDs and Linux return 0 and set a pending error in err |
2993 | | * Solaris returns -1 and sets errno |
2994 | | */ |
2995 | |
|
2996 | 0 | if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) |
2997 | 0 | == -1) |
2998 | 0 | { |
2999 | 0 | err = ngx_socket_errno; |
3000 | 0 | } |
3001 | |
|
3002 | 0 | goto closed; |
3003 | 0 | } |
3004 | | |
3005 | 0 | #endif |
3006 | | |
3007 | 0 | n = recv(c->fd, buf, 1, MSG_PEEK); |
3008 | |
|
3009 | 0 | if (n == 0) { |
3010 | 0 | rev->eof = 1; |
3011 | 0 | c->error = 1; |
3012 | 0 | err = 0; |
3013 | |
|
3014 | 0 | goto closed; |
3015 | |
|
3016 | 0 | } else if (n == -1) { |
3017 | 0 | err = ngx_socket_errno; |
3018 | |
|
3019 | 0 | if (err != NGX_EAGAIN) { |
3020 | 0 | rev->eof = 1; |
3021 | 0 | c->error = 1; |
3022 | |
|
3023 | 0 | goto closed; |
3024 | 0 | } |
3025 | 0 | } |
3026 | | |
3027 | | /* aio does not call this handler */ |
3028 | | |
3029 | 0 | if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) { |
3030 | |
|
3031 | 0 | if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { |
3032 | 0 | ngx_http_close_request(r, 0); |
3033 | 0 | } |
3034 | 0 | } |
3035 | |
|
3036 | 0 | return; |
3037 | | |
3038 | 0 | closed: |
3039 | |
|
3040 | 0 | if (err) { |
3041 | 0 | rev->error = 1; |
3042 | 0 | } |
3043 | |
|
3044 | | #if (NGX_HTTP_SSL) |
3045 | | if (c->ssl) { |
3046 | | c->ssl->no_send_shutdown = 1; |
3047 | | } |
3048 | | #endif |
3049 | |
|
3050 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, err, |
3051 | 0 | "client prematurely closed connection"); |
3052 | |
|
3053 | 0 | ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); |
3054 | 0 | } |
3055 | | |
3056 | | |
3057 | | static void |
3058 | | ngx_http_set_keepalive(ngx_http_request_t *r) |
3059 | 0 | { |
3060 | 0 | int tcp_nodelay; |
3061 | 0 | ngx_buf_t *b, *f; |
3062 | 0 | ngx_chain_t *cl, *ln; |
3063 | 0 | ngx_event_t *rev, *wev; |
3064 | 0 | ngx_connection_t *c; |
3065 | 0 | ngx_http_connection_t *hc; |
3066 | 0 | ngx_http_core_loc_conf_t *clcf; |
3067 | |
|
3068 | 0 | c = r->connection; |
3069 | 0 | rev = c->read; |
3070 | |
|
3071 | 0 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
3072 | |
|
3073 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "set http keepalive handler"); |
3074 | |
|
3075 | 0 | c->log->action = "closing request"; |
3076 | |
|
3077 | 0 | hc = r->http_connection; |
3078 | 0 | b = r->header_in; |
3079 | |
|
3080 | 0 | if (b->pos < b->last) { |
3081 | | |
3082 | | /* the pipelined request */ |
3083 | |
|
3084 | 0 | if (b != c->buffer) { |
3085 | | |
3086 | | /* |
3087 | | * If the large header buffers were allocated while the previous |
3088 | | * request processing then we do not use c->buffer for |
3089 | | * the pipelined request (see ngx_http_create_request()). |
3090 | | * |
3091 | | * Now we would move the large header buffers to the free list. |
3092 | | */ |
3093 | |
|
3094 | 0 | for (cl = hc->busy; cl; /* void */) { |
3095 | 0 | ln = cl; |
3096 | 0 | cl = cl->next; |
3097 | |
|
3098 | 0 | if (ln->buf == b) { |
3099 | 0 | ngx_free_chain(c->pool, ln); |
3100 | 0 | continue; |
3101 | 0 | } |
3102 | | |
3103 | 0 | f = ln->buf; |
3104 | 0 | f->pos = f->start; |
3105 | 0 | f->last = f->start; |
3106 | |
|
3107 | 0 | ln->next = hc->free; |
3108 | 0 | hc->free = ln; |
3109 | 0 | } |
3110 | |
|
3111 | 0 | cl = ngx_alloc_chain_link(c->pool); |
3112 | 0 | if (cl == NULL) { |
3113 | 0 | ngx_http_close_request(r, 0); |
3114 | 0 | return; |
3115 | 0 | } |
3116 | | |
3117 | 0 | cl->buf = b; |
3118 | 0 | cl->next = NULL; |
3119 | |
|
3120 | 0 | hc->busy = cl; |
3121 | 0 | hc->nbusy = 1; |
3122 | 0 | } |
3123 | 0 | } |
3124 | | |
3125 | | /* guard against recursive call from ngx_http_finalize_connection() */ |
3126 | 0 | r->keepalive = 0; |
3127 | |
|
3128 | 0 | ngx_http_free_request(r, 0); |
3129 | |
|
3130 | 0 | c->data = hc; |
3131 | |
|
3132 | 0 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
3133 | 0 | ngx_http_close_connection(c); |
3134 | 0 | return; |
3135 | 0 | } |
3136 | | |
3137 | 0 | wev = c->write; |
3138 | 0 | wev->handler = ngx_http_empty_handler; |
3139 | |
|
3140 | 0 | if (b->pos < b->last) { |
3141 | |
|
3142 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request"); |
3143 | |
|
3144 | 0 | c->log->action = "reading client pipelined request line"; |
3145 | |
|
3146 | 0 | r = ngx_http_create_request(c); |
3147 | 0 | if (r == NULL) { |
3148 | 0 | ngx_http_close_connection(c); |
3149 | 0 | return; |
3150 | 0 | } |
3151 | | |
3152 | 0 | r->pipeline = 1; |
3153 | |
|
3154 | 0 | c->data = r; |
3155 | |
|
3156 | 0 | c->sent = 0; |
3157 | 0 | c->destroyed = 0; |
3158 | 0 | c->pipeline = 1; |
3159 | |
|
3160 | 0 | if (rev->timer_set) { |
3161 | 0 | ngx_del_timer(rev); |
3162 | 0 | } |
3163 | |
|
3164 | 0 | rev->handler = ngx_http_process_request_line; |
3165 | 0 | ngx_post_event(rev, &ngx_posted_events); |
3166 | 0 | return; |
3167 | 0 | } |
3168 | | |
3169 | | /* |
3170 | | * To keep a memory footprint as small as possible for an idle keepalive |
3171 | | * connection we try to free c->buffer's memory if it was allocated outside |
3172 | | * the c->pool. The large header buffers are always allocated outside the |
3173 | | * c->pool and are freed too. |
3174 | | */ |
3175 | | |
3176 | 0 | b = c->buffer; |
3177 | |
|
3178 | 0 | if (ngx_pfree(c->pool, b->start) == NGX_OK) { |
3179 | | |
3180 | | /* |
3181 | | * the special note for ngx_http_keepalive_handler() that |
3182 | | * c->buffer's memory was freed |
3183 | | */ |
3184 | |
|
3185 | 0 | b->pos = NULL; |
3186 | |
|
3187 | 0 | } else { |
3188 | 0 | b->pos = b->start; |
3189 | 0 | b->last = b->start; |
3190 | 0 | } |
3191 | |
|
3192 | 0 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc free: %p", |
3193 | 0 | hc->free); |
3194 | |
|
3195 | 0 | if (hc->free) { |
3196 | 0 | for (cl = hc->free; cl; /* void */) { |
3197 | 0 | ln = cl; |
3198 | 0 | cl = cl->next; |
3199 | 0 | ngx_pfree(c->pool, ln->buf->start); |
3200 | 0 | ngx_free_chain(c->pool, ln); |
3201 | 0 | } |
3202 | |
|
3203 | 0 | hc->free = NULL; |
3204 | 0 | } |
3205 | |
|
3206 | 0 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc busy: %p %i", |
3207 | 0 | hc->busy, hc->nbusy); |
3208 | |
|
3209 | 0 | if (hc->busy) { |
3210 | 0 | for (cl = hc->busy; cl; /* void */) { |
3211 | 0 | ln = cl; |
3212 | 0 | cl = cl->next; |
3213 | 0 | ngx_pfree(c->pool, ln->buf->start); |
3214 | 0 | ngx_free_chain(c->pool, ln); |
3215 | 0 | } |
3216 | |
|
3217 | 0 | hc->busy = NULL; |
3218 | 0 | hc->nbusy = 0; |
3219 | 0 | } |
3220 | |
|
3221 | | #if (NGX_HTTP_SSL) |
3222 | | if (c->ssl) { |
3223 | | ngx_ssl_free_buffer(c); |
3224 | | } |
3225 | | #endif |
3226 | |
|
3227 | 0 | rev->handler = ngx_http_keepalive_handler; |
3228 | |
|
3229 | 0 | if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { |
3230 | 0 | if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) { |
3231 | 0 | ngx_http_close_connection(c); |
3232 | 0 | return; |
3233 | 0 | } |
3234 | 0 | } |
3235 | | |
3236 | 0 | c->log->action = "keepalive"; |
3237 | |
|
3238 | 0 | if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { |
3239 | 0 | if (ngx_tcp_push(c->fd) == -1) { |
3240 | 0 | ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); |
3241 | 0 | ngx_http_close_connection(c); |
3242 | 0 | return; |
3243 | 0 | } |
3244 | | |
3245 | 0 | c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; |
3246 | 0 | tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; |
3247 | |
|
3248 | 0 | } else { |
3249 | 0 | tcp_nodelay = 1; |
3250 | 0 | } |
3251 | | |
3252 | 0 | if (tcp_nodelay && clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { |
3253 | 0 | ngx_http_close_connection(c); |
3254 | 0 | return; |
3255 | 0 | } |
3256 | | |
3257 | | #if 0 |
3258 | | /* if ngx_http_request_t was freed then we need some other place */ |
3259 | | r->http_state = NGX_HTTP_KEEPALIVE_STATE; |
3260 | | #endif |
3261 | | |
3262 | 0 | c->idle = 1; |
3263 | 0 | ngx_reusable_connection(c, 1); |
3264 | |
|
3265 | 0 | ngx_add_timer(rev, clcf->keepalive_timeout); |
3266 | |
|
3267 | 0 | if (rev->ready) { |
3268 | 0 | ngx_post_event(rev, &ngx_posted_events); |
3269 | 0 | } |
3270 | 0 | } |
3271 | | |
3272 | | |
3273 | | static void |
3274 | | ngx_http_keepalive_handler(ngx_event_t *rev) |
3275 | 0 | { |
3276 | 0 | size_t size; |
3277 | 0 | ssize_t n; |
3278 | 0 | ngx_buf_t *b; |
3279 | 0 | ngx_connection_t *c; |
3280 | |
|
3281 | 0 | c = rev->data; |
3282 | |
|
3283 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http keepalive handler"); |
3284 | |
|
3285 | 0 | if (rev->timedout || c->close) { |
3286 | 0 | ngx_http_close_connection(c); |
3287 | 0 | return; |
3288 | 0 | } |
3289 | | |
3290 | | #if (NGX_HAVE_KQUEUE) |
3291 | | |
3292 | | if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { |
3293 | | if (rev->pending_eof) { |
3294 | | c->log->handler = NULL; |
3295 | | ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, |
3296 | | "kevent() reported that client %V closed " |
3297 | | "keepalive connection", &c->addr_text); |
3298 | | #if (NGX_HTTP_SSL) |
3299 | | if (c->ssl) { |
3300 | | c->ssl->no_send_shutdown = 1; |
3301 | | } |
3302 | | #endif |
3303 | | ngx_http_close_connection(c); |
3304 | | return; |
3305 | | } |
3306 | | } |
3307 | | |
3308 | | #endif |
3309 | | |
3310 | 0 | b = c->buffer; |
3311 | 0 | size = b->end - b->start; |
3312 | |
|
3313 | 0 | if (b->pos == NULL) { |
3314 | | |
3315 | | /* |
3316 | | * The c->buffer's memory was freed by ngx_http_set_keepalive(). |
3317 | | * However, the c->buffer->start and c->buffer->end were not changed |
3318 | | * to keep the buffer size. |
3319 | | */ |
3320 | |
|
3321 | 0 | b->pos = ngx_palloc(c->pool, size); |
3322 | 0 | if (b->pos == NULL) { |
3323 | 0 | ngx_http_close_connection(c); |
3324 | 0 | return; |
3325 | 0 | } |
3326 | | |
3327 | 0 | b->start = b->pos; |
3328 | 0 | b->last = b->pos; |
3329 | 0 | b->end = b->pos + size; |
3330 | 0 | } |
3331 | | |
3332 | | /* |
3333 | | * MSIE closes a keepalive connection with RST flag |
3334 | | * so we ignore ECONNRESET here. |
3335 | | */ |
3336 | | |
3337 | 0 | c->log_error = NGX_ERROR_IGNORE_ECONNRESET; |
3338 | 0 | ngx_set_socket_errno(0); |
3339 | |
|
3340 | 0 | n = c->recv(c, b->last, size); |
3341 | 0 | c->log_error = NGX_ERROR_INFO; |
3342 | |
|
3343 | 0 | if (n == NGX_AGAIN) { |
3344 | 0 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
3345 | 0 | ngx_http_close_connection(c); |
3346 | 0 | return; |
3347 | 0 | } |
3348 | | |
3349 | | /* |
3350 | | * Like ngx_http_set_keepalive() we are trying to not hold |
3351 | | * c->buffer's memory for a keepalive connection. |
3352 | | */ |
3353 | | |
3354 | 0 | if (ngx_pfree(c->pool, b->start) == NGX_OK) { |
3355 | | |
3356 | | /* |
3357 | | * the special note that c->buffer's memory was freed |
3358 | | */ |
3359 | |
|
3360 | 0 | b->pos = NULL; |
3361 | 0 | } |
3362 | |
|
3363 | 0 | return; |
3364 | 0 | } |
3365 | | |
3366 | 0 | if (n == NGX_ERROR) { |
3367 | 0 | ngx_http_close_connection(c); |
3368 | 0 | return; |
3369 | 0 | } |
3370 | | |
3371 | 0 | c->log->handler = NULL; |
3372 | |
|
3373 | 0 | if (n == 0) { |
3374 | 0 | ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno, |
3375 | 0 | "client %V closed keepalive connection", &c->addr_text); |
3376 | 0 | ngx_http_close_connection(c); |
3377 | 0 | return; |
3378 | 0 | } |
3379 | | |
3380 | 0 | b->last += n; |
3381 | |
|
3382 | 0 | c->log->handler = ngx_http_log_error; |
3383 | 0 | c->log->action = "reading client request line"; |
3384 | |
|
3385 | 0 | c->idle = 0; |
3386 | 0 | ngx_reusable_connection(c, 0); |
3387 | |
|
3388 | 0 | c->data = ngx_http_create_request(c); |
3389 | 0 | if (c->data == NULL) { |
3390 | 0 | ngx_http_close_connection(c); |
3391 | 0 | return; |
3392 | 0 | } |
3393 | | |
3394 | 0 | c->sent = 0; |
3395 | 0 | c->destroyed = 0; |
3396 | |
|
3397 | 0 | ngx_del_timer(rev); |
3398 | |
|
3399 | 0 | rev->handler = ngx_http_process_request_line; |
3400 | 0 | ngx_http_process_request_line(rev); |
3401 | 0 | } |
3402 | | |
3403 | | |
3404 | | static void |
3405 | | ngx_http_set_lingering_close(ngx_connection_t *c) |
3406 | 7 | { |
3407 | 7 | ngx_event_t *rev, *wev; |
3408 | 7 | ngx_http_request_t *r; |
3409 | 7 | ngx_http_core_loc_conf_t *clcf; |
3410 | | |
3411 | 7 | r = c->data; |
3412 | | |
3413 | 7 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
3414 | | |
3415 | 7 | if (r->lingering_time == 0) { |
3416 | 7 | r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); |
3417 | 7 | } |
3418 | | |
3419 | | #if (NGX_HTTP_SSL) |
3420 | | if (c->ssl) { |
3421 | | ngx_int_t rc; |
3422 | | |
3423 | | c->ssl->shutdown_without_free = 1; |
3424 | | |
3425 | | rc = ngx_ssl_shutdown(c); |
3426 | | |
3427 | | if (rc == NGX_ERROR) { |
3428 | | ngx_http_close_request(r, 0); |
3429 | | return; |
3430 | | } |
3431 | | |
3432 | | if (rc == NGX_AGAIN) { |
3433 | | c->ssl->handler = ngx_http_set_lingering_close; |
3434 | | return; |
3435 | | } |
3436 | | } |
3437 | | #endif |
3438 | | |
3439 | 7 | rev = c->read; |
3440 | 7 | rev->handler = ngx_http_lingering_close_handler; |
3441 | | |
3442 | 7 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
3443 | 0 | ngx_http_close_request(r, 0); |
3444 | 0 | return; |
3445 | 0 | } |
3446 | | |
3447 | 7 | wev = c->write; |
3448 | 7 | wev->handler = ngx_http_empty_handler; |
3449 | | |
3450 | 7 | if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { |
3451 | 0 | if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) { |
3452 | 0 | ngx_http_close_request(r, 0); |
3453 | 0 | return; |
3454 | 0 | } |
3455 | 0 | } |
3456 | | |
3457 | 7 | if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { |
3458 | 0 | ngx_connection_error(c, ngx_socket_errno, |
3459 | 0 | ngx_shutdown_socket_n " failed"); |
3460 | 0 | ngx_http_close_request(r, 0); |
3461 | 0 | return; |
3462 | 0 | } |
3463 | | |
3464 | 7 | c->close = 0; |
3465 | 7 | ngx_reusable_connection(c, 1); |
3466 | | |
3467 | 7 | ngx_add_timer(rev, clcf->lingering_timeout); |
3468 | | |
3469 | 7 | if (rev->ready) { |
3470 | 7 | ngx_http_lingering_close_handler(rev); |
3471 | 7 | } |
3472 | 7 | } |
3473 | | |
3474 | | |
3475 | | static void |
3476 | | ngx_http_lingering_close_handler(ngx_event_t *rev) |
3477 | 7 | { |
3478 | 7 | ssize_t n; |
3479 | 7 | ngx_msec_t timer; |
3480 | 7 | ngx_connection_t *c; |
3481 | 7 | ngx_http_request_t *r; |
3482 | 7 | ngx_http_core_loc_conf_t *clcf; |
3483 | 7 | u_char buffer[NGX_HTTP_LINGERING_BUFFER_SIZE]; |
3484 | | |
3485 | 7 | c = rev->data; |
3486 | 7 | r = c->data; |
3487 | | |
3488 | 7 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
3489 | 7 | "http lingering close handler"); |
3490 | | |
3491 | 7 | if (rev->timedout || c->close) { |
3492 | 0 | ngx_http_close_request(r, 0); |
3493 | 0 | return; |
3494 | 0 | } |
3495 | | |
3496 | 7 | timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); |
3497 | 7 | if ((ngx_msec_int_t) timer <= 0) { |
3498 | 0 | ngx_http_close_request(r, 0); |
3499 | 0 | return; |
3500 | 0 | } |
3501 | | |
3502 | 23 | do { |
3503 | 23 | n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE); |
3504 | | |
3505 | 23 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n); |
3506 | | |
3507 | 23 | if (n == NGX_AGAIN) { |
3508 | 0 | break; |
3509 | 0 | } |
3510 | | |
3511 | 23 | if (n == NGX_ERROR || n == 0) { |
3512 | 7 | ngx_http_close_request(r, 0); |
3513 | 7 | return; |
3514 | 7 | } |
3515 | | |
3516 | 23 | } while (rev->ready); |
3517 | | |
3518 | 0 | if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
3519 | 0 | ngx_http_close_request(r, 0); |
3520 | 0 | return; |
3521 | 0 | } |
3522 | | |
3523 | 0 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
3524 | |
|
3525 | 0 | timer *= 1000; |
3526 | |
|
3527 | 0 | if (timer > clcf->lingering_timeout) { |
3528 | 0 | timer = clcf->lingering_timeout; |
3529 | 0 | } |
3530 | |
|
3531 | 0 | ngx_add_timer(rev, timer); |
3532 | 0 | } |
3533 | | |
3534 | | |
3535 | | void |
3536 | | ngx_http_empty_handler(ngx_event_t *wev) |
3537 | 0 | { |
3538 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http empty handler"); |
3539 | |
|
3540 | 0 | return; |
3541 | 0 | } |
3542 | | |
3543 | | |
3544 | | void |
3545 | | ngx_http_request_empty_handler(ngx_http_request_t *r) |
3546 | 0 | { |
3547 | 0 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
3548 | 0 | "http request empty handler"); |
3549 | |
|
3550 | 0 | return; |
3551 | 0 | } |
3552 | | |
3553 | | |
3554 | | ngx_int_t |
3555 | | ngx_http_send_special(ngx_http_request_t *r, ngx_uint_t flags) |
3556 | 1 | { |
3557 | 1 | ngx_buf_t *b; |
3558 | 1 | ngx_chain_t out; |
3559 | | |
3560 | 1 | b = ngx_calloc_buf(r->pool); |
3561 | 1 | if (b == NULL) { |
3562 | 0 | return NGX_ERROR; |
3563 | 0 | } |
3564 | | |
3565 | 1 | if (flags & NGX_HTTP_LAST) { |
3566 | |
|
3567 | 0 | if (r == r->main && !r->post_action) { |
3568 | 0 | b->last_buf = 1; |
3569 | |
|
3570 | 0 | } else { |
3571 | 0 | b->sync = 1; |
3572 | 0 | b->last_in_chain = 1; |
3573 | 0 | } |
3574 | 0 | } |
3575 | | |
3576 | 1 | if (flags & NGX_HTTP_FLUSH) { |
3577 | 1 | b->flush = 1; |
3578 | 1 | } |
3579 | | |
3580 | 1 | out.buf = b; |
3581 | 1 | out.next = NULL; |
3582 | | |
3583 | 1 | return ngx_http_output_filter(r, &out); |
3584 | 1 | } |
3585 | | |
3586 | | |
3587 | | static ngx_int_t |
3588 | | ngx_http_post_action(ngx_http_request_t *r) |
3589 | 9 | { |
3590 | 9 | ngx_http_core_loc_conf_t *clcf; |
3591 | | |
3592 | 9 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
3593 | | |
3594 | 9 | if (clcf->post_action.data == NULL) { |
3595 | 9 | return NGX_DECLINED; |
3596 | 9 | } |
3597 | | |
3598 | 0 | if (r->post_action && r->uri_changes == 0) { |
3599 | 0 | return NGX_DECLINED; |
3600 | 0 | } |
3601 | | |
3602 | 0 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
3603 | 0 | "post action: \"%V\"", &clcf->post_action); |
3604 | |
|
3605 | 0 | r->main->count--; |
3606 | |
|
3607 | 0 | r->http_version = NGX_HTTP_VERSION_9; |
3608 | 0 | r->header_only = 1; |
3609 | 0 | r->post_action = 1; |
3610 | |
|
3611 | 0 | r->read_event_handler = ngx_http_block_reading; |
3612 | |
|
3613 | 0 | if (clcf->post_action.data[0] == '/') { |
3614 | 0 | ngx_http_internal_redirect(r, &clcf->post_action, NULL); |
3615 | |
|
3616 | 0 | } else { |
3617 | 0 | ngx_http_named_location(r, &clcf->post_action); |
3618 | 0 | } |
3619 | |
|
3620 | 0 | return NGX_OK; |
3621 | 0 | } |
3622 | | |
3623 | | |
3624 | | void |
3625 | | ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) |
3626 | 21 | { |
3627 | 21 | ngx_connection_t *c; |
3628 | | |
3629 | 21 | r = r->main; |
3630 | 21 | c = r->connection; |
3631 | | |
3632 | 21 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
3633 | 21 | "http request count:%d blk:%d", r->count, r->blocked); |
3634 | | |
3635 | 21 | if (r->count == 0) { |
3636 | 0 | ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero"); |
3637 | 0 | } |
3638 | | |
3639 | 21 | r->count--; |
3640 | | |
3641 | 21 | if (r->count || r->blocked) { |
3642 | 5 | return; |
3643 | 5 | } |
3644 | | |
3645 | 16 | #if (NGX_HTTP_V2) |
3646 | 16 | if (r->stream) { |
3647 | 0 | ngx_http_v2_close_stream(r->stream, rc); |
3648 | 0 | return; |
3649 | 0 | } |
3650 | 16 | #endif |
3651 | | |
3652 | 16 | ngx_http_free_request(r, rc); |
3653 | 16 | ngx_http_close_connection(c); |
3654 | 16 | } |
3655 | | |
3656 | | |
3657 | | void |
3658 | | ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) |
3659 | 16 | { |
3660 | 16 | ngx_log_t *log; |
3661 | 16 | ngx_pool_t *pool; |
3662 | 16 | struct linger linger; |
3663 | 16 | ngx_http_cleanup_t *cln; |
3664 | 16 | ngx_http_log_ctx_t *ctx; |
3665 | 16 | ngx_http_core_loc_conf_t *clcf; |
3666 | | |
3667 | 16 | log = r->connection->log; |
3668 | | |
3669 | 16 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http close request"); |
3670 | | |
3671 | 16 | if (r->pool == NULL) { |
3672 | 0 | ngx_log_error(NGX_LOG_ALERT, log, 0, "http request already closed"); |
3673 | 0 | return; |
3674 | 0 | } |
3675 | | |
3676 | 16 | cln = r->cleanup; |
3677 | 16 | r->cleanup = NULL; |
3678 | | |
3679 | 16 | while (cln) { |
3680 | 0 | if (cln->handler) { |
3681 | 0 | cln->handler(cln->data); |
3682 | 0 | } |
3683 | |
|
3684 | 0 | cln = cln->next; |
3685 | 0 | } |
3686 | | |
3687 | | #if (NGX_STAT_STUB) |
3688 | | |
3689 | | if (r->stat_reading) { |
3690 | | (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); |
3691 | | } |
3692 | | |
3693 | | if (r->stat_writing) { |
3694 | | (void) ngx_atomic_fetch_add(ngx_stat_writing, -1); |
3695 | | } |
3696 | | |
3697 | | #endif |
3698 | | |
3699 | 16 | if (rc > 0 && (r->headers_out.status == 0 || r->connection->sent == 0)) { |
3700 | 3 | r->headers_out.status = rc; |
3701 | 3 | } |
3702 | | |
3703 | 16 | if (!r->logged) { |
3704 | 16 | log->action = "logging request"; |
3705 | | |
3706 | 16 | ngx_http_log_request(r); |
3707 | 16 | } |
3708 | | |
3709 | 16 | log->action = "closing request"; |
3710 | | |
3711 | 16 | if (r->connection->timedout |
3712 | | #if (NGX_HTTP_V3) |
3713 | | && r->connection->quic == NULL |
3714 | | #endif |
3715 | 16 | ) |
3716 | 0 | { |
3717 | 0 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
3718 | |
|
3719 | 0 | if (clcf->reset_timedout_connection) { |
3720 | 0 | linger.l_onoff = 1; |
3721 | 0 | linger.l_linger = 0; |
3722 | |
|
3723 | 0 | if (setsockopt(r->connection->fd, SOL_SOCKET, SO_LINGER, |
3724 | 0 | (const void *) &linger, sizeof(struct linger)) == -1) |
3725 | 0 | { |
3726 | 0 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, |
3727 | 0 | "setsockopt(SO_LINGER) failed"); |
3728 | 0 | } |
3729 | 0 | } |
3730 | 0 | } |
3731 | | |
3732 | | /* the various request strings were allocated from r->pool */ |
3733 | 16 | ctx = log->data; |
3734 | 16 | ctx->request = NULL; |
3735 | | |
3736 | 16 | r->request_line.len = 0; |
3737 | | |
3738 | 16 | r->connection->destroyed = 1; |
3739 | | |
3740 | | /* |
3741 | | * Setting r->pool to NULL will increase probability to catch double close |
3742 | | * of request since the request object is allocated from its own pool. |
3743 | | */ |
3744 | | |
3745 | 16 | pool = r->pool; |
3746 | 16 | r->pool = NULL; |
3747 | | |
3748 | 16 | ngx_destroy_pool(pool); |
3749 | 16 | } |
3750 | | |
3751 | | |
3752 | | static void |
3753 | | ngx_http_log_request(ngx_http_request_t *r) |
3754 | 16 | { |
3755 | 16 | ngx_uint_t i, n; |
3756 | 16 | ngx_http_handler_pt *log_handler; |
3757 | 16 | ngx_http_core_main_conf_t *cmcf; |
3758 | | |
3759 | 16 | cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); |
3760 | | |
3761 | 16 | log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts; |
3762 | 16 | n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts; |
3763 | | |
3764 | 32 | for (i = 0; i < n; i++) { |
3765 | 16 | log_handler[i](r); |
3766 | 16 | } |
3767 | 16 | } |
3768 | | |
3769 | | |
3770 | | void |
3771 | | ngx_http_close_connection(ngx_connection_t *c) |
3772 | 16 | { |
3773 | 16 | ngx_pool_t *pool; |
3774 | | |
3775 | 16 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
3776 | 16 | "close http connection: %d", c->fd); |
3777 | | |
3778 | | #if (NGX_HTTP_SSL) |
3779 | | |
3780 | | if (c->ssl) { |
3781 | | if (ngx_ssl_shutdown(c) == NGX_AGAIN) { |
3782 | | c->ssl->handler = ngx_http_close_connection; |
3783 | | return; |
3784 | | } |
3785 | | } |
3786 | | |
3787 | | #endif |
3788 | | |
3789 | | #if (NGX_HTTP_V3) |
3790 | | if (c->quic) { |
3791 | | ngx_http_v3_reset_stream(c); |
3792 | | } |
3793 | | #endif |
3794 | | |
3795 | | #if (NGX_STAT_STUB) |
3796 | | (void) ngx_atomic_fetch_add(ngx_stat_active, -1); |
3797 | | #endif |
3798 | | |
3799 | 16 | c->destroyed = 1; |
3800 | | |
3801 | 16 | pool = c->pool; |
3802 | | |
3803 | 16 | ngx_close_connection(c); |
3804 | | |
3805 | 16 | ngx_destroy_pool(pool); |
3806 | 16 | } |
3807 | | |
3808 | | |
3809 | | static u_char * |
3810 | | ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) |
3811 | 0 | { |
3812 | 0 | u_char *p; |
3813 | 0 | ngx_http_request_t *r; |
3814 | 0 | ngx_http_log_ctx_t *ctx; |
3815 | |
|
3816 | 0 | if (log->action) { |
3817 | 0 | p = ngx_snprintf(buf, len, " while %s", log->action); |
3818 | 0 | len -= p - buf; |
3819 | 0 | buf = p; |
3820 | 0 | } |
3821 | |
|
3822 | 0 | ctx = log->data; |
3823 | |
|
3824 | 0 | p = ngx_snprintf(buf, len, ", client: %V", &ctx->connection->addr_text); |
3825 | 0 | len -= p - buf; |
3826 | |
|
3827 | 0 | r = ctx->request; |
3828 | |
|
3829 | 0 | if (r) { |
3830 | 0 | return r->log_handler(r, ctx->current_request, p, len); |
3831 | |
|
3832 | 0 | } else { |
3833 | 0 | p = ngx_snprintf(p, len, ", server: %V", |
3834 | 0 | &ctx->connection->listening->addr_text); |
3835 | 0 | } |
3836 | | |
3837 | 0 | return p; |
3838 | 0 | } |
3839 | | |
3840 | | |
3841 | | static u_char * |
3842 | | ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, |
3843 | | u_char *buf, size_t len) |
3844 | 0 | { |
3845 | 0 | char *uri_separator; |
3846 | 0 | u_char *p; |
3847 | 0 | ngx_http_upstream_t *u; |
3848 | 0 | ngx_http_core_srv_conf_t *cscf; |
3849 | |
|
3850 | 0 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
3851 | |
|
3852 | 0 | p = ngx_snprintf(buf, len, ", server: %V", &cscf->server_name); |
3853 | 0 | len -= p - buf; |
3854 | 0 | buf = p; |
3855 | |
|
3856 | 0 | if (r->request_line.data == NULL && r->request_start) { |
3857 | 0 | for (p = r->request_start; p < r->header_in->last; p++) { |
3858 | 0 | if (*p == CR || *p == LF) { |
3859 | 0 | break; |
3860 | 0 | } |
3861 | 0 | } |
3862 | |
|
3863 | 0 | r->request_line.len = p - r->request_start; |
3864 | 0 | r->request_line.data = r->request_start; |
3865 | 0 | } |
3866 | |
|
3867 | 0 | if (r->request_line.len) { |
3868 | 0 | p = ngx_snprintf(buf, len, ", request: \"%V\"", &r->request_line); |
3869 | 0 | len -= p - buf; |
3870 | 0 | buf = p; |
3871 | 0 | } |
3872 | |
|
3873 | 0 | if (r != sr) { |
3874 | 0 | p = ngx_snprintf(buf, len, ", subrequest: \"%V\"", &sr->uri); |
3875 | 0 | len -= p - buf; |
3876 | 0 | buf = p; |
3877 | 0 | } |
3878 | |
|
3879 | 0 | u = sr->upstream; |
3880 | |
|
3881 | 0 | if (u && u->peer.name) { |
3882 | |
|
3883 | 0 | uri_separator = ""; |
3884 | |
|
3885 | 0 | #if (NGX_HAVE_UNIX_DOMAIN) |
3886 | 0 | if (u->peer.sockaddr && u->peer.sockaddr->sa_family == AF_UNIX) { |
3887 | 0 | uri_separator = ":"; |
3888 | 0 | } |
3889 | 0 | #endif |
3890 | |
|
3891 | 0 | p = ngx_snprintf(buf, len, ", upstream: \"%V%V%s%V\"", |
3892 | 0 | &u->schema, u->peer.name, |
3893 | 0 | uri_separator, &u->uri); |
3894 | 0 | len -= p - buf; |
3895 | 0 | buf = p; |
3896 | 0 | } |
3897 | |
|
3898 | 0 | if (r->headers_in.host) { |
3899 | 0 | p = ngx_snprintf(buf, len, ", host: \"%V\"", |
3900 | 0 | &r->headers_in.host->value); |
3901 | 0 | len -= p - buf; |
3902 | 0 | buf = p; |
3903 | 0 | } |
3904 | |
|
3905 | 0 | if (r->headers_in.referer) { |
3906 | 0 | p = ngx_snprintf(buf, len, ", referrer: \"%V\"", |
3907 | 0 | &r->headers_in.referer->value); |
3908 | 0 | buf = p; |
3909 | 0 | } |
3910 | |
|
3911 | 0 | return buf; |
3912 | 0 | } |