blob: bd8b837168edb7035dc3034150dbc03fe609c4c9 [file] [log] [blame]
Igor Sysoevc31a9bb2005-11-26 10:11:11 +00001
2/*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7#include <ngx_config.h>
8#include <ngx_core.h>
9#include <ngx_event.h>
10#include <ngx_http.h>
11
12
13typedef struct {
14 ngx_http_upstream_conf_t upstream;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +000015} ngx_http_memcached_loc_conf_t;
16
17
18typedef struct {
19 size_t rest;
20 ngx_http_request_t *request;
Igor Sysoevdf3254a2006-01-11 15:26:57 +000021 ngx_str_t key;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +000022} ngx_http_memcached_ctx_t;
23
24
25static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r);
26static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r);
27static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r);
28static ngx_int_t ngx_http_memcached_filter_init(void *data);
29static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes);
30static void ngx_http_memcached_abort_request(ngx_http_request_t *r);
31static void ngx_http_memcached_finalize_request(ngx_http_request_t *r,
32 ngx_int_t rc);
33
34static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf);
35static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf,
36 void *parent, void *child);
37
38static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
39 void *conf);
40
Igor Sysoev3d2fd182006-12-04 16:46:13 +000041static char *ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
42 ngx_command_t *cmd, void *conf);
43static char *ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
44 ngx_command_t *cmd, void *conf);
45
Igor Sysoevc31a9bb2005-11-26 10:11:11 +000046
47static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = {
48 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
49 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
50 { ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
51 { ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
Igor Sysoevbb28b6d2006-07-11 13:20:19 +000052 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
Igor Sysoevc31a9bb2005-11-26 10:11:11 +000053 { ngx_null_string, 0 }
54};
55
56
57static ngx_command_t ngx_http_memcached_commands[] = {
58
59 { ngx_string("memcached_pass"),
60 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
61 ngx_http_memcached_pass,
62 NGX_HTTP_LOC_CONF_OFFSET,
63 0,
64 NULL },
65
66 { ngx_string("memcached_connect_timeout"),
67 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
68 ngx_conf_set_msec_slot,
69 NGX_HTTP_LOC_CONF_OFFSET,
70 offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout),
71 NULL },
72
73 { ngx_string("memcached_send_timeout"),
74 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
75 ngx_conf_set_msec_slot,
76 NGX_HTTP_LOC_CONF_OFFSET,
77 offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout),
78 NULL },
79
80 { ngx_string("memcached_buffer_size"),
81 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
82 ngx_conf_set_size_slot,
83 NGX_HTTP_LOC_CONF_OFFSET,
84 offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size),
85 NULL },
86
87 { ngx_string("memcached_read_timeout"),
88 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
89 ngx_conf_set_msec_slot,
90 NGX_HTTP_LOC_CONF_OFFSET,
91 offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout),
92 NULL },
93
94 { ngx_string("memcached_next_upstream"),
95 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
96 ngx_conf_set_bitmask_slot,
97 NGX_HTTP_LOC_CONF_OFFSET,
98 offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
99 &ngx_http_memcached_next_upstream_masks },
100
101 { ngx_string("memcached_upstream_max_fails"),
102 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000103 ngx_http_memcached_upstream_max_fails_unsupported,
104 0,
105 0,
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000106 NULL },
107
108 { ngx_string("memcached_upstream_fail_timeout"),
109 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000110 ngx_http_memcached_upstream_fail_timeout_unsupported,
111 0,
112 0,
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000113 NULL },
114
115 ngx_null_command
116};
117
118
Igor Sysoev8f125582006-07-28 15:16:17 +0000119static ngx_http_module_t ngx_http_memcached_module_ctx = {
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000120 NULL, /* preconfiguration */
121 NULL, /* postconfiguration */
122
123 NULL, /* create main configuration */
124 NULL, /* init main configuration */
125
126 NULL, /* create server configuration */
127 NULL, /* merge server configuration */
128
129 ngx_http_memcached_create_loc_conf, /* create location configration */
130 ngx_http_memcached_merge_loc_conf /* merge location configration */
131};
132
133
134ngx_module_t ngx_http_memcached_module = {
135 NGX_MODULE_V1,
136 &ngx_http_memcached_module_ctx, /* module context */
137 ngx_http_memcached_commands, /* module directives */
138 NGX_HTTP_MODULE, /* module type */
139 NULL, /* init master */
140 NULL, /* init module */
141 NULL, /* init process */
142 NULL, /* init thread */
143 NULL, /* exit thread */
144 NULL, /* exit process */
145 NULL, /* exit master */
146 NGX_MODULE_V1_PADDING
147};
148
149
150#define NGX_HTTP_MEMCACHED_END (sizeof(ngx_http_memcached_end) - 1)
151static u_char ngx_http_memcached_end[] = CRLF "END" CRLF;
152
153
154static ngx_int_t
155ngx_http_memcached_handler(ngx_http_request_t *r)
156{
157 ngx_int_t rc;
158 ngx_http_upstream_t *u;
159 ngx_http_memcached_ctx_t *ctx;
160 ngx_http_memcached_loc_conf_t *mlcf;
161
Igor Sysoevac72bd12006-05-04 15:32:46 +0000162 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000163 return NGX_HTTP_NOT_ALLOWED;
164 }
165
166 rc = ngx_http_discard_body(r);
167
168 if (rc != NGX_OK && rc != NGX_AGAIN) {
169 return rc;
170 }
171
172 if (ngx_http_set_content_type(r) != NGX_OK) {
173 return NGX_HTTP_INTERNAL_SERVER_ERROR;
174 }
175
176 mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
177
178 u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
179 if (u == NULL) {
180 return NGX_HTTP_INTERNAL_SERVER_ERROR;
181 }
182
183 u->peer.log = r->connection->log;
184 u->peer.log_error = NGX_ERROR_ERR;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000185#if (NGX_THREADS)
186 u->peer.lock = &r->connection->lock;
187#endif
188
189 u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
190
191 u->conf = &mlcf->upstream;
192
193 u->create_request = ngx_http_memcached_create_request;
194 u->reinit_request = ngx_http_memcached_reinit_request;
195 u->process_header = ngx_http_memcached_process_header;
196 u->abort_request = ngx_http_memcached_abort_request;
197 u->finalize_request = ngx_http_memcached_finalize_request;
198
199 r->upstream = u;
200
201 ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
202 if (ctx == NULL) {
203 return NGX_HTTP_INTERNAL_SERVER_ERROR;
204 }
205
206 ctx->rest = NGX_HTTP_MEMCACHED_END;
207 ctx->request = r;
208
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000209 ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
210
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000211 u->input_filter_init = ngx_http_memcached_filter_init;
212 u->input_filter = ngx_http_memcached_filter;
213 u->input_filter_ctx = ctx;
214
215 ngx_http_upstream_init(r);
216
217 return NGX_DONE;
218}
219
220
221static ngx_int_t
222ngx_http_memcached_create_request(ngx_http_request_t *r)
223{
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000224 size_t len;
225 ngx_buf_t *b;
226 ngx_chain_t *cl;
227 ngx_http_memcached_ctx_t *ctx;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000228
229 len = sizeof("get ") - 1 + r->uri.len + sizeof(" " CRLF) - 1;
230 if (r->args.len) {
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000231 len += 1 + r->args.len;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000232 }
233
234 b = ngx_create_temp_buf(r->pool, len);
235 if (b == NULL) {
236 return NGX_ERROR;
237 }
238
239 cl = ngx_alloc_chain_link(r->pool);
240 if (cl == NULL) {
241 return NGX_ERROR;
242 }
243
244 cl->buf = b;
245 cl->next = NULL;
246
247 r->upstream->request_bufs = cl;
248
249 *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' ';
250
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000251 ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
252
253 ctx->key.data = b->last;
254
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000255 b->last = ngx_copy(b->last, r->uri.data, r->uri.len);
256
257 if (r->args.len) {
258 *b->last++ = '?';
259 b->last = ngx_copy(b->last, r->args.data, r->args.len);
260 }
261
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000262 ctx->key.len = b->last - ctx->key.data;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000263
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000264 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000265 "http memcached request: \"%V\"", &ctx->key);
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000266
267 *b->last++ = ' '; *b->last++ = CR; *b->last++ = LF;
268
269 return NGX_OK;
270}
271
272
273static ngx_int_t
274ngx_http_memcached_reinit_request(ngx_http_request_t *r)
275{
276 return NGX_OK;
277}
278
279
280static ngx_int_t
281ngx_http_memcached_process_header(ngx_http_request_t *r)
282{
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000283 u_char *p, *len;
284 ngx_str_t line;
285 ngx_http_upstream_t *u;
286 ngx_http_memcached_ctx_t *ctx;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000287
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
298found:
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
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000310 ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
311
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000312 if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) {
313
314 p += sizeof("VALUE ") - 1;
315
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000316 if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) {
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000317 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
318 "memcached sent invalid key in response \"%V\" "
319 "for key \"%V\"",
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000320 &line, &ctx->key);
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000321
322 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
323 }
324
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000325 p += ctx->key.len;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000326
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
347 r->headers_out.content_length_n = ngx_atoof(len, p - len - 1);
348 if (r->headers_out.content_length_n == -1) {
349 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
350 "memcached sent invalid length in response \"%V\" "
351 "for key \"%V\"",
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000352 &line, &ctx->key);
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000353 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
354 }
355
356 u->headers_in.status_n = 200;
357 u->buffer.pos = p + 1;
358
359 return NGX_OK;
360 }
361
362 if (ngx_strcmp(p, "END\x0d") == 0) {
363 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000364 "key: \"%V\" was not found by memcached", &ctx->key);
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000365
366 u->headers_in.status_n = 404;
367
368 return NGX_OK;
369 }
370
371no_valid:
372
373 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
374 "memcached sent invalid response: \"%V\"", &line);
375
376 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
377}
378
379
380static ngx_int_t
381ngx_http_memcached_filter_init(void *data)
382{
383 ngx_http_memcached_ctx_t *ctx = data;
384
385 ngx_http_upstream_t *u;
386
387 u = ctx->request->upstream;
388
389 u->length += NGX_HTTP_MEMCACHED_END;
390
391 return NGX_OK;
392}
393
394
395static ngx_int_t
396ngx_http_memcached_filter(void *data, ssize_t bytes)
397{
398 ngx_http_memcached_ctx_t *ctx = data;
399
400 u_char *last;
401 ngx_buf_t *b;
402 ngx_chain_t *cl, **ll;
403 ngx_http_upstream_t *u;
404
405 u = ctx->request->upstream;
406 b = &u->buffer;
407
408 if (u->length == ctx->rest) {
409
410 if (ngx_strncmp(b->last,
411 ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END
412 - ctx->rest,
413 bytes) != 0)
414 {
415 ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
416 "memcached sent invalid trailer");
417 }
418
419 u->length -= bytes;
420 ctx->rest -= bytes;
421
422 return NGX_OK;
423 }
424
425 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
426 ll = &cl->next;
427 }
428
429 cl = ngx_chain_get_free_buf(ctx->request->pool, &u->free_bufs);
430 if (cl == NULL) {
431 return NGX_ERROR;
432 }
433
434 cl->buf->flush = 1;
435 cl->buf->memory = 1;
436
437 *ll = cl;
438
439 cl->buf->pos = b->last;
440 b->last += bytes;
441 cl->buf->last = b->last;
442
443 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
444 "memcached filter bytes:%z size:%z length:%z rest:%z",
445 bytes, b->last - b->pos, u->length, ctx->rest);
446
447 if (b->last - b->pos <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) {
448 u->length -= bytes;
449 return NGX_OK;
450 }
451
452
453 last = b->pos + u->length - NGX_HTTP_MEMCACHED_END;
454
455 if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
456 ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
457 "memcached sent invalid trailer");
458 }
459
460 ctx->rest = u->length - (b->last - b->pos);
461 b->last = last;
462 cl->buf->last = last;
463 u->length = ctx->rest;
464
465 return NGX_OK;
466}
467
468
469static void
470ngx_http_memcached_abort_request(ngx_http_request_t *r)
471{
472 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
473 "abort http memcached request");
474 return;
475}
476
477
478static void
479ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
480{
481 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
482 "finalize http memcached request");
483 return;
484}
485
486
487static void *
488ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
489{
490 ngx_http_memcached_loc_conf_t *conf;
491
492 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
493 if (conf == NULL) {
494 return NGX_CONF_ERROR;
495 }
496
497 /*
498 * set by ngx_pcalloc():
499 *
500 * conf->upstream.bufs.num = 0;
501 * conf->upstream.next_upstream = 0;
502 * conf->upstream.temp_path = NULL;
503 * conf->upstream.schema = { 0, NULL };
504 * conf->upstream.uri = { 0, NULL };
505 * conf->upstream.location = NULL;
506 *
507 * conf->peers = NULL;
508 */
509
510 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
511 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
512 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
513
514 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
515
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000516 /* the hardcoded values */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000517 conf->upstream.cyclic_temp_file = 0;
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000518 conf->upstream.buffering = 0;
519 conf->upstream.ignore_client_abort = 0;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000520 conf->upstream.send_lowat = 0;
521 conf->upstream.bufs.num = 0;
522 conf->upstream.busy_buffers_size = 0;
523 conf->upstream.max_temp_file_size = 0;
524 conf->upstream.temp_file_write_size = 0;
Igor Sysoevef809b82006-06-28 16:00:26 +0000525 conf->upstream.intercept_errors = 1;
Igor Sysoevef316432006-08-16 13:09:33 +0000526 conf->upstream.intercept_404 = 1;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000527 conf->upstream.pass_request_headers = 0;
528 conf->upstream.pass_request_body = 0;
529
530 return conf;
531}
532
533
534static char *
535ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
536{
537 ngx_http_memcached_loc_conf_t *prev = parent;
538 ngx_http_memcached_loc_conf_t *conf = child;
539
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000540 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
541 prev->upstream.connect_timeout, 60000);
542
543 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
544 prev->upstream.send_timeout, 60000);
545
546 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
547 prev->upstream.read_timeout, 60000);
548
549 ngx_conf_merge_size_value(conf->upstream.buffer_size,
550 prev->upstream.buffer_size,
551 (size_t) ngx_pagesize);
552
553 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
554 prev->upstream.next_upstream,
555 (NGX_CONF_BITMASK_SET
556 |NGX_HTTP_UPSTREAM_FT_ERROR
557 |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
558
Igor Sysoevbb28b6d2006-07-11 13:20:19 +0000559 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
560 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
561 |NGX_HTTP_UPSTREAM_FT_OFF;
562 }
563
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000564 return NGX_CONF_OK;
565}
566
567
568static char *
569ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
570{
571 ngx_http_memcached_loc_conf_t *lcf = conf;
572
573 ngx_str_t *value;
Igor Sysoev914bcbd2006-10-24 13:50:35 +0000574 ngx_url_t u;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000575 ngx_http_core_loc_conf_t *clcf;
576
577 if (lcf->upstream.schema.len) {
578 return "is duplicate";
579 }
580
581 value = cf->args->elts;
582
Igor Sysoev914bcbd2006-10-24 13:50:35 +0000583 ngx_memzero(&u, sizeof(ngx_url_t));
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000584
Igor Sysoev914bcbd2006-10-24 13:50:35 +0000585 u.url = value[1];
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000586 u.no_resolve = 1;
587 /* u.uri_part = 1; may be used as namespace */
Igor Sysoev62f87be2006-10-25 16:19:03 +0000588
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000589 lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
590 if (lcf->upstream.upstream == NULL) {
591 return NGX_CONF_ERROR;
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000592 }
593
Igor Sysoevc31a9bb2005-11-26 10:11:11 +0000594 lcf->upstream.schema.len = sizeof("memcached://") - 1;
595 lcf->upstream.schema.data = (u_char *) "memcached://";
596
597 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
598
599 clcf->handler = ngx_http_memcached_handler;
600
601 lcf->upstream.location = clcf->name;
602
603 if (clcf->name.data[clcf->name.len - 1] == '/') {
604 clcf->auto_redirect = 1;
605 }
606
607 return NGX_CONF_OK;
608}
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000609
610
611static char *
612ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
613 ngx_command_t *cmd, void *conf)
614{
615 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
616 "\"memcached_upstream_max_fails\" is not supported, "
617 "use the \"max_fails\" parameter of the \"server\" directive ",
618 "inside the \"upstream\" block");
619
620 return NGX_CONF_ERROR;
621}
622
623
624static char *
625ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
626 ngx_command_t *cmd, void *conf)
627{
628 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
629 "\"memcached_upstream_fail_timeout\" is not supported, "
630 "use the \"fail_timeout\" parameter of the \"server\" directive ",
631 "inside the \"upstream\" block");
632
633 return NGX_CONF_ERROR;
634}