Annotation of embedaddon/nginx/src/http/modules/ngx_http_headers_filter_module.c, revision 1.1.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 ngx_http_header_val_s  ngx_http_header_val_t;
                     14: 
                     15: typedef ngx_int_t (*ngx_http_set_header_pt)(ngx_http_request_t *r,
                     16:     ngx_http_header_val_t *hv, ngx_str_t *value);
                     17: 
                     18: 
                     19: typedef struct {
                     20:     ngx_str_t                  name;
                     21:     ngx_uint_t                 offset;
                     22:     ngx_http_set_header_pt     handler;
                     23: } ngx_http_set_header_t;
                     24: 
                     25: 
                     26: struct ngx_http_header_val_s {
                     27:     ngx_http_complex_value_t   value;
                     28:     ngx_str_t                  key;
                     29:     ngx_http_set_header_pt     handler;
                     30:     ngx_uint_t                 offset;
                     31: };
                     32: 
                     33: 
                     34: typedef enum {
                     35:     NGX_HTTP_EXPIRES_OFF,
                     36:     NGX_HTTP_EXPIRES_EPOCH,
                     37:     NGX_HTTP_EXPIRES_MAX,
                     38:     NGX_HTTP_EXPIRES_ACCESS,
                     39:     NGX_HTTP_EXPIRES_MODIFIED,
                     40:     NGX_HTTP_EXPIRES_DAILY,
                     41:     NGX_HTTP_EXPIRES_UNSET
                     42: } ngx_http_expires_t;
                     43: 
                     44: 
                     45: typedef struct {
                     46:     ngx_http_expires_t       expires;
                     47:     time_t                   expires_time;
                     48:     ngx_array_t             *headers;
                     49: } ngx_http_headers_conf_t;
                     50: 
                     51: 
                     52: static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r,
                     53:     ngx_http_headers_conf_t *conf);
                     54: static ngx_int_t ngx_http_add_cache_control(ngx_http_request_t *r,
                     55:     ngx_http_header_val_t *hv, ngx_str_t *value);
                     56: static ngx_int_t ngx_http_add_header(ngx_http_request_t *r,
                     57:     ngx_http_header_val_t *hv, ngx_str_t *value);
                     58: static ngx_int_t ngx_http_set_last_modified(ngx_http_request_t *r,
                     59:     ngx_http_header_val_t *hv, ngx_str_t *value);
                     60: static ngx_int_t ngx_http_set_response_header(ngx_http_request_t *r,
                     61:     ngx_http_header_val_t *hv, ngx_str_t *value);
                     62: 
                     63: static void *ngx_http_headers_create_conf(ngx_conf_t *cf);
                     64: static char *ngx_http_headers_merge_conf(ngx_conf_t *cf,
                     65:     void *parent, void *child);
                     66: static ngx_int_t ngx_http_headers_filter_init(ngx_conf_t *cf);
                     67: static char *ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd,
                     68:     void *conf);
                     69: static char *ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd,
                     70:     void *conf);
                     71: 
                     72: 
                     73: static ngx_http_set_header_t  ngx_http_set_headers[] = {
                     74: 
                     75:     { ngx_string("Cache-Control"), 0, ngx_http_add_cache_control },
                     76: 
                     77:     { ngx_string("Last-Modified"),
                     78:                  offsetof(ngx_http_headers_out_t, last_modified),
                     79:                  ngx_http_set_last_modified },
                     80: 
                     81:     { ngx_string("ETag"),
                     82:                  offsetof(ngx_http_headers_out_t, etag),
                     83:                  ngx_http_set_response_header },
                     84: 
                     85:     { ngx_null_string, 0, NULL }
                     86: };
                     87: 
                     88: 
                     89: static ngx_command_t  ngx_http_headers_filter_commands[] = {
                     90: 
                     91:     { ngx_string("expires"),
                     92:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                     93:                         |NGX_CONF_TAKE12,
                     94:       ngx_http_headers_expires,
                     95:       NGX_HTTP_LOC_CONF_OFFSET,
                     96:       0,
                     97:       NULL},
                     98: 
                     99:     { ngx_string("add_header"),
                    100:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                    101:                         |NGX_CONF_TAKE2,
                    102:       ngx_http_headers_add,
                    103:       NGX_HTTP_LOC_CONF_OFFSET,
                    104:       0,
                    105:       NULL},
                    106: 
                    107:       ngx_null_command
                    108: };
                    109: 
                    110: 
                    111: static ngx_http_module_t  ngx_http_headers_filter_module_ctx = {
                    112:     NULL,                                  /* preconfiguration */
                    113:     ngx_http_headers_filter_init,          /* postconfiguration */
                    114: 
                    115:     NULL,                                  /* create main configuration */
                    116:     NULL,                                  /* init main configuration */
                    117: 
                    118:     NULL,                                  /* create server configuration */
                    119:     NULL,                                  /* merge server configuration */
                    120: 
                    121:     ngx_http_headers_create_conf,          /* create location configuration */
                    122:     ngx_http_headers_merge_conf            /* merge location configuration */
                    123: };
                    124: 
                    125: 
                    126: ngx_module_t  ngx_http_headers_filter_module = {
                    127:     NGX_MODULE_V1,
                    128:     &ngx_http_headers_filter_module_ctx,   /* module context */
                    129:     ngx_http_headers_filter_commands,      /* module directives */
                    130:     NGX_HTTP_MODULE,                       /* module type */
                    131:     NULL,                                  /* init master */
                    132:     NULL,                                  /* init module */
                    133:     NULL,                                  /* init process */
                    134:     NULL,                                  /* init thread */
                    135:     NULL,                                  /* exit thread */
                    136:     NULL,                                  /* exit process */
                    137:     NULL,                                  /* exit master */
                    138:     NGX_MODULE_V1_PADDING
                    139: };
                    140: 
                    141: 
                    142: static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
                    143: 
                    144: 
                    145: static ngx_int_t
                    146: ngx_http_headers_filter(ngx_http_request_t *r)
                    147: {
                    148:     ngx_str_t                 value;
                    149:     ngx_uint_t                i;
                    150:     ngx_http_header_val_t    *h;
                    151:     ngx_http_headers_conf_t  *conf;
                    152: 
                    153:     conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);
                    154: 
                    155:     if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL)
                    156:         || r != r->main
                    157:         || (r->headers_out.status != NGX_HTTP_OK
                    158:             && r->headers_out.status != NGX_HTTP_CREATED
                    159:             && r->headers_out.status != NGX_HTTP_NO_CONTENT
                    160:             && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
                    161:             && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY
                    162:             && r->headers_out.status != NGX_HTTP_MOVED_TEMPORARILY
                    163:             && r->headers_out.status != NGX_HTTP_SEE_OTHER
                    164:             && r->headers_out.status != NGX_HTTP_NOT_MODIFIED
                    165:             && r->headers_out.status != NGX_HTTP_TEMPORARY_REDIRECT))
                    166:     {
                    167:         return ngx_http_next_header_filter(r);
                    168:     }
                    169: 
                    170:     if (conf->expires != NGX_HTTP_EXPIRES_OFF) {
                    171:         if (ngx_http_set_expires(r, conf) != NGX_OK) {
                    172:             return NGX_ERROR;
                    173:         }
                    174:     }
                    175: 
                    176:     if (conf->headers) {
                    177:         h = conf->headers->elts;
                    178:         for (i = 0; i < conf->headers->nelts; i++) {
                    179: 
                    180:             if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
                    181:                 return NGX_ERROR;
                    182:             }
                    183: 
                    184:             if (h[i].handler(r, &h[i], &value) != NGX_OK) {
                    185:                 return NGX_ERROR;
                    186:             }
                    187:         }
                    188:     }
                    189: 
                    190:     return ngx_http_next_header_filter(r);
                    191: }
                    192: 
                    193: 
                    194: static ngx_int_t
                    195: ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
                    196: {
                    197:     size_t            len;
                    198:     time_t            now, expires_time, max_age;
                    199:     ngx_uint_t        i;
                    200:     ngx_table_elt_t  *expires, *cc, **ccp;
                    201: 
                    202:     expires = r->headers_out.expires;
                    203: 
                    204:     if (expires == NULL) {
                    205: 
                    206:         expires = ngx_list_push(&r->headers_out.headers);
                    207:         if (expires == NULL) {
                    208:             return NGX_ERROR;
                    209:         }
                    210: 
                    211:         r->headers_out.expires = expires;
                    212: 
                    213:         expires->hash = 1;
                    214:         ngx_str_set(&expires->key, "Expires");
                    215:     }
                    216: 
                    217:     len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
                    218:     expires->value.len = len - 1;
                    219: 
                    220:     ccp = r->headers_out.cache_control.elts;
                    221: 
                    222:     if (ccp == NULL) {
                    223: 
                    224:         if (ngx_array_init(&r->headers_out.cache_control, r->pool,
                    225:                            1, sizeof(ngx_table_elt_t *))
                    226:             != NGX_OK)
                    227:         {
                    228:             return NGX_ERROR;
                    229:         }
                    230: 
                    231:         ccp = ngx_array_push(&r->headers_out.cache_control);
                    232:         if (ccp == NULL) {
                    233:             return NGX_ERROR;
                    234:         }
                    235: 
                    236:         cc = ngx_list_push(&r->headers_out.headers);
                    237:         if (cc == NULL) {
                    238:             return NGX_ERROR;
                    239:         }
                    240: 
                    241:         cc->hash = 1;
                    242:         ngx_str_set(&cc->key, "Cache-Control");
                    243:         *ccp = cc;
                    244: 
                    245:     } else {
                    246:         for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
                    247:             ccp[i]->hash = 0;
                    248:         }
                    249: 
                    250:         cc = ccp[0];
                    251:     }
                    252: 
                    253:     if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
                    254:         expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
                    255:         ngx_str_set(&cc->value, "no-cache");
                    256:         return NGX_OK;
                    257:     }
                    258: 
                    259:     if (conf->expires == NGX_HTTP_EXPIRES_MAX) {
                    260:         expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT";
                    261:         /* 10 years */
                    262:         ngx_str_set(&cc->value, "max-age=315360000");
                    263:         return NGX_OK;
                    264:     }
                    265: 
                    266:     expires->value.data = ngx_pnalloc(r->pool, len);
                    267:     if (expires->value.data == NULL) {
                    268:         return NGX_ERROR;
                    269:     }
                    270: 
                    271:     if (conf->expires_time == 0 && conf->expires != NGX_HTTP_EXPIRES_DAILY) {
                    272:         ngx_memcpy(expires->value.data, ngx_cached_http_time.data,
                    273:                    ngx_cached_http_time.len + 1);
                    274:         ngx_str_set(&cc->value, "max-age=0");
                    275:         return NGX_OK;
                    276:     }
                    277: 
                    278:     now = ngx_time();
                    279: 
                    280:     if (conf->expires == NGX_HTTP_EXPIRES_DAILY) {
                    281:         expires_time = ngx_next_time(conf->expires_time);
                    282:         max_age = expires_time - now;
                    283: 
                    284:     } else if (conf->expires == NGX_HTTP_EXPIRES_ACCESS
                    285:                || r->headers_out.last_modified_time == -1)
                    286:     {
                    287:         expires_time = now + conf->expires_time;
                    288:         max_age = conf->expires_time;
                    289: 
                    290:     } else {
                    291:         expires_time = r->headers_out.last_modified_time + conf->expires_time;
                    292:         max_age = expires_time - now;
                    293:     }
                    294: 
                    295:     ngx_http_time(expires->value.data, expires_time);
                    296: 
                    297:     if (conf->expires_time < 0 || max_age < 0) {
                    298:         ngx_str_set(&cc->value, "no-cache");
                    299:         return NGX_OK;
                    300:     }
                    301: 
                    302:     cc->value.data = ngx_pnalloc(r->pool,
                    303:                                  sizeof("max-age=") + NGX_TIME_T_LEN + 1);
                    304:     if (cc->value.data == NULL) {
                    305:         return NGX_ERROR;
                    306:     }
                    307: 
                    308:     cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", max_age)
                    309:                     - cc->value.data;
                    310: 
                    311:     return NGX_OK;
                    312: }
                    313: 
                    314: 
                    315: static ngx_int_t
                    316: ngx_http_add_header(ngx_http_request_t *r, ngx_http_header_val_t *hv,
                    317:     ngx_str_t *value)
                    318: {
                    319:     ngx_table_elt_t  *h;
                    320: 
                    321:     if (value->len) {
                    322:         h = ngx_list_push(&r->headers_out.headers);
                    323:         if (h == NULL) {
                    324:             return NGX_ERROR;
                    325:         }
                    326: 
                    327:         h->hash = 1;
                    328:         h->key = hv->key;
                    329:         h->value = *value;
                    330:     }
                    331: 
                    332:     return NGX_OK;
                    333: }
                    334: 
                    335: 
                    336: static ngx_int_t
                    337: ngx_http_add_cache_control(ngx_http_request_t *r, ngx_http_header_val_t *hv,
                    338:     ngx_str_t *value)
                    339: {
                    340:     ngx_table_elt_t  *cc, **ccp;
                    341: 
                    342:     ccp = r->headers_out.cache_control.elts;
                    343: 
                    344:     if (ccp == NULL) {
                    345: 
                    346:         if (ngx_array_init(&r->headers_out.cache_control, r->pool,
                    347:                            1, sizeof(ngx_table_elt_t *))
                    348:             != NGX_OK)
                    349:         {
                    350:             return NGX_ERROR;
                    351:         }
                    352:     }
                    353: 
                    354:     ccp = ngx_array_push(&r->headers_out.cache_control);
                    355:     if (ccp == NULL) {
                    356:         return NGX_ERROR;
                    357:     }
                    358: 
                    359:     cc = ngx_list_push(&r->headers_out.headers);
                    360:     if (cc == NULL) {
                    361:         return NGX_ERROR;
                    362:     }
                    363: 
                    364:     cc->hash = 1;
                    365:     ngx_str_set(&cc->key, "Cache-Control");
                    366:     cc->value = *value;
                    367: 
                    368:     *ccp = cc;
                    369: 
                    370:     return NGX_OK;
                    371: }
                    372: 
                    373: 
                    374: static ngx_int_t
                    375: ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
                    376:     ngx_str_t *value)
                    377: {
                    378:     if (ngx_http_set_response_header(r, hv, value) != NGX_OK) {
                    379:         return NGX_ERROR;
                    380:     }
                    381: 
                    382:     r->headers_out.last_modified_time =
                    383:         (value->len) ? ngx_http_parse_time(value->data, value->len) : -1;
                    384: 
                    385:     return NGX_OK;
                    386: }
                    387: 
                    388: 
                    389: static ngx_int_t
                    390: ngx_http_set_response_header(ngx_http_request_t *r, ngx_http_header_val_t *hv,
                    391:     ngx_str_t *value)
                    392: {
                    393:     ngx_table_elt_t  *h, **old;
                    394: 
                    395:     old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
                    396: 
                    397:     if (value->len == 0) {
                    398:         if (*old) {
                    399:             (*old)->hash = 0;
                    400:             *old = NULL;
                    401:         }
                    402: 
                    403:         return NGX_OK;
                    404:     }
                    405: 
                    406:     if (*old) {
                    407:         h = *old;
                    408: 
                    409:     } else {
                    410:         h = ngx_list_push(&r->headers_out.headers);
                    411:         if (h == NULL) {
                    412:             return NGX_ERROR;
                    413:         }
                    414: 
                    415:         *old = h;
                    416:     }
                    417: 
                    418:     h->hash = 1;
                    419:     h->key = hv->key;
                    420:     h->value = *value;
                    421: 
                    422:     return NGX_OK;
                    423: }
                    424: 
                    425: 
                    426: static void *
                    427: ngx_http_headers_create_conf(ngx_conf_t *cf)
                    428: {
                    429:     ngx_http_headers_conf_t  *conf;
                    430: 
                    431:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_conf_t));
                    432:     if (conf == NULL) {
                    433:         return NULL;
                    434:     }
                    435: 
                    436:     /*
                    437:      * set by ngx_pcalloc():
                    438:      *
                    439:      *     conf->headers = NULL;
                    440:      *     conf->expires_time = 0;
                    441:      */
                    442: 
                    443:     conf->expires = NGX_HTTP_EXPIRES_UNSET;
                    444: 
                    445:     return conf;
                    446: }
                    447: 
                    448: 
                    449: static char *
                    450: ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child)
                    451: {
                    452:     ngx_http_headers_conf_t *prev = parent;
                    453:     ngx_http_headers_conf_t *conf = child;
                    454: 
                    455:     if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
                    456:         conf->expires = prev->expires;
                    457:         conf->expires_time = prev->expires_time;
                    458: 
                    459:         if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
                    460:             conf->expires = NGX_HTTP_EXPIRES_OFF;
                    461:         }
                    462:     }
                    463: 
                    464:     if (conf->headers == NULL) {
                    465:         conf->headers = prev->headers;
                    466:     }
                    467: 
                    468:     return NGX_CONF_OK;
                    469: }
                    470: 
                    471: 
                    472: static ngx_int_t
                    473: ngx_http_headers_filter_init(ngx_conf_t *cf)
                    474: {
                    475:     ngx_http_next_header_filter = ngx_http_top_header_filter;
                    476:     ngx_http_top_header_filter = ngx_http_headers_filter;
                    477: 
                    478:     return NGX_OK;
                    479: }
                    480: 
                    481: 
                    482: static char *
                    483: ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    484: {
                    485:     ngx_http_headers_conf_t *hcf = conf;
                    486: 
                    487:     ngx_uint_t   minus, n;
                    488:     ngx_str_t   *value;
                    489: 
                    490:     if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) {
                    491:         return "is duplicate";
                    492:     }
                    493: 
                    494:     value = cf->args->elts;
                    495: 
                    496:     if (cf->args->nelts == 2) {
                    497: 
                    498:         if (ngx_strcmp(value[1].data, "epoch") == 0) {
                    499:             hcf->expires = NGX_HTTP_EXPIRES_EPOCH;
                    500:             return NGX_CONF_OK;
                    501:         }
                    502: 
                    503:         if (ngx_strcmp(value[1].data, "max") == 0) {
                    504:             hcf->expires = NGX_HTTP_EXPIRES_MAX;
                    505:             return NGX_CONF_OK;
                    506:         }
                    507: 
                    508:         if (ngx_strcmp(value[1].data, "off") == 0) {
                    509:             hcf->expires = NGX_HTTP_EXPIRES_OFF;
                    510:             return NGX_CONF_OK;
                    511:         }
                    512: 
                    513:         hcf->expires = NGX_HTTP_EXPIRES_ACCESS;
                    514: 
                    515:         n = 1;
                    516: 
                    517:     } else { /* cf->args->nelts == 3 */
                    518: 
                    519:         if (ngx_strcmp(value[1].data, "modified") != 0) {
                    520:             return "invalid value";
                    521:         }
                    522: 
                    523:         hcf->expires = NGX_HTTP_EXPIRES_MODIFIED;
                    524: 
                    525:         n = 2;
                    526:     }
                    527: 
                    528:     if (value[n].data[0] == '@') {
                    529:         value[n].data++;
                    530:         value[n].len--;
                    531:         minus = 0;
                    532: 
                    533:         if (hcf->expires == NGX_HTTP_EXPIRES_MODIFIED) {
                    534:             return "daily time cannot be used with \"modified\" parameter";
                    535:         }
                    536: 
                    537:         hcf->expires = NGX_HTTP_EXPIRES_DAILY;
                    538: 
                    539:     } else if (value[n].data[0] == '+') {
                    540:         value[n].data++;
                    541:         value[n].len--;
                    542:         minus = 0;
                    543: 
                    544:     } else if (value[n].data[0] == '-') {
                    545:         value[n].data++;
                    546:         value[n].len--;
                    547:         minus = 1;
                    548: 
                    549:     } else {
                    550:         minus = 0;
                    551:     }
                    552: 
                    553:     hcf->expires_time = ngx_parse_time(&value[n], 1);
                    554: 
                    555:     if (hcf->expires_time == (time_t) NGX_ERROR) {
                    556:         return "invalid value";
                    557:     }
                    558: 
                    559:     if (hcf->expires == NGX_HTTP_EXPIRES_DAILY
                    560:         && hcf->expires_time > 24 * 60 * 60)
                    561:     {
                    562:         return "daily time value must be less than 24 hours";
                    563:     }
                    564: 
                    565:     if (minus) {
                    566:         hcf->expires_time = - hcf->expires_time;
                    567:     }
                    568: 
                    569:     return NGX_CONF_OK;
                    570: }
                    571: 
                    572: 
                    573: static char *
                    574: ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    575: {
                    576:     ngx_http_headers_conf_t *hcf = conf;
                    577: 
                    578:     ngx_str_t                         *value;
                    579:     ngx_uint_t                         i;
                    580:     ngx_http_header_val_t             *hv;
                    581:     ngx_http_set_header_t             *set;
                    582:     ngx_http_compile_complex_value_t   ccv;
                    583: 
                    584:     value = cf->args->elts;
                    585: 
                    586:     if (hcf->headers == NULL) {
                    587:         hcf->headers = ngx_array_create(cf->pool, 1,
                    588:                                         sizeof(ngx_http_header_val_t));
                    589:         if (hcf->headers == NULL) {
                    590:             return NGX_CONF_ERROR;
                    591:         }
                    592:     }
                    593: 
                    594:     hv = ngx_array_push(hcf->headers);
                    595:     if (hv == NULL) {
                    596:         return NGX_CONF_ERROR;
                    597:     }
                    598: 
                    599:     hv->key = value[1];
                    600:     hv->handler = ngx_http_add_header;
                    601:     hv->offset = 0;
                    602: 
                    603:     set = ngx_http_set_headers;
                    604:     for (i = 0; set[i].name.len; i++) {
                    605:         if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) {
                    606:             continue;
                    607:         }
                    608: 
                    609:         hv->offset = set[i].offset;
                    610:         hv->handler = set[i].handler;
                    611: 
                    612:         break;
                    613:     }
                    614: 
                    615:     if (value[2].len == 0) {
                    616:         ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t));
                    617:         return NGX_CONF_OK;
                    618:     }
                    619: 
                    620:     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
                    621: 
                    622:     ccv.cf = cf;
                    623:     ccv.value = &value[2];
                    624:     ccv.complex_value = &hv->value;
                    625: 
                    626:     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
                    627:         return NGX_CONF_ERROR;
                    628:     }
                    629: 
                    630:     return NGX_CONF_OK;
                    631: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>