Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_upstream_keepalive_module.c @ 7524:deebe988cbd7
Perl: reworked perl module to pass ctx instead of request.
This ensures that correct ctx is always available, including after
filter finalization. In particular, this fixes a segmentation fault
with the following configuration:
location / {
image_filter test;
perl 'sub {
my $r = shift;
$r->send_http_header();
$r->print("foo\n");
$r->print("bar\n");
}';
}
This also seems to be the only way to correctly handle filter finalization
in various complex cases, for example, when embedded perl is used both
in the original handler and in an error page called after filter
finalization.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Fri, 12 Jul 2019 11:29:22 +0300 |
parents | 70c6b08973a0 |
children | 3939483cd1b5 |
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; | |
7340
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
15 ngx_uint_t requests; |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
16 ngx_msec_t timeout; |
4127 | 17 |
18 ngx_queue_t cache; | |
19 ngx_queue_t free; | |
20 | |
21 ngx_http_upstream_init_pt original_init_upstream; | |
22 ngx_http_upstream_init_peer_pt original_init_peer; | |
23 | |
24 } ngx_http_upstream_keepalive_srv_conf_t; | |
25 | |
26 | |
27 typedef struct { | |
28 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
29 | |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
30 ngx_queue_t queue; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
31 ngx_connection_t *connection; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
32 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
33 socklen_t socklen; |
6559
adf25b8d0431
Introduced the ngx_sockaddr_t type.
Ruslan Ermilov <ru@nginx.com>
parents:
6332
diff
changeset
|
34 ngx_sockaddr_t sockaddr; |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
35 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
36 } ngx_http_upstream_keepalive_cache_t; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
37 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
38 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
39 typedef struct { |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
40 ngx_http_upstream_keepalive_srv_conf_t *conf; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
41 |
4127 | 42 ngx_http_upstream_t *upstream; |
43 | |
44 void *data; | |
45 | |
46 ngx_event_get_peer_pt original_get_peer; | |
47 ngx_event_free_peer_pt original_free_peer; | |
48 | |
49 #if (NGX_HTTP_SSL) | |
50 ngx_event_set_peer_session_pt original_set_session; | |
51 ngx_event_save_peer_session_pt original_save_session; | |
52 #endif | |
53 | |
54 } ngx_http_upstream_keepalive_peer_data_t; | |
55 | |
56 | |
57 static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r, | |
58 ngx_http_upstream_srv_conf_t *us); | |
59 static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, | |
60 void *data); | |
61 static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, | |
62 void *data, ngx_uint_t state); | |
63 | |
64 static void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev); | |
65 static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev); | |
66 static void ngx_http_upstream_keepalive_close(ngx_connection_t *c); | |
67 | |
68 #if (NGX_HTTP_SSL) | |
69 static ngx_int_t ngx_http_upstream_keepalive_set_session( | |
70 ngx_peer_connection_t *pc, void *data); | |
71 static void ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, | |
72 void *data); | |
73 #endif | |
74 | |
75 static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf); | |
76 static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, | |
77 void *conf); | |
78 | |
79 | |
80 static ngx_command_t ngx_http_upstream_keepalive_commands[] = { | |
81 | |
82 { ngx_string("keepalive"), | |
5830
3e5b630e0ec9
Upstream keepalive: removed "single" parameter remnants.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5213
diff
changeset
|
83 NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, |
4127 | 84 ngx_http_upstream_keepalive, |
5213
822b82191940
Upstream keepalive: slightly simplified code.
Ruslan Ermilov <ru@nginx.com>
parents:
5133
diff
changeset
|
85 NGX_HTTP_SRV_CONF_OFFSET, |
4127 | 86 0, |
87 NULL }, | |
88 | |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
89 { ngx_string("keepalive_timeout"), |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
90 NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
91 ngx_conf_set_msec_slot, |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
92 NGX_HTTP_SRV_CONF_OFFSET, |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
93 offsetof(ngx_http_upstream_keepalive_srv_conf_t, timeout), |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
94 NULL }, |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
95 |
7340
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
96 { ngx_string("keepalive_requests"), |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
97 NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
98 ngx_conf_set_num_slot, |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
99 NGX_HTTP_SRV_CONF_OFFSET, |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
100 offsetof(ngx_http_upstream_keepalive_srv_conf_t, requests), |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
101 NULL }, |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
102 |
4127 | 103 ngx_null_command |
104 }; | |
105 | |
106 | |
107 static ngx_http_module_t ngx_http_upstream_keepalive_module_ctx = { | |
108 NULL, /* preconfiguration */ | |
109 NULL, /* postconfiguration */ | |
110 | |
111 NULL, /* create main configuration */ | |
112 NULL, /* init main configuration */ | |
113 | |
114 ngx_http_upstream_keepalive_create_conf, /* create server configuration */ | |
115 NULL, /* merge server configuration */ | |
116 | |
117 NULL, /* create location configuration */ | |
118 NULL /* merge location configuration */ | |
119 }; | |
120 | |
121 | |
122 ngx_module_t ngx_http_upstream_keepalive_module = { | |
123 NGX_MODULE_V1, | |
124 &ngx_http_upstream_keepalive_module_ctx, /* module context */ | |
125 ngx_http_upstream_keepalive_commands, /* module directives */ | |
126 NGX_HTTP_MODULE, /* module type */ | |
127 NULL, /* init master */ | |
128 NULL, /* init module */ | |
129 NULL, /* init process */ | |
130 NULL, /* init thread */ | |
131 NULL, /* exit thread */ | |
132 NULL, /* exit process */ | |
133 NULL, /* exit master */ | |
134 NGX_MODULE_V1_PADDING | |
135 }; | |
136 | |
137 | |
138 static ngx_int_t | |
139 ngx_http_upstream_init_keepalive(ngx_conf_t *cf, | |
140 ngx_http_upstream_srv_conf_t *us) | |
141 { | |
142 ngx_uint_t i; | |
143 ngx_http_upstream_keepalive_srv_conf_t *kcf; | |
144 ngx_http_upstream_keepalive_cache_t *cached; | |
145 | |
146 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, | |
147 "init keepalive"); | |
148 | |
149 kcf = ngx_http_conf_upstream_srv_conf(us, | |
150 ngx_http_upstream_keepalive_module); | |
151 | |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
152 ngx_conf_init_msec_value(kcf->timeout, 60000); |
7340
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
153 ngx_conf_init_uint_value(kcf->requests, 100); |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
154 |
4127 | 155 if (kcf->original_init_upstream(cf, us) != NGX_OK) { |
156 return NGX_ERROR; | |
157 } | |
158 | |
159 kcf->original_init_peer = us->peer.init; | |
160 | |
161 us->peer.init = ngx_http_upstream_init_keepalive_peer; | |
162 | |
163 /* allocate cache items and add to free queue */ | |
164 | |
165 cached = ngx_pcalloc(cf->pool, | |
166 sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached); | |
167 if (cached == NULL) { | |
168 return NGX_ERROR; | |
169 } | |
170 | |
171 ngx_queue_init(&kcf->cache); | |
172 ngx_queue_init(&kcf->free); | |
173 | |
174 for (i = 0; i < kcf->max_cached; i++) { | |
175 ngx_queue_insert_head(&kcf->free, &cached[i].queue); | |
176 cached[i].conf = kcf; | |
177 } | |
178 | |
179 return NGX_OK; | |
180 } | |
181 | |
182 | |
183 static ngx_int_t | |
184 ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r, | |
185 ngx_http_upstream_srv_conf_t *us) | |
186 { | |
187 ngx_http_upstream_keepalive_peer_data_t *kp; | |
188 ngx_http_upstream_keepalive_srv_conf_t *kcf; | |
189 | |
190 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
191 "init keepalive peer"); | |
192 | |
193 kcf = ngx_http_conf_upstream_srv_conf(us, | |
194 ngx_http_upstream_keepalive_module); | |
195 | |
196 kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t)); | |
197 if (kp == NULL) { | |
198 return NGX_ERROR; | |
199 } | |
200 | |
201 if (kcf->original_init_peer(r, us) != NGX_OK) { | |
202 return NGX_ERROR; | |
203 } | |
204 | |
205 kp->conf = kcf; | |
206 kp->upstream = r->upstream; | |
207 kp->data = r->upstream->peer.data; | |
208 kp->original_get_peer = r->upstream->peer.get; | |
209 kp->original_free_peer = r->upstream->peer.free; | |
210 | |
211 r->upstream->peer.data = kp; | |
212 r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer; | |
213 r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer; | |
214 | |
215 #if (NGX_HTTP_SSL) | |
216 kp->original_set_session = r->upstream->peer.set_session; | |
217 kp->original_save_session = r->upstream->peer.save_session; | |
218 r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session; | |
219 r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session; | |
220 #endif | |
221 | |
222 return NGX_OK; | |
223 } | |
224 | |
225 | |
226 static ngx_int_t | |
227 ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data) | |
228 { | |
229 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
230 ngx_http_upstream_keepalive_cache_t *item; | |
231 | |
232 ngx_int_t rc; | |
233 ngx_queue_t *q, *cache; | |
234 ngx_connection_t *c; | |
235 | |
236 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
237 "get keepalive peer"); | |
238 | |
4694
5b5c07dee156
Upstream keepalive: "single" parameter deprecated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
239 /* ask balancer */ |
4127 | 240 |
241 rc = kp->original_get_peer(pc, kp->data); | |
242 | |
4694
5b5c07dee156
Upstream keepalive: "single" parameter deprecated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
243 if (rc != NGX_OK) { |
4127 | 244 return rc; |
245 } | |
246 | |
247 /* search cache for suitable connection */ | |
248 | |
249 cache = &kp->conf->cache; | |
250 | |
251 for (q = ngx_queue_head(cache); | |
252 q != ngx_queue_sentinel(cache); | |
253 q = ngx_queue_next(q)) | |
254 { | |
255 item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); | |
256 c = item->connection; | |
257 | |
258 if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr, | |
259 item->socklen, pc->socklen) | |
260 == 0) | |
261 { | |
262 ngx_queue_remove(q); | |
263 ngx_queue_insert_head(&kp->conf->free, q); | |
264 | |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
265 goto found; |
4127 | 266 } |
267 } | |
268 | |
269 return NGX_OK; | |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
270 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
271 found: |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
272 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
273 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
274 "get keepalive peer: using connection %p", c); |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
275 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
276 c->idle = 0; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
277 c->sent = 0; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
278 c->log = pc->log; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
279 c->read->log = pc->log; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
280 c->write->log = pc->log; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
281 c->pool->log = pc->log; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
282 |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
283 if (c->read->timer_set) { |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
284 ngx_del_timer(c->read); |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
285 } |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
286 |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
287 pc->connection = c; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
288 pc->cached = 1; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
289 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
290 return NGX_DONE; |
4127 | 291 } |
292 | |
293 | |
294 static void | |
295 ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data, | |
296 ngx_uint_t state) | |
297 { | |
298 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
299 ngx_http_upstream_keepalive_cache_t *item; | |
300 | |
301 ngx_queue_t *q; | |
302 ngx_connection_t *c; | |
303 ngx_http_upstream_t *u; | |
304 | |
305 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
306 "free keepalive peer"); | |
307 | |
308 /* cache valid connections */ | |
309 | |
310 u = kp->upstream; | |
311 c = pc->connection; | |
312 | |
5133
089a662c17d1
Upstream: removed double-free workarounds in peer.free() methods.
Ruslan Ermilov <ru@nginx.com>
parents:
4998
diff
changeset
|
313 if (state & NGX_PEER_FAILED |
4127 | 314 || c == NULL |
315 || c->read->eof | |
316 || c->read->error | |
317 || c->read->timedout | |
318 || c->write->error | |
319 || c->write->timedout) | |
320 { | |
321 goto invalid; | |
322 } | |
323 | |
7340
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
324 if (c->requests >= kp->conf->requests) { |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
325 goto invalid; |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
326 } |
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
327 |
4127 | 328 if (!u->keepalive) { |
329 goto invalid; | |
330 } | |
331 | |
6332
78b4e10b4367
Upstream: don't keep connections on early responses (ticket #669).
Maxim Dounin <mdounin@mdounin.ru>
parents:
6220
diff
changeset
|
332 if (!u->request_body_sent) { |
78b4e10b4367
Upstream: don't keep connections on early responses (ticket #669).
Maxim Dounin <mdounin@mdounin.ru>
parents:
6220
diff
changeset
|
333 goto invalid; |
78b4e10b4367
Upstream: don't keep connections on early responses (ticket #669).
Maxim Dounin <mdounin@mdounin.ru>
parents:
6220
diff
changeset
|
334 } |
78b4e10b4367
Upstream: don't keep connections on early responses (ticket #669).
Maxim Dounin <mdounin@mdounin.ru>
parents:
6220
diff
changeset
|
335 |
6220
5e6142609e48
Core: idle connections now closed only once on exiting.
Valentin Bartenev <vbart@nginx.com>
parents:
6167
diff
changeset
|
336 if (ngx_terminate || ngx_exiting) { |
5e6142609e48
Core: idle connections now closed only once on exiting.
Valentin Bartenev <vbart@nginx.com>
parents:
6167
diff
changeset
|
337 goto invalid; |
5e6142609e48
Core: idle connections now closed only once on exiting.
Valentin Bartenev <vbart@nginx.com>
parents:
6167
diff
changeset
|
338 } |
5e6142609e48
Core: idle connections now closed only once on exiting.
Valentin Bartenev <vbart@nginx.com>
parents:
6167
diff
changeset
|
339 |
4127 | 340 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
341 goto invalid; | |
342 } | |
343 | |
344 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
345 "free keepalive peer: saving connection %p", c); | |
346 | |
347 if (ngx_queue_empty(&kp->conf->free)) { | |
348 | |
349 q = ngx_queue_last(&kp->conf->cache); | |
350 ngx_queue_remove(q); | |
351 | |
352 item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); | |
353 | |
354 ngx_http_upstream_keepalive_close(item->connection); | |
355 | |
356 } else { | |
357 q = ngx_queue_head(&kp->conf->free); | |
358 ngx_queue_remove(q); | |
359 | |
360 item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue); | |
361 } | |
362 | |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
363 ngx_queue_insert_head(&kp->conf->cache, q); |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
364 |
4127 | 365 item->connection = c; |
366 | |
367 pc->connection = NULL; | |
368 | |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
369 c->read->delayed = 0; |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
370 ngx_add_timer(c->read, kp->conf->timeout); |
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
371 |
4127 | 372 if (c->write->timer_set) { |
373 ngx_del_timer(c->write); | |
374 } | |
375 | |
376 c->write->handler = ngx_http_upstream_keepalive_dummy_handler; | |
377 c->read->handler = ngx_http_upstream_keepalive_close_handler; | |
378 | |
379 c->data = item; | |
380 c->idle = 1; | |
381 c->log = ngx_cycle->log; | |
382 c->read->log = ngx_cycle->log; | |
383 c->write->log = ngx_cycle->log; | |
384 c->pool->log = ngx_cycle->log; | |
385 | |
386 item->socklen = pc->socklen; | |
387 ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen); | |
388 | |
389 if (c->read->ready) { | |
390 ngx_http_upstream_keepalive_close_handler(c->read); | |
391 } | |
392 | |
393 invalid: | |
394 | |
395 kp->original_free_peer(pc, kp->data, state); | |
396 } | |
397 | |
398 | |
399 static void | |
400 ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev) | |
401 { | |
402 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, | |
403 "keepalive dummy handler"); | |
404 } | |
405 | |
406 | |
407 static void | |
408 ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev) | |
409 { | |
410 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
411 ngx_http_upstream_keepalive_cache_t *item; | |
412 | |
413 int n; | |
414 char buf[1]; | |
415 ngx_connection_t *c; | |
416 | |
417 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, | |
418 "keepalive close handler"); | |
419 | |
420 c = ev->data; | |
421 | |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
422 if (c->close || c->read->timedout) { |
4127 | 423 goto close; |
424 } | |
425 | |
426 n = recv(c->fd, buf, 1, MSG_PEEK); | |
427 | |
428 if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { | |
5999
4d8936b1fc32
Upstream keepalive: drop ready flag on EAGAIN from recv(MSG_PEEK).
Valentin Bartenev <vbart@nginx.com>
parents:
5864
diff
changeset
|
429 ev->ready = 0; |
4127 | 430 |
431 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
432 goto close; | |
433 } | |
434 | |
435 return; | |
436 } | |
437 | |
438 close: | |
439 | |
440 item = c->data; | |
441 conf = item->conf; | |
442 | |
443 ngx_http_upstream_keepalive_close(c); | |
444 | |
445 ngx_queue_remove(&item->queue); | |
446 ngx_queue_insert_head(&conf->free, &item->queue); | |
447 } | |
448 | |
449 | |
450 static void | |
451 ngx_http_upstream_keepalive_close(ngx_connection_t *c) | |
452 { | |
453 | |
454 #if (NGX_HTTP_SSL) | |
455 | |
456 if (c->ssl) { | |
457 c->ssl->no_wait_shutdown = 1; | |
458 c->ssl->no_send_shutdown = 1; | |
459 | |
460 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { | |
461 c->ssl->handler = ngx_http_upstream_keepalive_close; | |
462 return; | |
463 } | |
464 } | |
465 | |
466 #endif | |
467 | |
468 ngx_destroy_pool(c->pool); | |
469 ngx_close_connection(c); | |
470 } | |
471 | |
472 | |
473 #if (NGX_HTTP_SSL) | |
474 | |
475 static ngx_int_t | |
476 ngx_http_upstream_keepalive_set_session(ngx_peer_connection_t *pc, void *data) | |
477 { | |
478 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
479 | |
480 return kp->original_set_session(pc, kp->data); | |
481 } | |
482 | |
483 | |
484 static void | |
485 ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, void *data) | |
486 { | |
487 ngx_http_upstream_keepalive_peer_data_t *kp = data; | |
488 | |
489 kp->original_save_session(pc, kp->data); | |
490 return; | |
491 } | |
492 | |
493 #endif | |
494 | |
495 | |
496 static void * | |
497 ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) | |
498 { | |
499 ngx_http_upstream_keepalive_srv_conf_t *conf; | |
500 | |
501 conf = ngx_pcalloc(cf->pool, | |
502 sizeof(ngx_http_upstream_keepalive_srv_conf_t)); | |
503 if (conf == NULL) { | |
504 return NULL; | |
505 } | |
506 | |
507 /* | |
508 * set by ngx_pcalloc(): | |
509 * | |
510 * conf->original_init_upstream = NULL; | |
511 * conf->original_init_peer = NULL; | |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
512 * conf->max_cached = 0; |
4127 | 513 */ |
514 | |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
515 conf->timeout = NGX_CONF_UNSET_MSEC; |
7340
70c6b08973a0
Upstream keepalive: keepalive_requests directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7339
diff
changeset
|
516 conf->requests = NGX_CONF_UNSET_UINT; |
7339
d9029e113a05
Upstream keepalive: keepalive_timeout directive.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7338
diff
changeset
|
517 |
4127 | 518 return conf; |
519 } | |
520 | |
521 | |
522 static char * | |
523 ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
524 { | |
525 ngx_http_upstream_srv_conf_t *uscf; | |
5213
822b82191940
Upstream keepalive: slightly simplified code.
Ruslan Ermilov <ru@nginx.com>
parents:
5133
diff
changeset
|
526 ngx_http_upstream_keepalive_srv_conf_t *kcf = conf; |
4127 | 527 |
528 ngx_int_t n; | |
529 ngx_str_t *value; | |
530 | |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
531 if (kcf->max_cached) { |
4998
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
532 return "is duplicate"; |
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
533 } |
82336a9ce26d
Upstream keepalive: detect duplicate "keepalive" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4694
diff
changeset
|
534 |
4127 | 535 /* read options */ |
536 | |
537 value = cf->args->elts; | |
538 | |
539 n = ngx_atoi(value[1].data, value[1].len); | |
540 | |
541 if (n == NGX_ERROR || n == 0) { | |
542 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
543 "invalid value \"%V\" in \"%V\" directive", | |
544 &value[1], &cmd->name); | |
545 return NGX_CONF_ERROR; | |
546 } | |
547 | |
548 kcf->max_cached = n; | |
549 | |
7338
46174066b75f
Upstream keepalive: comment added.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7165
diff
changeset
|
550 /* init upstream handler */ |
46174066b75f
Upstream keepalive: comment added.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7165
diff
changeset
|
551 |
6167
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
552 uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
553 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
554 kcf->original_init_upstream = uscf->peer.init_upstream |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
555 ? uscf->peer.init_upstream |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
556 : ngx_http_upstream_init_round_robin; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
557 |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
558 uscf->peer.init_upstream = ngx_http_upstream_init_keepalive; |
87d48f8793b6
Upstream keepalive: reduced diffs to the plus version of nginx.
Roman Arutyunyan <arut@nginx.com>
parents:
5999
diff
changeset
|
559 |
4127 | 560 return NGX_CONF_OK; |
561 } |