Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_http_upstream_conf_t   upstream;
0015     ngx_int_t                  index;
0016     ngx_uint_t                 gzip_flag;
0017 } ngx_http_memcached_loc_conf_t;
0018 
0019 
0020 typedef struct {
0021     size_t                     rest;
0022     ngx_http_request_t        *request;
0023     ngx_str_t                  key;
0024 } ngx_http_memcached_ctx_t;
0025 
0026 
0027 static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r);
0028 static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r);
0029 static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r);
0030 static ngx_int_t ngx_http_memcached_filter_init(void *data);
0031 static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes);
0032 static void ngx_http_memcached_abort_request(ngx_http_request_t *r);
0033 static void ngx_http_memcached_finalize_request(ngx_http_request_t *r,
0034     ngx_int_t rc);
0035 
0036 static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf);
0037 static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf,
0038     void *parent, void *child);
0039 
0040 static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
0041     void *conf);
0042 
0043 
0044 static ngx_conf_bitmask_t  ngx_http_memcached_next_upstream_masks[] = {
0045     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
0046     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
0047     { ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
0048     { ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
0049     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
0050     { ngx_null_string, 0 }
0051 };
0052 
0053 
0054 static ngx_command_t  ngx_http_memcached_commands[] = {
0055 
0056     { ngx_string("memcached_pass"),
0057       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
0058       ngx_http_memcached_pass,
0059       NGX_HTTP_LOC_CONF_OFFSET,
0060       0,
0061       NULL },
0062 
0063     { ngx_string("memcached_bind"),
0064       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0065       ngx_http_upstream_bind_set_slot,
0066       NGX_HTTP_LOC_CONF_OFFSET,
0067       offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
0068       NULL },
0069 
0070     { ngx_string("memcached_connect_timeout"),
0071       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0072       ngx_conf_set_msec_slot,
0073       NGX_HTTP_LOC_CONF_OFFSET,
0074       offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout),
0075       NULL },
0076 
0077     { ngx_string("memcached_send_timeout"),
0078       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0079       ngx_conf_set_msec_slot,
0080       NGX_HTTP_LOC_CONF_OFFSET,
0081       offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout),
0082       NULL },
0083 
0084     { ngx_string("memcached_buffer_size"),
0085       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0086       ngx_conf_set_size_slot,
0087       NGX_HTTP_LOC_CONF_OFFSET,
0088       offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size),
0089       NULL },
0090 
0091     { ngx_string("memcached_read_timeout"),
0092       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0093       ngx_conf_set_msec_slot,
0094       NGX_HTTP_LOC_CONF_OFFSET,
0095       offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout),
0096       NULL },
0097 
0098     { ngx_string("memcached_next_upstream"),
0099       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0100       ngx_conf_set_bitmask_slot,
0101       NGX_HTTP_LOC_CONF_OFFSET,
0102       offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
0103       &ngx_http_memcached_next_upstream_masks },
0104 
0105     { ngx_string("memcached_next_upstream_tries"),
0106       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0107       ngx_conf_set_num_slot,
0108       NGX_HTTP_LOC_CONF_OFFSET,
0109       offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream_tries),
0110       NULL },
0111 
0112     { ngx_string("memcached_next_upstream_timeout"),
0113       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0114       ngx_conf_set_msec_slot,
0115       NGX_HTTP_LOC_CONF_OFFSET,
0116       offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream_timeout),
0117       NULL },
0118 
0119     { ngx_string("memcached_gzip_flag"),
0120       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0121       ngx_conf_set_num_slot,
0122       NGX_HTTP_LOC_CONF_OFFSET,
0123       offsetof(ngx_http_memcached_loc_conf_t, gzip_flag),
0124       NULL },
0125 
0126       ngx_null_command
0127 };
0128 
0129 
0130 static ngx_http_module_t  ngx_http_memcached_module_ctx = {
0131     NULL,                                  /* preconfiguration */
0132     NULL,                                  /* postconfiguration */
0133 
0134     NULL,                                  /* create main configuration */
0135     NULL,                                  /* init main configuration */
0136 
0137     NULL,                                  /* create server configuration */
0138     NULL,                                  /* merge server configuration */
0139 
0140     ngx_http_memcached_create_loc_conf,    /* create location configuration */
0141     ngx_http_memcached_merge_loc_conf      /* merge location configuration */
0142 };
0143 
0144 
0145 ngx_module_t  ngx_http_memcached_module = {
0146     NGX_MODULE_V1,
0147     &ngx_http_memcached_module_ctx,        /* module context */
0148     ngx_http_memcached_commands,           /* module directives */
0149     NGX_HTTP_MODULE,                       /* module type */
0150     NULL,                                  /* init master */
0151     NULL,                                  /* init module */
0152     NULL,                                  /* init process */
0153     NULL,                                  /* init thread */
0154     NULL,                                  /* exit thread */
0155     NULL,                                  /* exit process */
0156     NULL,                                  /* exit master */
0157     NGX_MODULE_V1_PADDING
0158 };
0159 
0160 
0161 static ngx_str_t  ngx_http_memcached_key = ngx_string("memcached_key");
0162 
0163 
0164 #define NGX_HTTP_MEMCACHED_END   (sizeof(ngx_http_memcached_end) - 1)
0165 static u_char  ngx_http_memcached_end[] = CRLF "END" CRLF;
0166 
0167 
0168 static ngx_int_t
0169 ngx_http_memcached_handler(ngx_http_request_t *r)
0170 {
0171     ngx_int_t                       rc;
0172     ngx_http_upstream_t            *u;
0173     ngx_http_memcached_ctx_t       *ctx;
0174     ngx_http_memcached_loc_conf_t  *mlcf;
0175 
0176     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
0177         return NGX_HTTP_NOT_ALLOWED;
0178     }
0179 
0180     rc = ngx_http_discard_request_body(r);
0181 
0182     if (rc != NGX_OK) {
0183         return rc;
0184     }
0185 
0186     if (ngx_http_set_content_type(r) != NGX_OK) {
0187         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0188     }
0189 
0190     if (ngx_http_upstream_create(r) != NGX_OK) {
0191         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0192     }
0193 
0194     u = r->upstream;
0195 
0196     ngx_str_set(&u->schema, "memcached://");
0197     u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
0198 
0199     mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
0200 
0201     u->conf = &mlcf->upstream;
0202 
0203     u->create_request = ngx_http_memcached_create_request;
0204     u->reinit_request = ngx_http_memcached_reinit_request;
0205     u->process_header = ngx_http_memcached_process_header;
0206     u->abort_request = ngx_http_memcached_abort_request;
0207     u->finalize_request = ngx_http_memcached_finalize_request;
0208 
0209     ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
0210     if (ctx == NULL) {
0211         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0212     }
0213 
0214     ctx->request = r;
0215 
0216     ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
0217 
0218     u->input_filter_init = ngx_http_memcached_filter_init;
0219     u->input_filter = ngx_http_memcached_filter;
0220     u->input_filter_ctx = ctx;
0221 
0222     r->main->count++;
0223 
0224     ngx_http_upstream_init(r);
0225 
0226     return NGX_DONE;
0227 }
0228 
0229 
0230 static ngx_int_t
0231 ngx_http_memcached_create_request(ngx_http_request_t *r)
0232 {
0233     size_t                          len;
0234     uintptr_t                       escape;
0235     ngx_buf_t                      *b;
0236     ngx_chain_t                    *cl;
0237     ngx_http_memcached_ctx_t       *ctx;
0238     ngx_http_variable_value_t      *vv;
0239     ngx_http_memcached_loc_conf_t  *mlcf;
0240 
0241     mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
0242 
0243     vv = ngx_http_get_indexed_variable(r, mlcf->index);
0244 
0245     if (vv == NULL || vv->not_found || vv->len == 0) {
0246         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0247                       "the \"$memcached_key\" variable is not set");
0248         return NGX_ERROR;
0249     }
0250 
0251     escape = 2 * ngx_escape_uri(NULL, vv->data, vv->len, NGX_ESCAPE_MEMCACHED);
0252 
0253     len = sizeof("get ") - 1 + vv->len + escape + sizeof(CRLF) - 1;
0254 
0255     b = ngx_create_temp_buf(r->pool, len);
0256     if (b == NULL) {
0257         return NGX_ERROR;
0258     }
0259 
0260     cl = ngx_alloc_chain_link(r->pool);
0261     if (cl == NULL) {
0262         return NGX_ERROR;
0263     }
0264 
0265     cl->buf = b;
0266     cl->next = NULL;
0267 
0268     r->upstream->request_bufs = cl;
0269 
0270     *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' ';
0271 
0272     ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
0273 
0274     ctx->key.data = b->last;
0275 
0276     if (escape == 0) {
0277         b->last = ngx_copy(b->last, vv->data, vv->len);
0278 
0279     } else {
0280         b->last = (u_char *) ngx_escape_uri(b->last, vv->data, vv->len,
0281                                             NGX_ESCAPE_MEMCACHED);
0282     }
0283 
0284     ctx->key.len = b->last - ctx->key.data;
0285 
0286     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0287                    "http memcached request: \"%V\"", &ctx->key);
0288 
0289     *b->last++ = CR; *b->last++ = LF;
0290 
0291     return NGX_OK;
0292 }
0293 
0294 
0295 static ngx_int_t
0296 ngx_http_memcached_reinit_request(ngx_http_request_t *r)
0297 {
0298     return NGX_OK;
0299 }
0300 
0301 
0302 static ngx_int_t
0303 ngx_http_memcached_process_header(ngx_http_request_t *r)
0304 {
0305     u_char                         *p, *start;
0306     ngx_str_t                       line;
0307     ngx_uint_t                      flags;
0308     ngx_table_elt_t                *h;
0309     ngx_http_upstream_t            *u;
0310     ngx_http_memcached_ctx_t       *ctx;
0311     ngx_http_memcached_loc_conf_t  *mlcf;
0312 
0313     u = r->upstream;
0314 
0315     for (p = u->buffer.pos; p < u->buffer.last; p++) {
0316         if (*p == LF) {
0317             goto found;
0318         }
0319     }
0320 
0321     return NGX_AGAIN;
0322 
0323 found:
0324 
0325     line.data = u->buffer.pos;
0326     line.len = p - u->buffer.pos;
0327 
0328     if (line.len == 0 || *(p - 1) != CR) {
0329         goto no_valid;
0330     }
0331 
0332     *p = '\0';
0333     line.len--;
0334 
0335     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0336                    "memcached: \"%V\"", &line);
0337 
0338     p = u->buffer.pos;
0339 
0340     ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module);
0341     mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
0342 
0343     if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) {
0344 
0345         p += sizeof("VALUE ") - 1;
0346 
0347         if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) {
0348             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0349                           "memcached sent invalid key in response \"%V\" "
0350                           "for key \"%V\"",
0351                           &line, &ctx->key);
0352 
0353             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
0354         }
0355 
0356         p += ctx->key.len;
0357 
0358         if (*p++ != ' ') {
0359             goto no_valid;
0360         }
0361 
0362         /* flags */
0363 
0364         start = p;
0365 
0366         while (*p) {
0367             if (*p++ == ' ') {
0368                 if (mlcf->gzip_flag) {
0369                     goto flags;
0370                 } else {
0371                     goto length;
0372                 }
0373             }
0374         }
0375 
0376         goto no_valid;
0377 
0378     flags:
0379 
0380         flags = ngx_atoi(start, p - start - 1);
0381 
0382         if (flags == (ngx_uint_t) NGX_ERROR) {
0383             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0384                           "memcached sent invalid flags in response \"%V\" "
0385                           "for key \"%V\"",
0386                           &line, &ctx->key);
0387             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
0388         }
0389 
0390         if (flags & mlcf->gzip_flag) {
0391             h = ngx_list_push(&r->headers_out.headers);
0392             if (h == NULL) {
0393                 return NGX_ERROR;
0394             }
0395 
0396             h->hash = 1;
0397             ngx_str_set(&h->key, "Content-Encoding");
0398             ngx_str_set(&h->value, "gzip");
0399             r->headers_out.content_encoding = h;
0400         }
0401 
0402     length:
0403 
0404         start = p;
0405         p = line.data + line.len;
0406 
0407         u->headers_in.content_length_n = ngx_atoof(start, p - start);
0408         if (u->headers_in.content_length_n == NGX_ERROR) {
0409             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0410                           "memcached sent invalid length in response \"%V\" "
0411                           "for key \"%V\"",
0412                           &line, &ctx->key);
0413             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
0414         }
0415 
0416         u->headers_in.status_n = 200;
0417         u->state->status = 200;
0418         u->buffer.pos = p + sizeof(CRLF) - 1;
0419 
0420         return NGX_OK;
0421     }
0422 
0423     if (ngx_strcmp(p, "END\x0d") == 0) {
0424         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
0425                       "key: \"%V\" was not found by memcached", &ctx->key);
0426 
0427         u->headers_in.content_length_n = 0;
0428         u->headers_in.status_n = 404;
0429         u->state->status = 404;
0430         u->buffer.pos = p + sizeof("END" CRLF) - 1;
0431         u->keepalive = 1;
0432 
0433         return NGX_OK;
0434     }
0435 
0436 no_valid:
0437 
0438     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0439                   "memcached sent invalid response: \"%V\"", &line);
0440 
0441     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
0442 }
0443 
0444 
0445 static ngx_int_t
0446 ngx_http_memcached_filter_init(void *data)
0447 {
0448     ngx_http_memcached_ctx_t  *ctx = data;
0449 
0450     ngx_http_upstream_t  *u;
0451 
0452     u = ctx->request->upstream;
0453 
0454     if (u->headers_in.status_n != 404) {
0455         u->length = u->headers_in.content_length_n + NGX_HTTP_MEMCACHED_END;
0456         ctx->rest = NGX_HTTP_MEMCACHED_END;
0457 
0458     } else {
0459         u->length = 0;
0460     }
0461 
0462     return NGX_OK;
0463 }
0464 
0465 
0466 static ngx_int_t
0467 ngx_http_memcached_filter(void *data, ssize_t bytes)
0468 {
0469     ngx_http_memcached_ctx_t  *ctx = data;
0470 
0471     u_char               *last;
0472     ngx_buf_t            *b;
0473     ngx_chain_t          *cl, **ll;
0474     ngx_http_upstream_t  *u;
0475 
0476     u = ctx->request->upstream;
0477     b = &u->buffer;
0478 
0479     if (u->length == (ssize_t) ctx->rest) {
0480 
0481         if (ngx_strncmp(b->last,
0482                    ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
0483                    bytes)
0484             != 0)
0485         {
0486             ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
0487                           "memcached sent invalid trailer");
0488 
0489             u->length = 0;
0490             ctx->rest = 0;
0491 
0492             return NGX_OK;
0493         }
0494 
0495         u->length -= bytes;
0496         ctx->rest -= bytes;
0497 
0498         if (u->length == 0) {
0499             u->keepalive = 1;
0500         }
0501 
0502         return NGX_OK;
0503     }
0504 
0505     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
0506         ll = &cl->next;
0507     }
0508 
0509     cl = ngx_chain_get_free_buf(ctx->request->pool, &u->free_bufs);
0510     if (cl == NULL) {
0511         return NGX_ERROR;
0512     }
0513 
0514     cl->buf->flush = 1;
0515     cl->buf->memory = 1;
0516 
0517     *ll = cl;
0518 
0519     last = b->last;
0520     cl->buf->pos = last;
0521     b->last += bytes;
0522     cl->buf->last = b->last;
0523     cl->buf->tag = u->output.tag;
0524 
0525     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
0526                    "memcached filter bytes:%z size:%z length:%O rest:%z",
0527                    bytes, b->last - b->pos, u->length, ctx->rest);
0528 
0529     if (bytes <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) {
0530         u->length -= bytes;
0531         return NGX_OK;
0532     }
0533 
0534     last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END);
0535 
0536     if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
0537         ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
0538                       "memcached sent invalid trailer");
0539 
0540         b->last = last;
0541         cl->buf->last = last;
0542         u->length = 0;
0543         ctx->rest = 0;
0544 
0545         return NGX_OK;
0546     }
0547 
0548     ctx->rest -= b->last - last;
0549     b->last = last;
0550     cl->buf->last = last;
0551     u->length = ctx->rest;
0552 
0553     if (u->length == 0) {
0554         u->keepalive = 1;
0555     }
0556 
0557     return NGX_OK;
0558 }
0559 
0560 
0561 static void
0562 ngx_http_memcached_abort_request(ngx_http_request_t *r)
0563 {
0564     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0565                    "abort http memcached request");
0566     return;
0567 }
0568 
0569 
0570 static void
0571 ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
0572 {
0573     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0574                    "finalize http memcached request");
0575     return;
0576 }
0577 
0578 
0579 static void *
0580 ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
0581 {
0582     ngx_http_memcached_loc_conf_t  *conf;
0583 
0584     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
0585     if (conf == NULL) {
0586         return NULL;
0587     }
0588 
0589     /*
0590      * set by ngx_pcalloc():
0591      *
0592      *     conf->upstream.bufs.num = 0;
0593      *     conf->upstream.next_upstream = 0;
0594      *     conf->upstream.temp_path = NULL;
0595      *     conf->upstream.uri = { 0, NULL };
0596      *     conf->upstream.location = NULL;
0597      */
0598 
0599     conf->upstream.local = NGX_CONF_UNSET_PTR;
0600     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
0601     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
0602     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
0603     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
0604     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
0605 
0606     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
0607 
0608     /* the hardcoded values */
0609     conf->upstream.cyclic_temp_file = 0;
0610     conf->upstream.buffering = 0;
0611     conf->upstream.ignore_client_abort = 0;
0612     conf->upstream.send_lowat = 0;
0613     conf->upstream.bufs.num = 0;
0614     conf->upstream.busy_buffers_size = 0;
0615     conf->upstream.max_temp_file_size = 0;
0616     conf->upstream.temp_file_write_size = 0;
0617     conf->upstream.intercept_errors = 1;
0618     conf->upstream.intercept_404 = 1;
0619     conf->upstream.pass_request_headers = 0;
0620     conf->upstream.pass_request_body = 0;
0621     conf->upstream.force_ranges = 1;
0622 
0623     conf->index = NGX_CONF_UNSET;
0624     conf->gzip_flag = NGX_CONF_UNSET_UINT;
0625 
0626     return conf;
0627 }
0628 
0629 
0630 static char *
0631 ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
0632 {
0633     ngx_http_memcached_loc_conf_t *prev = parent;
0634     ngx_http_memcached_loc_conf_t *conf = child;
0635 
0636     ngx_conf_merge_ptr_value(conf->upstream.local,
0637                               prev->upstream.local, NULL);
0638 
0639     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
0640                               prev->upstream.next_upstream_tries, 0);
0641 
0642     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
0643                               prev->upstream.connect_timeout, 60000);
0644 
0645     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
0646                               prev->upstream.send_timeout, 60000);
0647 
0648     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
0649                               prev->upstream.read_timeout, 60000);
0650 
0651     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
0652                               prev->upstream.next_upstream_timeout, 0);
0653 
0654     ngx_conf_merge_size_value(conf->upstream.buffer_size,
0655                               prev->upstream.buffer_size,
0656                               (size_t) ngx_pagesize);
0657 
0658     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
0659                               prev->upstream.next_upstream,
0660                               (NGX_CONF_BITMASK_SET
0661                                |NGX_HTTP_UPSTREAM_FT_ERROR
0662                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
0663 
0664     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
0665         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
0666                                        |NGX_HTTP_UPSTREAM_FT_OFF;
0667     }
0668 
0669     if (conf->upstream.upstream == NULL) {
0670         conf->upstream.upstream = prev->upstream.upstream;
0671     }
0672 
0673     if (conf->index == NGX_CONF_UNSET) {
0674         conf->index = prev->index;
0675     }
0676 
0677     ngx_conf_merge_uint_value(conf->gzip_flag, prev->gzip_flag, 0);
0678 
0679     return NGX_CONF_OK;
0680 }
0681 
0682 
0683 static char *
0684 ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0685 {
0686     ngx_http_memcached_loc_conf_t *mlcf = conf;
0687 
0688     ngx_str_t                 *value;
0689     ngx_url_t                  u;
0690     ngx_http_core_loc_conf_t  *clcf;
0691 
0692     if (mlcf->upstream.upstream) {
0693         return "is duplicate";
0694     }
0695 
0696     value = cf->args->elts;
0697 
0698     ngx_memzero(&u, sizeof(ngx_url_t));
0699 
0700     u.url = value[1];
0701     u.no_resolve = 1;
0702 
0703     mlcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
0704     if (mlcf->upstream.upstream == NULL) {
0705         return NGX_CONF_ERROR;
0706     }
0707 
0708     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
0709 
0710     clcf->handler = ngx_http_memcached_handler;
0711 
0712     if (clcf->name.data[clcf->name.len - 1] == '/') {
0713         clcf->auto_redirect = 1;
0714     }
0715 
0716     mlcf->index = ngx_http_get_variable_index(cf, &ngx_http_memcached_key);
0717 
0718     if (mlcf->index == NGX_ERROR) {
0719         return NGX_CONF_ERROR;
0720     }
0721 
0722     return NGX_CONF_OK;
0723 }