Mercurial > hg > nginx
annotate src/http/modules/ngx_http_memcached_module.c @ 4207:4fc91bae6f83
Better recheck of dead upstream servers.
Previously nginx used to mark backend again as live as soon as fail_timeout
passes (10s by default) since last failure. On the other hand, detecting
dead backend takes up to 60s (proxy_connect_timeout) in typical situation
"backend is down and doesn't respond to any packets". This resulted in
suboptimal behaviour in the above situation (up to 23% of requests were
directed to dead backend with default settings).
More detailed description of the problem may be found here (in Russian):
http://mailman.nginx.org/pipermail/nginx-ru/2011-August/042172.html
Fix is to only allow one request after fail_timeout passes, and
mark backend as "live" only if this request succeeds.
Note that with new code backend will not be marked "live" unless "check"
request is completed, and this may take a while in some specific workloads
(e.g. streaming). This is believed to be acceptable.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 12 Oct 2011 14:22:48 +0000 |
parents | 16c60162c35b |
children | d620f497c50f |
rev | line source |
---|---|
581 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 typedef struct { | |
13 ngx_http_upstream_conf_t upstream; | |
1076 | 14 ngx_int_t index; |
581 | 15 } ngx_http_memcached_loc_conf_t; |
16 | |
17 | |
18 typedef struct { | |
19 size_t rest; | |
20 ngx_http_request_t *request; | |
597 | 21 ngx_str_t key; |
581 | 22 } ngx_http_memcached_ctx_t; |
23 | |
24 | |
25 static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r); | |
26 static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r); | |
27 static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r); | |
28 static ngx_int_t ngx_http_memcached_filter_init(void *data); | |
29 static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes); | |
30 static void ngx_http_memcached_abort_request(ngx_http_request_t *r); | |
31 static void ngx_http_memcached_finalize_request(ngx_http_request_t *r, | |
32 ngx_int_t rc); | |
33 | |
34 static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf); | |
35 static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, | |
36 void *parent, void *child); | |
37 | |
38 static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, | |
39 void *conf); | |
40 | |
41 | |
42 static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = { | |
43 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, | |
44 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, | |
45 { ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, | |
46 { ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, | |
665 | 47 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, |
581 | 48 { ngx_null_string, 0 } |
49 }; | |
50 | |
51 | |
52 static ngx_command_t ngx_http_memcached_commands[] = { | |
53 | |
54 { ngx_string("memcached_pass"), | |
1788
f10228d7ea06
allow memached_pass inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1787
diff
changeset
|
55 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, |
581 | 56 ngx_http_memcached_pass, |
57 NGX_HTTP_LOC_CONF_OFFSET, | |
58 0, | |
59 NULL }, | |
60 | |
3271
fcd98af88df3
proxy_bind, fastcgi_bind, and memcached_bind
Igor Sysoev <igor@sysoev.ru>
parents:
3061
diff
changeset
|
61 { ngx_string("memcached_bind"), |
fcd98af88df3
proxy_bind, fastcgi_bind, and memcached_bind
Igor Sysoev <igor@sysoev.ru>
parents:
3061
diff
changeset
|
62 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
3399 | 63 ngx_http_upstream_bind_set_slot, |
3271
fcd98af88df3
proxy_bind, fastcgi_bind, and memcached_bind
Igor Sysoev <igor@sysoev.ru>
parents:
3061
diff
changeset
|
64 NGX_HTTP_LOC_CONF_OFFSET, |
fcd98af88df3
proxy_bind, fastcgi_bind, and memcached_bind
Igor Sysoev <igor@sysoev.ru>
parents:
3061
diff
changeset
|
65 offsetof(ngx_http_memcached_loc_conf_t, upstream.local), |
fcd98af88df3
proxy_bind, fastcgi_bind, and memcached_bind
Igor Sysoev <igor@sysoev.ru>
parents:
3061
diff
changeset
|
66 NULL }, |
fcd98af88df3
proxy_bind, fastcgi_bind, and memcached_bind
Igor Sysoev <igor@sysoev.ru>
parents:
3061
diff
changeset
|
67 |
581 | 68 { ngx_string("memcached_connect_timeout"), |
69 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
70 ngx_conf_set_msec_slot, | |
71 NGX_HTTP_LOC_CONF_OFFSET, | |
72 offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout), | |
73 NULL }, | |
74 | |
75 { ngx_string("memcached_send_timeout"), | |
76 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
77 ngx_conf_set_msec_slot, | |
78 NGX_HTTP_LOC_CONF_OFFSET, | |
79 offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout), | |
80 NULL }, | |
81 | |
82 { ngx_string("memcached_buffer_size"), | |
83 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
84 ngx_conf_set_size_slot, | |
85 NGX_HTTP_LOC_CONF_OFFSET, | |
86 offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size), | |
87 NULL }, | |
88 | |
89 { ngx_string("memcached_read_timeout"), | |
90 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
91 ngx_conf_set_msec_slot, | |
92 NGX_HTTP_LOC_CONF_OFFSET, | |
93 offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout), | |
94 NULL }, | |
95 | |
96 { ngx_string("memcached_next_upstream"), | |
97 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
98 ngx_conf_set_bitmask_slot, | |
99 NGX_HTTP_LOC_CONF_OFFSET, | |
100 offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream), | |
101 &ngx_http_memcached_next_upstream_masks }, | |
102 | |
103 ngx_null_command | |
104 }; | |
105 | |
106 | |
667 | 107 static ngx_http_module_t ngx_http_memcached_module_ctx = { |
581 | 108 NULL, /* preconfiguration */ |
109 NULL, /* postconfiguration */ | |
110 | |
111 NULL, /* create main configuration */ | |
112 NULL, /* init main configuration */ | |
113 | |
114 NULL, /* create server configuration */ | |
115 NULL, /* merge server configuration */ | |
116 | |
117 ngx_http_memcached_create_loc_conf, /* create location configration */ | |
118 ngx_http_memcached_merge_loc_conf /* merge location configration */ | |
119 }; | |
120 | |
121 | |
122 ngx_module_t ngx_http_memcached_module = { | |
123 NGX_MODULE_V1, | |
124 &ngx_http_memcached_module_ctx, /* module context */ | |
125 ngx_http_memcached_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 | |
1076 | 138 static ngx_str_t ngx_http_memcached_key = ngx_string("memcached_key"); |
139 | |
140 | |
581 | 141 #define NGX_HTTP_MEMCACHED_END (sizeof(ngx_http_memcached_end) - 1) |
142 static u_char ngx_http_memcached_end[] = CRLF "END" CRLF; | |
143 | |
144 | |
145 static ngx_int_t | |
146 ngx_http_memcached_handler(ngx_http_request_t *r) | |
147 { | |
148 ngx_int_t rc; | |
149 ngx_http_upstream_t *u; | |
150 ngx_http_memcached_ctx_t *ctx; | |
151 ngx_http_memcached_loc_conf_t *mlcf; | |
152 | |
645 | 153 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { |
581 | 154 return NGX_HTTP_NOT_ALLOWED; |
155 } | |
156 | |
1370
cc114c85be0f
rename ngx_http_discard_body() to ngx_http_discard_request_body()
Igor Sysoev <igor@sysoev.ru>
parents:
1333
diff
changeset
|
157 rc = ngx_http_discard_request_body(r); |
581 | 158 |
1374 | 159 if (rc != NGX_OK) { |
581 | 160 return rc; |
161 } | |
162 | |
163 if (ngx_http_set_content_type(r) != NGX_OK) { | |
164 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
165 } | |
166 | |
3006
95972b9e790b
ngx_http_upstream_create() to cleanup the previous upstream after
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
167 if (ngx_http_upstream_create(r) != NGX_OK) { |
581 | 168 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
169 } | |
170 | |
3006
95972b9e790b
ngx_http_upstream_create() to cleanup the previous upstream after
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
171 u = r->upstream; |
95972b9e790b
ngx_http_upstream_create() to cleanup the previous upstream after
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
172 |
3516
dd1570b6f237
ngx_str_set() and ngx_str_null()
Igor Sysoev <igor@sysoev.ru>
parents:
3487
diff
changeset
|
173 ngx_str_set(&u->schema, "memcached://"); |
3006
95972b9e790b
ngx_http_upstream_create() to cleanup the previous upstream after
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
174 u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; |
581 | 175 |
3006
95972b9e790b
ngx_http_upstream_create() to cleanup the previous upstream after
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
176 mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); |
581 | 177 |
178 u->conf = &mlcf->upstream; | |
179 | |
180 u->create_request = ngx_http_memcached_create_request; | |
181 u->reinit_request = ngx_http_memcached_reinit_request; | |
182 u->process_header = ngx_http_memcached_process_header; | |
183 u->abort_request = ngx_http_memcached_abort_request; | |
184 u->finalize_request = ngx_http_memcached_finalize_request; | |
185 | |
186 ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); | |
187 if (ctx == NULL) { | |
188 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
189 } | |
190 | |
191 ctx->rest = NGX_HTTP_MEMCACHED_END; | |
192 ctx->request = r; | |
193 | |
597 | 194 ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); |
195 | |
581 | 196 u->input_filter_init = ngx_http_memcached_filter_init; |
197 u->input_filter = ngx_http_memcached_filter; | |
198 u->input_filter_ctx = ctx; | |
199 | |
3061
f444f291ed38
fix request counter for memcached, introduced in r3050
Igor Sysoev <igor@sysoev.ru>
parents:
3006
diff
changeset
|
200 r->main->count++; |
f444f291ed38
fix request counter for memcached, introduced in r3050
Igor Sysoev <igor@sysoev.ru>
parents:
3006
diff
changeset
|
201 |
581 | 202 ngx_http_upstream_init(r); |
203 | |
204 return NGX_DONE; | |
205 } | |
206 | |
207 | |
208 static ngx_int_t | |
209 ngx_http_memcached_create_request(ngx_http_request_t *r) | |
210 { | |
1076 | 211 size_t len; |
1333
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
212 uintptr_t escape; |
1076 | 213 ngx_buf_t *b; |
214 ngx_chain_t *cl; | |
215 ngx_http_memcached_ctx_t *ctx; | |
216 ngx_http_variable_value_t *vv; | |
217 ngx_http_memcached_loc_conf_t *mlcf; | |
218 | |
219 mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); | |
581 | 220 |
1076 | 221 vv = ngx_http_get_indexed_variable(r, mlcf->index); |
222 | |
223 if (vv == NULL || vv->not_found || vv->len == 0) { | |
224 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
225 "the \"$memcached_key\" variable is not set"); | |
226 return NGX_ERROR; | |
227 } | |
228 | |
1333
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
229 escape = 2 * ngx_escape_uri(NULL, vv->data, vv->len, NGX_ESCAPE_MEMCACHED); |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
230 |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
231 len = sizeof("get ") - 1 + vv->len + escape + sizeof(CRLF) - 1; |
581 | 232 |
233 b = ngx_create_temp_buf(r->pool, len); | |
234 if (b == NULL) { | |
235 return NGX_ERROR; | |
236 } | |
237 | |
238 cl = ngx_alloc_chain_link(r->pool); | |
239 if (cl == NULL) { | |
240 return NGX_ERROR; | |
241 } | |
242 | |
243 cl->buf = b; | |
244 cl->next = NULL; | |
245 | |
246 r->upstream->request_bufs = cl; | |
247 | |
248 *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' '; | |
249 | |
597 | 250 ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); |
251 | |
252 ctx->key.data = b->last; | |
253 | |
1333
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
254 if (escape == 0) { |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
255 b->last = ngx_copy(b->last, vv->data, vv->len); |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
256 |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
257 } else { |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
258 b->last = (u_char *) ngx_escape_uri(b->last, vv->data, vv->len, |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
259 NGX_ESCAPE_MEMCACHED); |
07ebeeb55700
escape space, etc in $memcached_key
Igor Sysoev <igor@sysoev.ru>
parents:
1332
diff
changeset
|
260 } |
581 | 261 |
597 | 262 ctx->key.len = b->last - ctx->key.data; |
581 | 263 |
264 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
597 | 265 "http memcached request: \"%V\"", &ctx->key); |
581 | 266 |
1088
2d8e72584534
eliminate the useless space symbol
Igor Sysoev <igor@sysoev.ru>
parents:
1076
diff
changeset
|
267 *b->last++ = CR; *b->last++ = LF; |
581 | 268 |
269 return NGX_OK; | |
270 } | |
271 | |
272 | |
273 static ngx_int_t | |
274 ngx_http_memcached_reinit_request(ngx_http_request_t *r) | |
275 { | |
276 return NGX_OK; | |
277 } | |
278 | |
279 | |
280 static ngx_int_t | |
281 ngx_http_memcached_process_header(ngx_http_request_t *r) | |
282 { | |
597 | 283 u_char *p, *len; |
284 ngx_str_t line; | |
285 ngx_http_upstream_t *u; | |
286 ngx_http_memcached_ctx_t *ctx; | |
581 | 287 |
288 u = r->upstream; | |
289 | |
290 for (p = u->buffer.pos; p < u->buffer.last; p++) { | |
291 if (*p == LF) { | |
292 goto found; | |
293 } | |
294 } | |
295 | |
296 return NGX_AGAIN; | |
297 | |
298 found: | |
299 | |
300 *p = '\0'; | |
301 | |
302 line.len = p - u->buffer.pos - 1; | |
303 line.data = u->buffer.pos; | |
304 | |
305 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
306 "memcached: \"%V\"", &line); | |
307 | |
308 p = u->buffer.pos; | |
309 | |
597 | 310 ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); |
311 | |
581 | 312 if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) { |
313 | |
314 p += sizeof("VALUE ") - 1; | |
315 | |
597 | 316 if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) { |
581 | 317 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
318 "memcached sent invalid key in response \"%V\" " | |
319 "for key \"%V\"", | |
597 | 320 &line, &ctx->key); |
581 | 321 |
322 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
323 } | |
324 | |
597 | 325 p += ctx->key.len; |
581 | 326 |
327 if (*p++ != ' ') { | |
328 goto no_valid; | |
329 } | |
330 | |
331 /* skip flags */ | |
332 | |
333 while (*p) { | |
334 if (*p++ == ' ') { | |
335 goto length; | |
336 } | |
337 } | |
338 | |
339 goto no_valid; | |
340 | |
341 length: | |
342 | |
343 len = p; | |
344 | |
345 while (*p && *p++ != CR) { /* void */ } | |
346 | |
4117
103b0d9afe07
Upstream: content_length_n API change.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3523
diff
changeset
|
347 u->headers_in.content_length_n = ngx_atoof(len, p - len - 1); |
103b0d9afe07
Upstream: content_length_n API change.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3523
diff
changeset
|
348 if (u->headers_in.content_length_n == -1) { |
581 | 349 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
350 "memcached sent invalid length in response \"%V\" " | |
351 "for key \"%V\"", | |
597 | 352 &line, &ctx->key); |
581 | 353 return NGX_HTTP_UPSTREAM_INVALID_HEADER; |
354 } | |
355 | |
356 u->headers_in.status_n = 200; | |
1567
31d4278d51c0
memcached did not set $upstream_response_time
Igor Sysoev <igor@sysoev.ru>
parents:
1554
diff
changeset
|
357 u->state->status = 200; |
581 | 358 u->buffer.pos = p + 1; |
359 | |
360 return NGX_OK; | |
361 } | |
362 | |
363 if (ngx_strcmp(p, "END\x0d") == 0) { | |
364 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
597 | 365 "key: \"%V\" was not found by memcached", &ctx->key); |
581 | 366 |
367 u->headers_in.status_n = 404; | |
1567
31d4278d51c0
memcached did not set $upstream_response_time
Igor Sysoev <igor@sysoev.ru>
parents:
1554
diff
changeset
|
368 u->state->status = 404; |
4121
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
369 u->keepalive = 1; |
581 | 370 |
371 return NGX_OK; | |
372 } | |
373 | |
374 no_valid: | |
375 | |
376 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
377 "memcached sent invalid response: \"%V\"", &line); | |
378 | |
379 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
380 } | |
381 | |
382 | |
383 static ngx_int_t | |
384 ngx_http_memcached_filter_init(void *data) | |
385 { | |
386 ngx_http_memcached_ctx_t *ctx = data; | |
387 | |
388 ngx_http_upstream_t *u; | |
389 | |
390 u = ctx->request->upstream; | |
391 | |
392 u->length += NGX_HTTP_MEMCACHED_END; | |
393 | |
394 return NGX_OK; | |
395 } | |
396 | |
397 | |
398 static ngx_int_t | |
399 ngx_http_memcached_filter(void *data, ssize_t bytes) | |
400 { | |
401 ngx_http_memcached_ctx_t *ctx = data; | |
402 | |
403 u_char *last; | |
404 ngx_buf_t *b; | |
405 ngx_chain_t *cl, **ll; | |
406 ngx_http_upstream_t *u; | |
407 | |
408 u = ctx->request->upstream; | |
409 b = &u->buffer; | |
410 | |
4118
dbddec65fdab
Upstream: r->upstream->length type change to off_t.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4117
diff
changeset
|
411 if (u->length == (ssize_t) ctx->rest) { |
581 | 412 |
413 if (ngx_strncmp(b->last, | |
1548 | 414 ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest, |
3487
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
415 bytes) |
1548 | 416 != 0) |
581 | 417 { |
418 ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, | |
419 "memcached sent invalid trailer"); | |
3487
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
420 |
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
421 u->length = 0; |
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
422 ctx->rest = 0; |
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
423 |
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
424 return NGX_OK; |
581 | 425 } |
426 | |
3487
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
427 u->length -= bytes; |
5d2acf153153
revert partially r1555 and fix the error "memcached sent invalid trailer"
Igor Sysoev <igor@sysoev.ru>
parents:
3399
diff
changeset
|
428 ctx->rest -= bytes; |
581 | 429 |
4121
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
430 if (u->length == 0) { |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
431 u->keepalive = 1; |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
432 } |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
433 |
581 | 434 return NGX_OK; |
435 } | |
436 | |
437 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { | |
438 ll = &cl->next; | |
439 } | |
440 | |
441 cl = ngx_chain_get_free_buf(ctx->request->pool, &u->free_bufs); | |
442 if (cl == NULL) { | |
443 return NGX_ERROR; | |
444 } | |
445 | |
446 cl->buf->flush = 1; | |
447 cl->buf->memory = 1; | |
448 | |
449 *ll = cl; | |
450 | |
1554
30fcc8478d85
two commits those go together by mistake
Igor Sysoev <igor@sysoev.ru>
parents:
1548
diff
changeset
|
451 last = b->last; |
30fcc8478d85
two commits those go together by mistake
Igor Sysoev <igor@sysoev.ru>
parents:
1548
diff
changeset
|
452 cl->buf->pos = last; |
581 | 453 b->last += bytes; |
454 cl->buf->last = b->last; | |
1908
f2953601ed3c
fix memory leak in long-lived non buffered connections
Igor Sysoev <igor@sysoev.ru>
parents:
1788
diff
changeset
|
455 cl->buf->tag = u->output.tag; |
581 | 456 |
457 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, | |
458 "memcached filter bytes:%z size:%z length:%z rest:%z", | |
459 bytes, b->last - b->pos, u->length, ctx->rest); | |
460 | |
1554
30fcc8478d85
two commits those go together by mistake
Igor Sysoev <igor@sysoev.ru>
parents:
1548
diff
changeset
|
461 if (bytes <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) { |
581 | 462 u->length -= bytes; |
463 return NGX_OK; | |
464 } | |
465 | |
1554
30fcc8478d85
two commits those go together by mistake
Igor Sysoev <igor@sysoev.ru>
parents:
1548
diff
changeset
|
466 last += u->length - NGX_HTTP_MEMCACHED_END; |
581 | 467 |
468 if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) { | |
469 ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, | |
470 "memcached sent invalid trailer"); | |
4121
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
471 |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
472 b->last = last; |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
473 cl->buf->last = last; |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
474 u->length = 0; |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
475 ctx->rest = 0; |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
476 |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
477 return NGX_OK; |
581 | 478 } |
479 | |
1554
30fcc8478d85
two commits those go together by mistake
Igor Sysoev <igor@sysoev.ru>
parents:
1548
diff
changeset
|
480 ctx->rest -= b->last - last; |
581 | 481 b->last = last; |
482 cl->buf->last = last; | |
483 u->length = ctx->rest; | |
484 | |
4121
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
485 if (u->length == 0) { |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
486 u->keepalive = 1; |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
487 } |
16c60162c35b
Keepalive support in memcached.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4118
diff
changeset
|
488 |
581 | 489 return NGX_OK; |
490 } | |
491 | |
492 | |
493 static void | |
494 ngx_http_memcached_abort_request(ngx_http_request_t *r) | |
495 { | |
496 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
497 "abort http memcached request"); | |
498 return; | |
499 } | |
500 | |
501 | |
502 static void | |
503 ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc) | |
504 { | |
505 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
506 "finalize http memcached request"); | |
507 return; | |
508 } | |
509 | |
510 | |
511 static void * | |
512 ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) | |
513 { | |
514 ngx_http_memcached_loc_conf_t *conf; | |
515 | |
516 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t)); | |
517 if (conf == NULL) { | |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2392
diff
changeset
|
518 return NULL; |
581 | 519 } |
520 | |
521 /* | |
522 * set by ngx_pcalloc(): | |
523 * | |
524 * conf->upstream.bufs.num = 0; | |
525 * conf->upstream.next_upstream = 0; | |
526 * conf->upstream.temp_path = NULL; | |
527 * conf->upstream.uri = { 0, NULL }; | |
528 * conf->upstream.location = NULL; | |
529 */ | |
530 | |
531 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; | |
532 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; | |
533 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; | |
534 | |
535 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; | |
536 | |
884 | 537 /* the hardcoded values */ |
581 | 538 conf->upstream.cyclic_temp_file = 0; |
629 | 539 conf->upstream.buffering = 0; |
540 conf->upstream.ignore_client_abort = 0; | |
581 | 541 conf->upstream.send_lowat = 0; |
542 conf->upstream.bufs.num = 0; | |
543 conf->upstream.busy_buffers_size = 0; | |
544 conf->upstream.max_temp_file_size = 0; | |
545 conf->upstream.temp_file_write_size = 0; | |
657 | 546 conf->upstream.intercept_errors = 1; |
675 | 547 conf->upstream.intercept_404 = 1; |
581 | 548 conf->upstream.pass_request_headers = 0; |
549 conf->upstream.pass_request_body = 0; | |
550 | |
1787
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
551 conf->index = NGX_CONF_UNSET; |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
552 |
581 | 553 return conf; |
554 } | |
555 | |
556 | |
557 static char * | |
558 ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
559 { | |
560 ngx_http_memcached_loc_conf_t *prev = parent; | |
561 ngx_http_memcached_loc_conf_t *conf = child; | |
562 | |
563 ngx_conf_merge_msec_value(conf->upstream.connect_timeout, | |
564 prev->upstream.connect_timeout, 60000); | |
565 | |
566 ngx_conf_merge_msec_value(conf->upstream.send_timeout, | |
567 prev->upstream.send_timeout, 60000); | |
568 | |
569 ngx_conf_merge_msec_value(conf->upstream.read_timeout, | |
570 prev->upstream.read_timeout, 60000); | |
571 | |
572 ngx_conf_merge_size_value(conf->upstream.buffer_size, | |
573 prev->upstream.buffer_size, | |
574 (size_t) ngx_pagesize); | |
575 | |
576 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, | |
577 prev->upstream.next_upstream, | |
578 (NGX_CONF_BITMASK_SET | |
579 |NGX_HTTP_UPSTREAM_FT_ERROR | |
580 |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); | |
581 | |
665 | 582 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) { |
583 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET | |
584 |NGX_HTTP_UPSTREAM_FT_OFF; | |
585 } | |
586 | |
1787
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
587 if (conf->upstream.upstream == NULL) { |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
588 conf->upstream.upstream = prev->upstream.upstream; |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
589 } |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
590 |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
591 if (conf->index == NGX_CONF_UNSET) { |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
592 conf->index = prev->index; |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
593 } |
a37fe5ceacc4
inherit $memached_key index and memcached_pass upstream inside "if" block
Igor Sysoev <igor@sysoev.ru>
parents:
1658
diff
changeset
|
594 |
581 | 595 return NGX_CONF_OK; |
596 } | |
597 | |
598 | |
599 static char * | |
600 ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
601 { | |
2392 | 602 ngx_http_memcached_loc_conf_t *mlcf = conf; |
581 | 603 |
604 ngx_str_t *value; | |
807
3095bf59059b
now the "memcached_pass" directive uses ngx_parse_url()
Igor Sysoev <igor@sysoev.ru>
parents:
675
diff
changeset
|
605 ngx_url_t u; |
581 | 606 ngx_http_core_loc_conf_t *clcf; |
607 | |
2392 | 608 if (mlcf->upstream.upstream) { |
581 | 609 return "is duplicate"; |
610 } | |
611 | |
612 value = cf->args->elts; | |
613 | |
807
3095bf59059b
now the "memcached_pass" directive uses ngx_parse_url()
Igor Sysoev <igor@sysoev.ru>
parents:
675
diff
changeset
|
614 ngx_memzero(&u, sizeof(ngx_url_t)); |
581 | 615 |
807
3095bf59059b
now the "memcached_pass" directive uses ngx_parse_url()
Igor Sysoev <igor@sysoev.ru>
parents:
675
diff
changeset
|
616 u.url = value[1]; |
884 | 617 u.no_resolve = 1; |
815
b630109560b7
style fix: remove trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
807
diff
changeset
|
618 |
2392 | 619 mlcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); |
620 if (mlcf->upstream.upstream == NULL) { | |
884 | 621 return NGX_CONF_ERROR; |
581 | 622 } |
623 | |
624 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
625 | |
626 clcf->handler = ngx_http_memcached_handler; | |
627 | |
628 if (clcf->name.data[clcf->name.len - 1] == '/') { | |
629 clcf->auto_redirect = 1; | |
630 } | |
631 | |
2392 | 632 mlcf->index = ngx_http_get_variable_index(cf, &ngx_http_memcached_key); |
1076 | 633 |
2392 | 634 if (mlcf->index == NGX_ERROR) { |
1076 | 635 return NGX_CONF_ERROR; |
636 } | |
637 | |
581 | 638 return NGX_CONF_OK; |
639 } |