Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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