Mercurial > hg > nginx
annotate src/http/modules/ngx_http_upstream_keepalive_module.c @ 5204:a64c8a5da336
PCRE: retain input pattern for all regular expressions.
Previously, input pattern was kept only for regular expressions
with named captures, which resulted in error log entries without
input pattern for PCRE errors that occured while processing
regular expressions without them.
Signed-off-by: Piotr Sikora <piotr@cloudflare.com>
author | Piotr Sikora <piotr@cloudflare.com> |
---|---|
date | Thu, 02 May 2013 03:26:36 -0700 |
parents | 089a662c17d1 |
children | 822b82191940 |
rev | line source |
---|---|
4127 | 1 |
2 /* | |
3 * Copyright (C) Maxim Dounin | |
4412 | 4 * Copyright (C) Nginx, Inc. |
4127 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
14 ngx_uint_t max_cached; | |
15 | |
16 ngx_queue_t cache; | |
17 ngx_queue_t free; | |
18 | |
19 ngx_http_upstream_init_pt original_init_upstream; | |
20 ngx_http_upstream_init_peer_pt original_init_peer; | |
21 | |
22 } ngx_http_upstream_keepalive_srv_conf_t; | |
23 | |
24 | |
25 typedef struct { | |
26 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
27 | |
28 ngx_http_upstream_t *upstream; | |
29 | |
30 void *data; | |
31 | |
32 ngx_event_get_peer_pt original_get_peer; | |
33 ngx_event_free_peer_pt original_free_peer; | |
34 | |
35 #if (NGX_HTTP_SSL) | |
36 ngx_event_set_peer_session_pt original_set_session; | |
37 ngx_event_save_peer_session_pt original_save_session; | |
38 #endif | |
39 | |
40 } ngx_http_upstream_keepalive_peer_data_t; | |
41 | |
42 | |
43 typedef struct { | |
44 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
45 | |
46 ngx_queue_t queue; | |
47 ngx_connection_t *connection; | |
48 | |
49 socklen_t socklen; | |
50 u_char sockaddr[NGX_SOCKADDRLEN]; | |
51 | |
52 } ngx_http_upstream_keepalive_cache_t; | |
53 | |
54 | |
55 static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r, | |
56 ngx_http_upstream_srv_conf_t *us); | |
57 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, | |
58 void *data); | |
59 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, | |
60 void *data, ngx_uint_t state); | |
61 | |
62 static void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev); | |
63 static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev); | |
64 static void ngx_http_upstream_keepalive_close(ngx_connection_t *c); | |
65 | |
66 | |
67 #if (NGX_HTTP_SSL) | |
68 static ngx_int_t ngx_http_upstream_keepalive_set_session( | |
69 ngx_peer_connection_t *pc, void *data); | |
70 static void ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, | |
71 void *data); | |
72 #endif | |
73 | |
74 static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf); | |
75 static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, | |
76 void *conf); | |
77 | |
78 | |
79 static ngx_command_t ngx_http_upstream_keepalive_commands[] = { | |
80 | |
81 { ngx_string("keepalive"), | |
82 NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, | |
83 ngx_http_upstream_keepalive, | |
84 0, | |
85 0, | |
86 NULL }, | |
87 | |
88 ngx_null_command | |
89 }; | |
90 | |
91 | |
92 static ngx_http_module_t ngx_http_upstream_keepalive_module_ctx = { | |
93 NULL, /* preconfiguration */ | |
94 NULL, /* postconfiguration */ | |
95 | |
96 NULL, /* create main configuration */ | |
97 NULL, /* init main configuration */ | |
98 | |
99 ngx_http_upstream_keepalive_create_conf, /* create server configuration */ | |
100 NULL, /* merge server configuration */ | |
101 | |
102 NULL, /* create location configuration */ | |
103 NULL /* merge location configuration */ | |
104 }; | |
105 | |
106 | |
107 ngx_module_t ngx_http_upstream_keepalive_module = { | |
108 NGX_MODULE_V1, | |
109 &ngx_http_upstream_keepalive_module_ctx, /* module context */ | |
110 ngx_http_upstream_keepalive_commands, /* module directives */ | |
111 NGX_HTTP_MODULE, /* module type */ | |
112 NULL, /* init master */ | |
113 NULL, /* init module */ | |
114 NULL, /* init process */ | |
115 NULL, /* init thread */ | |
116 NULL, /* exit thread */ | |
117 NULL, /* exit process */ | |
118 NULL, /* exit master */ | |
119 NGX_MODULE_V1_PADDING | |
120 }; | |
121 | |
122 | |
123 static ngx_int_t | |
124 ngx_http_upstream_init_keepalive(ngx_conf_t *cf, | |
125 ngx_http_upstream_srv_conf_t *us) | |
126 { | |
127 ngx_uint_t i; | |
128 ngx_http_upstream_keepalive_srv_conf_t *kcf; | |
129 ngx_http_upstream_keepalive_cache_t *cached; | |
130 | |
131 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, | |
132 "init keepalive"); | |
133 | |
134 kcf = ngx_http_conf_upstream_srv_conf(us, | |
135 ngx_http_upstream_keepalive_module); | |
136 | |
137 if (kcf->original_init_upstream(cf, us) != NGX_OK) { | |
138 return NGX_ERROR; | |
139 } | |
140 | |
141 kcf->original_init_peer = us->peer.init; | |
142 | |
143 us->peer.init = ngx_http_upstream_init_keepalive_peer; | |
144 | |
145 /* allocate cache items and add to free queue */ | |
146 | |
147 cached = ngx_pcalloc(cf->pool, | |
148 sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached); | |
149 if (cached == NULL) { | |
150 return NGX_ERROR; | |
151 } | |
152 | |
153 ngx_queue_init(&kcf->cache); | |
154 ngx_queue_init(&kcf->free); | |
155 | |
156 for (i = 0; i < kcf->max_cached; i++) { | |
157 ngx_queue_insert_head(&kcf->free, &cached[i].queue); | |
158 cached[i].conf = kcf; | |
159 } | |
160 | |
161 return NGX_OK; | |
162 } | |
163 | |
164 | |
165 static ngx_int_t | |
166 ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r, | |
167 ngx_http_upstream_srv_conf_t *us) | |
168 { | |
169 ngx_http_upstream_keepalive_peer_data_t *kp; | |
170 ngx_http_upstream_keepalive_srv_conf_t *kcf; | |
171 | |
172 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
173 "init keepalive peer"); | |
174 | |
175 kcf = ngx_http_conf_upstream_srv_conf(us, | |
176 ngx_http_upstream_keepalive_module); | |
177 | |
178 kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t)); | |
179 if (kp == NULL) { | |
180 return NGX_ERROR; | |
181 } | |
182 | |
183 if (kcf->original_init_peer(r, us) != NGX_OK) { | |
184 return NGX_ERROR; | |
185 } | |
186 | |
187 kp->conf = kcf; | |
188 kp->upstream = r->upstream; | |
189 kp->data = r->upstream->peer.data; | |
190 kp->original_get_peer = r->upstream->peer.get; | |
191 kp->original_free_peer = r->upstream->peer.free; | |
192 | |
193 r->upstream->peer.data = kp; | |
194 r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer; | |
195 r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer; | |
196 | |
197 #if (NGX_HTTP_SSL) | |
198 kp->original_set_session = r->upstream->peer.set_session; | |
199 kp->original_save_session = r->upstream->peer.save_session; | |
200 r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session; | |
201 r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session; | |
202 #endif | |
203 | |
204 return NGX_OK; | |
205 } | |
206 | |
207 | |
208 static ngx_int_t | |
209 ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) | |
210 { | |
211 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
212 ngx_http_upstream_keepalive_cache_t *item; | |
213 | |
214 ngx_int_t rc; | |
215 ngx_queue_t *q, *cache; | |
216 ngx_connection_t *c; | |
217 | |
218 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
219 "get keepalive peer"); | |
220 | |
4694
5b5c07dee156
Upstream keepalive: "single" parameter deprecated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
221 /* ask balancer */ |
4127 | 222 |
223 rc = kp->original_get_peer(pc, kp->data); | |
224 | |
4694
5b5c07dee156
Upstream keepalive: "single" parameter deprecated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
225 if (rc != NGX_OK) { |
4127 | 226 return rc; |
227 } | |
228 | |
229 /* search cache for suitable connection */ | |
230 | |
231 cache = &kp->conf->cache; | |
232 | |
233 for (q = ngx_queue_head(cache); | |
234 q != ngx_queue_sentinel(cache); | |
235 q = ngx_queue_next(q)) | |
236 { | |
237 item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); | |
238 c = item->connection; | |
239 | |
240 if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr, | |
241 item->socklen, pc->socklen) | |
242 == 0) | |
243 { | |
244 ngx_queue_remove(q); | |
245 ngx_queue_insert_head(&kp->conf->free, q); | |
246 | |
247 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
248 "get keepalive peer: using connection %p", c); | |
249 | |
250 c->idle = 0; | |
251 c->log = pc->log; | |
252 c->read->log = pc->log; | |
253 c->write->log = pc->log; | |
254 c->pool->log = pc->log; | |
255 | |
256 pc->connection = c; | |
257 pc->cached = 1; | |
258 | |
259 return NGX_DONE; | |
260 } | |
261 } | |
262 | |
263 return NGX_OK; | |
264 } | |
265 | |
266 | |
267 static void | |
268 ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, | |
269 ngx_uint_t state) | |
270 { | |
271 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
272 ngx_http_upstream_keepalive_cache_t *item; | |
273 | |
274 ngx_queue_t *q; | |
275 ngx_connection_t *c; | |
276 ngx_http_upstream_t *u; | |
277 | |
278 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
279 "free keepalive peer"); | |
280 | |
281 /* cache valid connections */ | |
282 | |
283 u = kp->upstream; | |
284 c = pc->connection; | |
285 | |
5133
089a662c17d1
Upstream: removed double-free workarounds in peer.free() methods.
Ruslan Ermilov <ru@nginx.com>
parents:
4998
diff
changeset
|
286 if (state & NGX_PEER_FAILED |
4127 | 287 || c == NULL |
288 || c->read->eof | |
289 || c->read->error | |
290 || c->read->timedout | |
291 || c->write->error | |
292 || c->write->timedout) | |
293 { | |
294 goto invalid; | |
295 } | |
296 | |
297 if (!u->keepalive) { | |
298 goto invalid; | |
299 } | |
300 | |
301 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
302 goto invalid; | |
303 } | |
304 | |
305 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
306 "free keepalive peer: saving connection %p", c); | |
307 | |
308 if (ngx_queue_empty(&kp->conf->free)) { | |
309 | |
310 q = ngx_queue_last(&kp->conf->cache); | |
311 ngx_queue_remove(q); | |
312 | |
313 item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); | |
314 | |
315 ngx_http_upstream_keepalive_close(item->connection); | |
316 | |
317 } else { | |
318 q = ngx_queue_head(&kp->conf->free); | |
319 ngx_queue_remove(q); | |
320 | |
321 item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); | |
322 } | |
323 | |
324 item->connection = c; | |
325 ngx_queue_insert_head(&kp->conf->cache, q); | |
326 | |
327 pc->connection = NULL; | |
328 | |
329 if (c->read->timer_set) { | |
330 ngx_del_timer(c->read); | |
331 } | |
332 if (c->write->timer_set) { | |
333 ngx_del_timer(c->write); | |
334 } | |
335 | |
336 c->write->handler = ngx_http_upstream_keepalive_dummy_handler; | |
337 c->read->handler = ngx_http_upstream_keepalive_close_handler; | |
338 | |
339 c->data = item; | |
340 c->idle = 1; | |
341 c->log = ngx_cycle->log; | |
342 c->read->log = ngx_cycle->log; | |
343 c->write->log = ngx_cycle->log; | |
344 c->pool->log = ngx_cycle->log; | |
345 | |
346 item->socklen = pc->socklen; | |
347 ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); | |
348 | |
349 if (c->read->ready) { | |
350 ngx_http_upstream_keepalive_close_handler(c->read); | |
351 } | |
352 | |
353 invalid: | |
354 | |
355 kp->original_free_peer(pc, kp->data, state); | |
356 } | |
357 | |
358 | |
359 static void | |
360 ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev) | |
361 { | |
362 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, | |
363 "keepalive dummy handler"); | |
364 } | |
365 | |
366 | |
367 static void | |
368 ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev) | |
369 { | |
370 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
371 ngx_http_upstream_keepalive_cache_t *item; | |
372 | |
373 int n; | |
374 char buf[1]; | |
375 ngx_connection_t *c; | |
376 | |
377 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, | |
378 "keepalive close handler"); | |
379 | |
380 c = ev->data; | |
381 | |
382 if (c->close) { | |
383 goto close; | |
384 } | |
385 | |
386 n = recv(c->fd, buf, 1, MSG_PEEK); | |
387 | |
388 if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { | |
389 /* stale event */ | |
390 | |
391 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
392 goto close; | |
393 } | |
394 | |
395 return; | |
396 } | |
397 | |
398 close: | |
399 | |
400 item = c->data; | |
401 conf = item->conf; | |
402 | |
403 ngx_http_upstream_keepalive_close(c); | |
404 | |
405 ngx_queue_remove(&item->queue); | |
406 ngx_queue_insert_head(&conf->free, &item->queue); | |
407 } | |
408 | |
409 | |
410 static void | |
411 ngx_http_upstream_keepalive_close(ngx_connection_t *c) | |
412 { | |
413 | |
414 #if (NGX_HTTP_SSL) | |
415 | |
416 if (c->ssl) { | |
417 c->ssl->no_wait_shutdown = 1; | |
418 c->ssl->no_send_shutdown = 1; | |
419 | |
420 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { | |
421 c->ssl->handler = ngx_http_upstream_keepalive_close; | |
422 return; | |
423 } | |
424 } | |
425 | |
426 #endif | |
427 | |
428 ngx_destroy_pool(c->pool); | |
429 ngx_close_connection(c); | |
430 } | |
431 | |
432 | |
433 #if (NGX_HTTP_SSL) | |
434 | |
435 static ngx_int_t | |
436 ngx_http_upstream_keepalive_set_session(ngx_peer_connection_t *pc, void *data) | |
437 { | |
438 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
439 | |
440 return kp->original_set_session(pc, kp->data); | |
441 } | |
442 | |
443 | |
444 static void | |
445 ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, void *data) | |
446 { | |
447 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
448 | |
449 kp->original_save_session(pc, kp->data); | |
450 return; | |
451 } | |
452 | |
453 #endif | |
454 | |
455 | |
456 static void * | |
457 ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) | |
458 { | |
459 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
460 | |
461 conf = ngx_pcalloc(cf->pool, | |
462 sizeof(ngx_http_upstream_keepalive_srv_conf_t)); | |
463 if (conf == NULL) { | |
464 return NULL; | |
465 } | |
466 | |
467 /* | |
468 * set by ngx_pcalloc(): | |
469 * | |
470 * conf->original_init_upstream = NULL; | |
471 * conf->original_init_peer = NULL; | |
472 */ | |
473 | |
474 conf->max_cached = 1; | |
475 | |
476 return conf; | |
477 } | |
478 | |
479 | |
480 static char * | |
481 ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
482 { | |
483 ngx_http_upstream_srv_conf_t *uscf; | |
484 ngx_http_upstream_keepalive_srv_conf_t *kcf; | |
485 | |
486 ngx_int_t n; | |
487 ngx_str_t *value; | |
488 ngx_uint_t i; | |
489 | |
490 uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); | |
491 | |
492 kcf = ngx_http_conf_upstream_srv_conf(uscf, | |
493 ngx_http_upstream_keepalive_module); | |
494 | |
4998
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
495 if (kcf->original_init_upstream) { |
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
496 return "is duplicate"; |
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
497 } |
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
498 |
4127 | 499 kcf->original_init_upstream = uscf->peer.init_upstream |
500 ? uscf->peer.init_upstream | |
501 : ngx_http_upstream_init_round_robin; | |
502 | |
503 uscf->peer.init_upstream = ngx_http_upstream_init_keepalive; | |
504 | |
505 /* read options */ | |
506 | |
507 value = cf->args->elts; | |
508 | |
509 n = ngx_atoi(value[1].data, value[1].len); | |
510 | |
511 if (n == NGX_ERROR || n == 0) { | |
512 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
513 "invalid value \"%V\" in \"%V\" directive", | |
514 &value[1], &cmd->name); | |
515 return NGX_CONF_ERROR; | |
516 } | |
517 | |
518 kcf->max_cached = n; | |
519 | |
520 for (i = 2; i < cf->args->nelts; i++) { | |
521 | |
522 if (ngx_strcmp(value[i].data, "single") == 0) { | |
4694
5b5c07dee156
Upstream keepalive: "single" parameter deprecated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
523 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
5b5c07dee156
Upstream keepalive: "single" parameter deprecated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
524 "the \"single\" parameter is deprecated"); |
4127 | 525 continue; |
526 } | |
527 | |
528 goto invalid; | |
529 } | |
530 | |
531 return NGX_CONF_OK; | |
532 | |
533 invalid: | |
534 | |
535 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
536 "invalid parameter \"%V\"", &value[i]); | |
537 | |
538 return NGX_CONF_ERROR; | |
539 } |