Annotation of embedaddon/nginx/src/http/modules/ngx_http_memcached_module.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11:
! 12:
! 13: typedef struct {
! 14: ngx_http_upstream_conf_t upstream;
! 15: ngx_int_t index;
! 16: ngx_uint_t gzip_flag;
! 17: } ngx_http_memcached_loc_conf_t;
! 18:
! 19:
! 20: typedef struct {
! 21: size_t rest;
! 22: ngx_http_request_t *request;
! 23: ngx_str_t key;
! 24: } ngx_http_memcached_ctx_t;
! 25:
! 26:
! 27: static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r);
! 28: static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r);
! 29: static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r);
! 30: static ngx_int_t ngx_http_memcached_filter_init(void *data);
! 31: static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes);
! 32: static void ngx_http_memcached_abort_request(ngx_http_request_t *r);
! 33: static void ngx_http_memcached_finalize_request(ngx_http_request_t *r,
! 34: ngx_int_t rc);
! 35:
! 36: static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf);
! 37: static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf,
! 38: void *parent, void *child);
! 39:
! 40: static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
! 41: void *conf);
! 42:
! 43:
! 44: static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = {
! 45: { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
! 46: { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
! 47: { ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
! 48: { ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
! 49: { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
! 50: { ngx_null_string, 0 }
! 51: };
! 52:
! 53:
! 54: static ngx_command_t ngx_http_memcached_commands[] = {
! 55:
! 56: { ngx_string("memcached_pass"),
! 57: NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
! 58: ngx_http_memcached_pass,
! 59: NGX_HTTP_LOC_CONF_OFFSET,
! 60: 0,
! 61: NULL },
! 62:
! 63: { ngx_string("memcached_bind"),
! 64: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 65: ngx_http_upstream_bind_set_slot,
! 66: NGX_HTTP_LOC_CONF_OFFSET,
! 67: offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
! 68: NULL },
! 69:
! 70: { ngx_string("memcached_connect_timeout"),
! 71: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 72: ngx_conf_set_msec_slot,
! 73: NGX_HTTP_LOC_CONF_OFFSET,
! 74: offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout),
! 75: NULL },
! 76:
! 77: { ngx_string("memcached_send_timeout"),
! 78: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 79: ngx_conf_set_msec_slot,
! 80: NGX_HTTP_LOC_CONF_OFFSET,
! 81: offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout),
! 82: NULL },
! 83:
! 84: { ngx_string("memcached_buffer_size"),
! 85: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 86: ngx_conf_set_size_slot,
! 87: NGX_HTTP_LOC_CONF_OFFSET,
! 88: offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size),
! 89: NULL },
! 90:
! 91: { ngx_string("memcached_read_timeout"),
! 92: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 93: ngx_conf_set_msec_slot,
! 94: NGX_HTTP_LOC_CONF_OFFSET,
! 95: offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout),
! 96: NULL },
! 97:
! 98: { ngx_string("memcached_next_upstream"),
! 99: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
! 100: ngx_conf_set_bitmask_slot,
! 101: NGX_HTTP_LOC_CONF_OFFSET,
! 102: offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
! 103: &ngx_http_memcached_next_upstream_masks },
! 104:
! 105: { ngx_string("memcached_gzip_flag"),
! 106: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 107: ngx_conf_set_num_slot,
! 108: NGX_HTTP_LOC_CONF_OFFSET,
! 109: offsetof(ngx_http_memcached_loc_conf_t, gzip_flag),
! 110: NULL },
! 111:
! 112: ngx_null_command
! 113: };
! 114:
! 115:
! 116: static ngx_http_module_t ngx_http_memcached_module_ctx = {
! 117: NULL, /* preconfiguration */
! 118: NULL, /* postconfiguration */
! 119:
! 120: NULL, /* create main configuration */
! 121: NULL, /* init main configuration */
! 122:
! 123: NULL, /* create server configuration */
! 124: NULL, /* merge server configuration */
! 125:
! 126: ngx_http_memcached_create_loc_conf, /* create location configuration */
! 127: ngx_http_memcached_merge_loc_conf /* merge location configuration */
! 128: };
! 129:
! 130:
! 131: ngx_module_t ngx_http_memcached_module = {
! 132: NGX_MODULE_V1,
! 133: &ngx_http_memcached_module_ctx, /* module context */
! 134: ngx_http_memcached_commands, /* module directives */
! 135: NGX_HTTP_MODULE, /* module type */
! 136: NULL, /* init master */
! 137: NULL, /* init module */
! 138: NULL, /* init process */
! 139: NULL, /* init thread */
! 140: NULL, /* exit thread */
! 141: NULL, /* exit process */
! 142: NULL, /* exit master */
! 143: NGX_MODULE_V1_PADDING
! 144: };
! 145:
! 146:
! 147: static ngx_str_t ngx_http_memcached_key = ngx_string("memcached_key");
! 148:
! 149:
! 150: #define NGX_HTTP_MEMCACHED_END (sizeof(ngx_http_memcached_end) - 1)
! 151: static u_char ngx_http_memcached_end[] = CRLF "END" CRLF;
! 152:
! 153:
! 154: static ngx_int_t
! 155: ngx_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:
! 162: if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
! 163: return NGX_HTTP_NOT_ALLOWED;
! 164: }
! 165:
! 166: rc = ngx_http_discard_request_body(r);
! 167:
! 168: if (rc != NGX_OK) {
! 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: if (ngx_http_upstream_create(r) != NGX_OK) {
! 177: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 178: }
! 179:
! 180: u = r->upstream;
! 181:
! 182: ngx_str_set(&u->schema, "memcached://");
! 183: u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
! 184:
! 185: mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
! 186:
! 187: u->conf = &mlcf->upstream;
! 188:
! 189: u->create_request = ngx_http_memcached_create_request;
! 190: u->reinit_request = ngx_http_memcached_reinit_request;
! 191: u->process_header = ngx_http_memcached_process_header;
! 192: u->abort_request = ngx_http_memcached_abort_request;
! 193: u->finalize_request = ngx_http_memcached_finalize_request;
! 194:
! 195: ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
! 196: if (ctx == NULL) {
! 197: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 198: }
! 199:
! 200: ctx->rest = NGX_HTTP_MEMCACHED_END;
! 201: ctx->request = r;
! 202:
! 203: ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
! 204:
! 205: u->input_filter_init = ngx_http_memcached_filter_init;
! 206: u->input_filter = ngx_http_memcached_filter;
! 207: u->input_filter_ctx = ctx;
! 208:
! 209: r->main->count++;
! 210:
! 211: ngx_http_upstream_init(r);
! 212:
! 213: return NGX_DONE;
! 214: }
! 215:
! 216:
! 217: static ngx_int_t
! 218: ngx_http_memcached_create_request(ngx_http_request_t *r)
! 219: {
! 220: size_t len;
! 221: uintptr_t escape;
! 222: ngx_buf_t *b;
! 223: ngx_chain_t *cl;
! 224: ngx_http_memcached_ctx_t *ctx;
! 225: ngx_http_variable_value_t *vv;
! 226: ngx_http_memcached_loc_conf_t *mlcf;
! 227:
! 228: mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
! 229:
! 230: vv = ngx_http_get_indexed_variable(r, mlcf->index);
! 231:
! 232: if (vv == NULL || vv->not_found || vv->len == 0) {
! 233: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 234: "the \"$memcached_key\" variable is not set");
! 235: return NGX_ERROR;
! 236: }
! 237:
! 238: escape = 2 * ngx_escape_uri(NULL, vv->data, vv->len, NGX_ESCAPE_MEMCACHED);
! 239:
! 240: len = sizeof("get ") - 1 + vv->len + escape + sizeof(CRLF) - 1;
! 241:
! 242: b = ngx_create_temp_buf(r->pool, len);
! 243: if (b == NULL) {
! 244: return NGX_ERROR;
! 245: }
! 246:
! 247: cl = ngx_alloc_chain_link(r->pool);
! 248: if (cl == NULL) {
! 249: return NGX_ERROR;
! 250: }
! 251:
! 252: cl->buf = b;
! 253: cl->next = NULL;
! 254:
! 255: r->upstream->request_bufs = cl;
! 256:
! 257: *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' ';
! 258:
! 259: ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
! 260:
! 261: ctx->key.data = b->last;
! 262:
! 263: if (escape == 0) {
! 264: b->last = ngx_copy(b->last, vv->data, vv->len);
! 265:
! 266: } else {
! 267: b->last = (u_char *) ngx_escape_uri(b->last, vv->data, vv->len,
! 268: NGX_ESCAPE_MEMCACHED);
! 269: }
! 270:
! 271: ctx->key.len = b->last - ctx->key.data;
! 272:
! 273: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 274: "http memcached request: \"%V\"", &ctx->key);
! 275:
! 276: *b->last++ = CR; *b->last++ = LF;
! 277:
! 278: return NGX_OK;
! 279: }
! 280:
! 281:
! 282: static ngx_int_t
! 283: ngx_http_memcached_reinit_request(ngx_http_request_t *r)
! 284: {
! 285: return NGX_OK;
! 286: }
! 287:
! 288:
! 289: static ngx_int_t
! 290: ngx_http_memcached_process_header(ngx_http_request_t *r)
! 291: {
! 292: u_char *p, *start;
! 293: ngx_str_t line;
! 294: ngx_uint_t flags;
! 295: ngx_table_elt_t *h;
! 296: ngx_http_upstream_t *u;
! 297: ngx_http_memcached_ctx_t *ctx;
! 298: ngx_http_memcached_loc_conf_t *mlcf;
! 299:
! 300: u = r->upstream;
! 301:
! 302: for (p = u->buffer.pos; p < u->buffer.last; p++) {
! 303: if (*p == LF) {
! 304: goto found;
! 305: }
! 306: }
! 307:
! 308: return NGX_AGAIN;
! 309:
! 310: found:
! 311:
! 312: *p = '\0';
! 313:
! 314: line.len = p - u->buffer.pos - 1;
! 315: line.data = u->buffer.pos;
! 316:
! 317: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 318: "memcached: \"%V\"", &line);
! 319:
! 320: p = u->buffer.pos;
! 321:
! 322: ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
! 323: mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
! 324:
! 325: if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) {
! 326:
! 327: p += sizeof("VALUE ") - 1;
! 328:
! 329: if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) {
! 330: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 331: "memcached sent invalid key in response \"%V\" "
! 332: "for key \"%V\"",
! 333: &line, &ctx->key);
! 334:
! 335: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
! 336: }
! 337:
! 338: p += ctx->key.len;
! 339:
! 340: if (*p++ != ' ') {
! 341: goto no_valid;
! 342: }
! 343:
! 344: /* flags */
! 345:
! 346: start = p;
! 347:
! 348: while (*p) {
! 349: if (*p++ == ' ') {
! 350: if (mlcf->gzip_flag) {
! 351: goto flags;
! 352: } else {
! 353: goto length;
! 354: }
! 355: }
! 356: }
! 357:
! 358: goto no_valid;
! 359:
! 360: flags:
! 361:
! 362: flags = ngx_atoi(start, p - start - 1);
! 363:
! 364: if (flags == (ngx_uint_t) NGX_ERROR) {
! 365: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 366: "memcached sent invalid flags in response \"%V\" "
! 367: "for key \"%V\"",
! 368: &line, &ctx->key);
! 369: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
! 370: }
! 371:
! 372: if (flags & mlcf->gzip_flag) {
! 373: h = ngx_list_push(&r->headers_out.headers);
! 374: if (h == NULL) {
! 375: return NGX_ERROR;
! 376: }
! 377:
! 378: h->hash = 1;
! 379: h->key.len = sizeof("Content-Encoding") - 1;
! 380: h->key.data = (u_char *) "Content-Encoding";
! 381: h->value.len = sizeof("gzip") - 1;
! 382: h->value.data = (u_char *) "gzip";
! 383:
! 384: r->headers_out.content_encoding = h;
! 385: }
! 386:
! 387: length:
! 388:
! 389: start = p;
! 390:
! 391: while (*p && *p++ != CR) { /* void */ }
! 392:
! 393: u->headers_in.content_length_n = ngx_atoof(start, p - start - 1);
! 394: if (u->headers_in.content_length_n == -1) {
! 395: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 396: "memcached sent invalid length in response \"%V\" "
! 397: "for key \"%V\"",
! 398: &line, &ctx->key);
! 399: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
! 400: }
! 401:
! 402: u->headers_in.status_n = 200;
! 403: u->state->status = 200;
! 404: u->buffer.pos = p + 1;
! 405:
! 406: return NGX_OK;
! 407: }
! 408:
! 409: if (ngx_strcmp(p, "END\x0d") == 0) {
! 410: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
! 411: "key: \"%V\" was not found by memcached", &ctx->key);
! 412:
! 413: u->headers_in.status_n = 404;
! 414: u->state->status = 404;
! 415: u->keepalive = 1;
! 416:
! 417: return NGX_OK;
! 418: }
! 419:
! 420: no_valid:
! 421:
! 422: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 423: "memcached sent invalid response: \"%V\"", &line);
! 424:
! 425: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
! 426: }
! 427:
! 428:
! 429: static ngx_int_t
! 430: ngx_http_memcached_filter_init(void *data)
! 431: {
! 432: ngx_http_memcached_ctx_t *ctx = data;
! 433:
! 434: ngx_http_upstream_t *u;
! 435:
! 436: u = ctx->request->upstream;
! 437:
! 438: u->length += NGX_HTTP_MEMCACHED_END;
! 439:
! 440: return NGX_OK;
! 441: }
! 442:
! 443:
! 444: static ngx_int_t
! 445: ngx_http_memcached_filter(void *data, ssize_t bytes)
! 446: {
! 447: ngx_http_memcached_ctx_t *ctx = data;
! 448:
! 449: u_char *last;
! 450: ngx_buf_t *b;
! 451: ngx_chain_t *cl, **ll;
! 452: ngx_http_upstream_t *u;
! 453:
! 454: u = ctx->request->upstream;
! 455: b = &u->buffer;
! 456:
! 457: if (u->length == (ssize_t) ctx->rest) {
! 458:
! 459: if (ngx_strncmp(b->last,
! 460: ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
! 461: bytes)
! 462: != 0)
! 463: {
! 464: ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
! 465: "memcached sent invalid trailer");
! 466:
! 467: u->length = 0;
! 468: ctx->rest = 0;
! 469:
! 470: return NGX_OK;
! 471: }
! 472:
! 473: u->length -= bytes;
! 474: ctx->rest -= bytes;
! 475:
! 476: if (u->length == 0) {
! 477: u->keepalive = 1;
! 478: }
! 479:
! 480: return NGX_OK;
! 481: }
! 482:
! 483: for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
! 484: ll = &cl->next;
! 485: }
! 486:
! 487: cl = ngx_chain_get_free_buf(ctx->request->pool, &u->free_bufs);
! 488: if (cl == NULL) {
! 489: return NGX_ERROR;
! 490: }
! 491:
! 492: cl->buf->flush = 1;
! 493: cl->buf->memory = 1;
! 494:
! 495: *ll = cl;
! 496:
! 497: last = b->last;
! 498: cl->buf->pos = last;
! 499: b->last += bytes;
! 500: cl->buf->last = b->last;
! 501: cl->buf->tag = u->output.tag;
! 502:
! 503: ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
! 504: "memcached filter bytes:%z size:%z length:%z rest:%z",
! 505: bytes, b->last - b->pos, u->length, ctx->rest);
! 506:
! 507: if (bytes <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) {
! 508: u->length -= bytes;
! 509: return NGX_OK;
! 510: }
! 511:
! 512: last += u->length - NGX_HTTP_MEMCACHED_END;
! 513:
! 514: if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
! 515: ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
! 516: "memcached sent invalid trailer");
! 517:
! 518: b->last = last;
! 519: cl->buf->last = last;
! 520: u->length = 0;
! 521: ctx->rest = 0;
! 522:
! 523: return NGX_OK;
! 524: }
! 525:
! 526: ctx->rest -= b->last - last;
! 527: b->last = last;
! 528: cl->buf->last = last;
! 529: u->length = ctx->rest;
! 530:
! 531: if (u->length == 0) {
! 532: u->keepalive = 1;
! 533: }
! 534:
! 535: return NGX_OK;
! 536: }
! 537:
! 538:
! 539: static void
! 540: ngx_http_memcached_abort_request(ngx_http_request_t *r)
! 541: {
! 542: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 543: "abort http memcached request");
! 544: return;
! 545: }
! 546:
! 547:
! 548: static void
! 549: ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
! 550: {
! 551: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 552: "finalize http memcached request");
! 553: return;
! 554: }
! 555:
! 556:
! 557: static void *
! 558: ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
! 559: {
! 560: ngx_http_memcached_loc_conf_t *conf;
! 561:
! 562: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
! 563: if (conf == NULL) {
! 564: return NULL;
! 565: }
! 566:
! 567: /*
! 568: * set by ngx_pcalloc():
! 569: *
! 570: * conf->upstream.bufs.num = 0;
! 571: * conf->upstream.next_upstream = 0;
! 572: * conf->upstream.temp_path = NULL;
! 573: * conf->upstream.uri = { 0, NULL };
! 574: * conf->upstream.location = NULL;
! 575: */
! 576:
! 577: conf->upstream.local = NGX_CONF_UNSET_PTR;
! 578: conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
! 579: conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
! 580: conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
! 581:
! 582: conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
! 583:
! 584: /* the hardcoded values */
! 585: conf->upstream.cyclic_temp_file = 0;
! 586: conf->upstream.buffering = 0;
! 587: conf->upstream.ignore_client_abort = 0;
! 588: conf->upstream.send_lowat = 0;
! 589: conf->upstream.bufs.num = 0;
! 590: conf->upstream.busy_buffers_size = 0;
! 591: conf->upstream.max_temp_file_size = 0;
! 592: conf->upstream.temp_file_write_size = 0;
! 593: conf->upstream.intercept_errors = 1;
! 594: conf->upstream.intercept_404 = 1;
! 595: conf->upstream.pass_request_headers = 0;
! 596: conf->upstream.pass_request_body = 0;
! 597:
! 598: conf->index = NGX_CONF_UNSET;
! 599: conf->gzip_flag = NGX_CONF_UNSET_UINT;
! 600:
! 601: return conf;
! 602: }
! 603:
! 604:
! 605: static char *
! 606: ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
! 607: {
! 608: ngx_http_memcached_loc_conf_t *prev = parent;
! 609: ngx_http_memcached_loc_conf_t *conf = child;
! 610:
! 611: ngx_conf_merge_ptr_value(conf->upstream.local,
! 612: prev->upstream.local, NULL);
! 613:
! 614: ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
! 615: prev->upstream.connect_timeout, 60000);
! 616:
! 617: ngx_conf_merge_msec_value(conf->upstream.send_timeout,
! 618: prev->upstream.send_timeout, 60000);
! 619:
! 620: ngx_conf_merge_msec_value(conf->upstream.read_timeout,
! 621: prev->upstream.read_timeout, 60000);
! 622:
! 623: ngx_conf_merge_size_value(conf->upstream.buffer_size,
! 624: prev->upstream.buffer_size,
! 625: (size_t) ngx_pagesize);
! 626:
! 627: ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
! 628: prev->upstream.next_upstream,
! 629: (NGX_CONF_BITMASK_SET
! 630: |NGX_HTTP_UPSTREAM_FT_ERROR
! 631: |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
! 632:
! 633: if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
! 634: conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
! 635: |NGX_HTTP_UPSTREAM_FT_OFF;
! 636: }
! 637:
! 638: if (conf->upstream.upstream == NULL) {
! 639: conf->upstream.upstream = prev->upstream.upstream;
! 640: }
! 641:
! 642: if (conf->index == NGX_CONF_UNSET) {
! 643: conf->index = prev->index;
! 644: }
! 645:
! 646: ngx_conf_merge_uint_value(conf->gzip_flag, prev->gzip_flag, 0);
! 647:
! 648: return NGX_CONF_OK;
! 649: }
! 650:
! 651:
! 652: static char *
! 653: ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 654: {
! 655: ngx_http_memcached_loc_conf_t *mlcf = conf;
! 656:
! 657: ngx_str_t *value;
! 658: ngx_url_t u;
! 659: ngx_http_core_loc_conf_t *clcf;
! 660:
! 661: if (mlcf->upstream.upstream) {
! 662: return "is duplicate";
! 663: }
! 664:
! 665: value = cf->args->elts;
! 666:
! 667: ngx_memzero(&u, sizeof(ngx_url_t));
! 668:
! 669: u.url = value[1];
! 670: u.no_resolve = 1;
! 671:
! 672: mlcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
! 673: if (mlcf->upstream.upstream == NULL) {
! 674: return NGX_CONF_ERROR;
! 675: }
! 676:
! 677: clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
! 678:
! 679: clcf->handler = ngx_http_memcached_handler;
! 680:
! 681: if (clcf->name.data[clcf->name.len - 1] == '/') {
! 682: clcf->auto_redirect = 1;
! 683: }
! 684:
! 685: mlcf->index = ngx_http_get_variable_index(cf, &ngx_http_memcached_key);
! 686:
! 687: if (mlcf->index == NGX_ERROR) {
! 688: return NGX_CONF_ERROR;
! 689: }
! 690:
! 691: return NGX_CONF_OK;
! 692: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>