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) Roman Arutyunyan
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_stream.h>
0011 
0012 
0013 typedef struct {
0014     uint32_t                              hash;
0015     ngx_str_t                            *server;
0016 } ngx_stream_upstream_chash_point_t;
0017 
0018 
0019 typedef struct {
0020     ngx_uint_t                            number;
0021     ngx_stream_upstream_chash_point_t     point[1];
0022 } ngx_stream_upstream_chash_points_t;
0023 
0024 
0025 typedef struct {
0026     ngx_stream_complex_value_t            key;
0027     ngx_stream_upstream_chash_points_t   *points;
0028 } ngx_stream_upstream_hash_srv_conf_t;
0029 
0030 
0031 typedef struct {
0032     /* the round robin data must be first */
0033     ngx_stream_upstream_rr_peer_data_t    rrp;
0034     ngx_stream_upstream_hash_srv_conf_t  *conf;
0035     ngx_str_t                             key;
0036     ngx_uint_t                            tries;
0037     ngx_uint_t                            rehash;
0038     uint32_t                              hash;
0039     ngx_event_get_peer_pt                 get_rr_peer;
0040 } ngx_stream_upstream_hash_peer_data_t;
0041 
0042 
0043 static ngx_int_t ngx_stream_upstream_init_hash(ngx_conf_t *cf,
0044     ngx_stream_upstream_srv_conf_t *us);
0045 static ngx_int_t ngx_stream_upstream_init_hash_peer(ngx_stream_session_t *s,
0046     ngx_stream_upstream_srv_conf_t *us);
0047 static ngx_int_t ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc,
0048     void *data);
0049 
0050 static ngx_int_t ngx_stream_upstream_init_chash(ngx_conf_t *cf,
0051     ngx_stream_upstream_srv_conf_t *us);
0052 static int ngx_libc_cdecl
0053     ngx_stream_upstream_chash_cmp_points(const void *one, const void *two);
0054 static ngx_uint_t ngx_stream_upstream_find_chash_point(
0055     ngx_stream_upstream_chash_points_t *points, uint32_t hash);
0056 static ngx_int_t ngx_stream_upstream_init_chash_peer(ngx_stream_session_t *s,
0057     ngx_stream_upstream_srv_conf_t *us);
0058 static ngx_int_t ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc,
0059     void *data);
0060 
0061 static void *ngx_stream_upstream_hash_create_conf(ngx_conf_t *cf);
0062 static char *ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd,
0063     void *conf);
0064 
0065 
0066 static ngx_command_t  ngx_stream_upstream_hash_commands[] = {
0067 
0068     { ngx_string("hash"),
0069       NGX_STREAM_UPS_CONF|NGX_CONF_TAKE12,
0070       ngx_stream_upstream_hash,
0071       NGX_STREAM_SRV_CONF_OFFSET,
0072       0,
0073       NULL },
0074 
0075       ngx_null_command
0076 };
0077 
0078 
0079 static ngx_stream_module_t  ngx_stream_upstream_hash_module_ctx = {
0080     NULL,                                  /* preconfiguration */
0081     NULL,                                  /* postconfiguration */
0082 
0083     NULL,                                  /* create main configuration */
0084     NULL,                                  /* init main configuration */
0085 
0086     ngx_stream_upstream_hash_create_conf,  /* create server configuration */
0087     NULL                                   /* merge server configuration */
0088 };
0089 
0090 
0091 ngx_module_t  ngx_stream_upstream_hash_module = {
0092     NGX_MODULE_V1,
0093     &ngx_stream_upstream_hash_module_ctx,  /* module context */
0094     ngx_stream_upstream_hash_commands,     /* module directives */
0095     NGX_STREAM_MODULE,                     /* module type */
0096     NULL,                                  /* init master */
0097     NULL,                                  /* init module */
0098     NULL,                                  /* init process */
0099     NULL,                                  /* init thread */
0100     NULL,                                  /* exit thread */
0101     NULL,                                  /* exit process */
0102     NULL,                                  /* exit master */
0103     NGX_MODULE_V1_PADDING
0104 };
0105 
0106 
0107 static ngx_int_t
0108 ngx_stream_upstream_init_hash(ngx_conf_t *cf,
0109     ngx_stream_upstream_srv_conf_t *us)
0110 {
0111     if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
0112         return NGX_ERROR;
0113     }
0114 
0115     us->peer.init = ngx_stream_upstream_init_hash_peer;
0116 
0117     return NGX_OK;
0118 }
0119 
0120 
0121 static ngx_int_t
0122 ngx_stream_upstream_init_hash_peer(ngx_stream_session_t *s,
0123     ngx_stream_upstream_srv_conf_t *us)
0124 {
0125     ngx_stream_upstream_hash_srv_conf_t   *hcf;
0126     ngx_stream_upstream_hash_peer_data_t  *hp;
0127 
0128     hp = ngx_palloc(s->connection->pool,
0129                     sizeof(ngx_stream_upstream_hash_peer_data_t));
0130     if (hp == NULL) {
0131         return NGX_ERROR;
0132     }
0133 
0134     s->upstream->peer.data = &hp->rrp;
0135 
0136     if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) {
0137         return NGX_ERROR;
0138     }
0139 
0140     s->upstream->peer.get = ngx_stream_upstream_get_hash_peer;
0141 
0142     hcf = ngx_stream_conf_upstream_srv_conf(us,
0143                                             ngx_stream_upstream_hash_module);
0144 
0145     if (ngx_stream_complex_value(s, &hcf->key, &hp->key) != NGX_OK) {
0146         return NGX_ERROR;
0147     }
0148 
0149     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
0150                    "upstream hash key:\"%V\"", &hp->key);
0151 
0152     hp->conf = hcf;
0153     hp->tries = 0;
0154     hp->rehash = 0;
0155     hp->hash = 0;
0156     hp->get_rr_peer = ngx_stream_upstream_get_round_robin_peer;
0157 
0158     return NGX_OK;
0159 }
0160 
0161 
0162 static ngx_int_t
0163 ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
0164 {
0165     ngx_stream_upstream_hash_peer_data_t *hp = data;
0166 
0167     time_t                          now;
0168     u_char                          buf[NGX_INT_T_LEN];
0169     size_t                          size;
0170     uint32_t                        hash;
0171     ngx_int_t                       w;
0172     uintptr_t                       m;
0173     ngx_uint_t                      n, p;
0174     ngx_stream_upstream_rr_peer_t  *peer;
0175 
0176     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0177                    "get hash peer, try: %ui", pc->tries);
0178 
0179     ngx_stream_upstream_rr_peers_rlock(hp->rrp.peers);
0180 
0181     if (hp->tries > 20 || hp->rrp.peers->single) {
0182         ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0183         return hp->get_rr_peer(pc, &hp->rrp);
0184     }
0185 
0186     now = ngx_time();
0187 
0188     pc->connection = NULL;
0189 
0190     for ( ;; ) {
0191 
0192         /*
0193          * Hash expression is compatible with Cache::Memcached:
0194          * ((crc32([REHASH] KEY) >> 16) & 0x7fff) + PREV_HASH
0195          * with REHASH omitted at the first iteration.
0196          */
0197 
0198         ngx_crc32_init(hash);
0199 
0200         if (hp->rehash > 0) {
0201             size = ngx_sprintf(buf, "%ui", hp->rehash) - buf;
0202             ngx_crc32_update(&hash, buf, size);
0203         }
0204 
0205         ngx_crc32_update(&hash, hp->key.data, hp->key.len);
0206         ngx_crc32_final(hash);
0207 
0208         hash = (hash >> 16) & 0x7fff;
0209 
0210         hp->hash += hash;
0211         hp->rehash++;
0212 
0213         w = hp->hash % hp->rrp.peers->total_weight;
0214         peer = hp->rrp.peers->peer;
0215         p = 0;
0216 
0217         while (w >= peer->weight) {
0218             w -= peer->weight;
0219             peer = peer->next;
0220             p++;
0221         }
0222 
0223         n = p / (8 * sizeof(uintptr_t));
0224         m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
0225 
0226         if (hp->rrp.tried[n] & m) {
0227             goto next;
0228         }
0229 
0230         ngx_stream_upstream_rr_peer_lock(hp->rrp.peers, peer);
0231 
0232         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0233                        "get hash peer, value:%uD, peer:%ui", hp->hash, p);
0234 
0235         if (peer->down) {
0236             ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer);
0237             goto next;
0238         }
0239 
0240         if (peer->max_fails
0241             && peer->fails >= peer->max_fails
0242             && now - peer->checked <= peer->fail_timeout)
0243         {
0244             ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer);
0245             goto next;
0246         }
0247 
0248         if (peer->max_conns && peer->conns >= peer->max_conns) {
0249             ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer);
0250             goto next;
0251         }
0252 
0253         break;
0254 
0255     next:
0256 
0257         if (++hp->tries > 20) {
0258             ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0259             return hp->get_rr_peer(pc, &hp->rrp);
0260         }
0261     }
0262 
0263     hp->rrp.current = peer;
0264 
0265     pc->sockaddr = peer->sockaddr;
0266     pc->socklen = peer->socklen;
0267     pc->name = &peer->name;
0268 
0269     peer->conns++;
0270 
0271     if (now - peer->checked > peer->fail_timeout) {
0272         peer->checked = now;
0273     }
0274 
0275     ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer);
0276     ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0277 
0278     hp->rrp.tried[n] |= m;
0279 
0280     return NGX_OK;
0281 }
0282 
0283 
0284 static ngx_int_t
0285 ngx_stream_upstream_init_chash(ngx_conf_t *cf,
0286     ngx_stream_upstream_srv_conf_t *us)
0287 {
0288     u_char                               *host, *port, c;
0289     size_t                                host_len, port_len, size;
0290     uint32_t                              hash, base_hash;
0291     ngx_str_t                            *server;
0292     ngx_uint_t                            npoints, i, j;
0293     ngx_stream_upstream_rr_peer_t        *peer;
0294     ngx_stream_upstream_rr_peers_t       *peers;
0295     ngx_stream_upstream_chash_points_t   *points;
0296     ngx_stream_upstream_hash_srv_conf_t  *hcf;
0297     union {
0298         uint32_t                          value;
0299         u_char                            byte[4];
0300     } prev_hash;
0301 
0302     if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
0303         return NGX_ERROR;
0304     }
0305 
0306     us->peer.init = ngx_stream_upstream_init_chash_peer;
0307 
0308     peers = us->peer.data;
0309     npoints = peers->total_weight * 160;
0310 
0311     size = sizeof(ngx_stream_upstream_chash_points_t)
0312            + sizeof(ngx_stream_upstream_chash_point_t) * (npoints - 1);
0313 
0314     points = ngx_palloc(cf->pool, size);
0315     if (points == NULL) {
0316         return NGX_ERROR;
0317     }
0318 
0319     points->number = 0;
0320 
0321     for (peer = peers->peer; peer; peer = peer->next) {
0322         server = &peer->server;
0323 
0324         /*
0325          * Hash expression is compatible with Cache::Memcached::Fast:
0326          * crc32(HOST \0 PORT PREV_HASH).
0327          */
0328 
0329         if (server->len >= 5
0330             && ngx_strncasecmp(server->data, (u_char *) "unix:", 5) == 0)
0331         {
0332             host = server->data + 5;
0333             host_len = server->len - 5;
0334             port = NULL;
0335             port_len = 0;
0336             goto done;
0337         }
0338 
0339         for (j = 0; j < server->len; j++) {
0340             c = server->data[server->len - j - 1];
0341 
0342             if (c == ':') {
0343                 host = server->data;
0344                 host_len = server->len - j - 1;
0345                 port = server->data + server->len - j;
0346                 port_len = j;
0347                 goto done;
0348             }
0349 
0350             if (c < '0' || c > '9') {
0351                 break;
0352             }
0353         }
0354 
0355         host = server->data;
0356         host_len = server->len;
0357         port = NULL;
0358         port_len = 0;
0359 
0360     done:
0361 
0362         ngx_crc32_init(base_hash);
0363         ngx_crc32_update(&base_hash, host, host_len);
0364         ngx_crc32_update(&base_hash, (u_char *) "", 1);
0365         ngx_crc32_update(&base_hash, port, port_len);
0366 
0367         prev_hash.value = 0;
0368         npoints = peer->weight * 160;
0369 
0370         for (j = 0; j < npoints; j++) {
0371             hash = base_hash;
0372 
0373             ngx_crc32_update(&hash, prev_hash.byte, 4);
0374             ngx_crc32_final(hash);
0375 
0376             points->point[points->number].hash = hash;
0377             points->point[points->number].server = server;
0378             points->number++;
0379 
0380 #if (NGX_HAVE_LITTLE_ENDIAN)
0381             prev_hash.value = hash;
0382 #else
0383             prev_hash.byte[0] = (u_char) (hash & 0xff);
0384             prev_hash.byte[1] = (u_char) ((hash >> 8) & 0xff);
0385             prev_hash.byte[2] = (u_char) ((hash >> 16) & 0xff);
0386             prev_hash.byte[3] = (u_char) ((hash >> 24) & 0xff);
0387 #endif
0388         }
0389     }
0390 
0391     ngx_qsort(points->point,
0392               points->number,
0393               sizeof(ngx_stream_upstream_chash_point_t),
0394               ngx_stream_upstream_chash_cmp_points);
0395 
0396     for (i = 0, j = 1; j < points->number; j++) {
0397         if (points->point[i].hash != points->point[j].hash) {
0398             points->point[++i] = points->point[j];
0399         }
0400     }
0401 
0402     points->number = i + 1;
0403 
0404     hcf = ngx_stream_conf_upstream_srv_conf(us,
0405                                             ngx_stream_upstream_hash_module);
0406     hcf->points = points;
0407 
0408     return NGX_OK;
0409 }
0410 
0411 
0412 static int ngx_libc_cdecl
0413 ngx_stream_upstream_chash_cmp_points(const void *one, const void *two)
0414 {
0415     ngx_stream_upstream_chash_point_t *first =
0416                                      (ngx_stream_upstream_chash_point_t *) one;
0417     ngx_stream_upstream_chash_point_t *second =
0418                                      (ngx_stream_upstream_chash_point_t *) two;
0419 
0420     if (first->hash < second->hash) {
0421         return -1;
0422 
0423     } else if (first->hash > second->hash) {
0424         return 1;
0425 
0426     } else {
0427         return 0;
0428     }
0429 }
0430 
0431 
0432 static ngx_uint_t
0433 ngx_stream_upstream_find_chash_point(ngx_stream_upstream_chash_points_t *points,
0434     uint32_t hash)
0435 {
0436     ngx_uint_t                          i, j, k;
0437     ngx_stream_upstream_chash_point_t  *point;
0438 
0439     /* find first point >= hash */
0440 
0441     point = &points->point[0];
0442 
0443     i = 0;
0444     j = points->number;
0445 
0446     while (i < j) {
0447         k = (i + j) / 2;
0448 
0449         if (hash > point[k].hash) {
0450             i = k + 1;
0451 
0452         } else if (hash < point[k].hash) {
0453             j = k;
0454 
0455         } else {
0456             return k;
0457         }
0458     }
0459 
0460     return i;
0461 }
0462 
0463 
0464 static ngx_int_t
0465 ngx_stream_upstream_init_chash_peer(ngx_stream_session_t *s,
0466     ngx_stream_upstream_srv_conf_t *us)
0467 {
0468     uint32_t                               hash;
0469     ngx_stream_upstream_hash_srv_conf_t   *hcf;
0470     ngx_stream_upstream_hash_peer_data_t  *hp;
0471 
0472     if (ngx_stream_upstream_init_hash_peer(s, us) != NGX_OK) {
0473         return NGX_ERROR;
0474     }
0475 
0476     s->upstream->peer.get = ngx_stream_upstream_get_chash_peer;
0477 
0478     hp = s->upstream->peer.data;
0479     hcf = ngx_stream_conf_upstream_srv_conf(us,
0480                                             ngx_stream_upstream_hash_module);
0481 
0482     hash = ngx_crc32_long(hp->key.data, hp->key.len);
0483 
0484     ngx_stream_upstream_rr_peers_rlock(hp->rrp.peers);
0485 
0486     hp->hash = ngx_stream_upstream_find_chash_point(hcf->points, hash);
0487 
0488     ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0489 
0490     return NGX_OK;
0491 }
0492 
0493 
0494 static ngx_int_t
0495 ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
0496 {
0497     ngx_stream_upstream_hash_peer_data_t *hp = data;
0498 
0499     time_t                                now;
0500     intptr_t                              m;
0501     ngx_str_t                            *server;
0502     ngx_int_t                             total;
0503     ngx_uint_t                            i, n, best_i;
0504     ngx_stream_upstream_rr_peer_t        *peer, *best;
0505     ngx_stream_upstream_chash_point_t    *point;
0506     ngx_stream_upstream_chash_points_t   *points;
0507     ngx_stream_upstream_hash_srv_conf_t  *hcf;
0508 
0509     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0510                    "get consistent hash peer, try: %ui", pc->tries);
0511 
0512     ngx_stream_upstream_rr_peers_wlock(hp->rrp.peers);
0513 
0514     if (hp->tries > 20 || hp->rrp.peers->single) {
0515         ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0516         return hp->get_rr_peer(pc, &hp->rrp);
0517     }
0518 
0519     pc->connection = NULL;
0520 
0521     now = ngx_time();
0522     hcf = hp->conf;
0523 
0524     points = hcf->points;
0525     point = &points->point[0];
0526 
0527     for ( ;; ) {
0528         server = point[hp->hash % points->number].server;
0529 
0530         ngx_log_debug2(NGX_LOG_DEBUG_STREAM, pc->log, 0,
0531                        "consistent hash peer:%uD, server:\"%V\"",
0532                        hp->hash, server);
0533 
0534         best = NULL;
0535         best_i = 0;
0536         total = 0;
0537 
0538         for (peer = hp->rrp.peers->peer, i = 0;
0539              peer;
0540              peer = peer->next, i++)
0541         {
0542             n = i / (8 * sizeof(uintptr_t));
0543             m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
0544 
0545             if (hp->rrp.tried[n] & m) {
0546                 continue;
0547             }
0548 
0549             if (peer->down) {
0550                 continue;
0551             }
0552 
0553             if (peer->max_fails
0554                 && peer->fails >= peer->max_fails
0555                 && now - peer->checked <= peer->fail_timeout)
0556             {
0557                 continue;
0558             }
0559 
0560             if (peer->max_conns && peer->conns >= peer->max_conns) {
0561                 continue;
0562             }
0563 
0564             if (peer->server.len != server->len
0565                 || ngx_strncmp(peer->server.data, server->data, server->len)
0566                    != 0)
0567             {
0568                 continue;
0569             }
0570 
0571             peer->current_weight += peer->effective_weight;
0572             total += peer->effective_weight;
0573 
0574             if (peer->effective_weight < peer->weight) {
0575                 peer->effective_weight++;
0576             }
0577 
0578             if (best == NULL || peer->current_weight > best->current_weight) {
0579                 best = peer;
0580                 best_i = i;
0581             }
0582         }
0583 
0584         if (best) {
0585             best->current_weight -= total;
0586             break;
0587         }
0588 
0589         hp->hash++;
0590         hp->tries++;
0591 
0592         if (hp->tries > 20) {
0593             ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0594             return hp->get_rr_peer(pc, &hp->rrp);
0595         }
0596     }
0597 
0598     hp->rrp.current = best;
0599 
0600     pc->sockaddr = best->sockaddr;
0601     pc->socklen = best->socklen;
0602     pc->name = &best->name;
0603 
0604     best->conns++;
0605 
0606     if (now - best->checked > best->fail_timeout) {
0607         best->checked = now;
0608     }
0609 
0610     ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers);
0611 
0612     n = best_i / (8 * sizeof(uintptr_t));
0613     m = (uintptr_t) 1 << best_i % (8 * sizeof(uintptr_t));
0614 
0615     hp->rrp.tried[n] |= m;
0616 
0617     return NGX_OK;
0618 }
0619 
0620 
0621 static void *
0622 ngx_stream_upstream_hash_create_conf(ngx_conf_t *cf)
0623 {
0624     ngx_stream_upstream_hash_srv_conf_t  *conf;
0625 
0626     conf = ngx_palloc(cf->pool, sizeof(ngx_stream_upstream_hash_srv_conf_t));
0627     if (conf == NULL) {
0628         return NULL;
0629     }
0630 
0631     conf->points = NULL;
0632 
0633     return conf;
0634 }
0635 
0636 
0637 static char *
0638 ngx_stream_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0639 {
0640     ngx_stream_upstream_hash_srv_conf_t  *hcf = conf;
0641 
0642     ngx_str_t                           *value;
0643     ngx_stream_upstream_srv_conf_t      *uscf;
0644     ngx_stream_compile_complex_value_t   ccv;
0645 
0646     value = cf->args->elts;
0647 
0648     ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
0649 
0650     ccv.cf = cf;
0651     ccv.value = &value[1];
0652     ccv.complex_value = &hcf->key;
0653 
0654     if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
0655         return NGX_CONF_ERROR;
0656     }
0657 
0658     uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module);
0659 
0660     if (uscf->peer.init_upstream) {
0661         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
0662                            "load balancing method redefined");
0663     }
0664 
0665     uscf->flags = NGX_STREAM_UPSTREAM_CREATE
0666                   |NGX_STREAM_UPSTREAM_WEIGHT
0667                   |NGX_STREAM_UPSTREAM_MAX_CONNS
0668                   |NGX_STREAM_UPSTREAM_MAX_FAILS
0669                   |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
0670                   |NGX_STREAM_UPSTREAM_DOWN;
0671 
0672     if (cf->args->nelts == 2) {
0673         uscf->peer.init_upstream = ngx_stream_upstream_init_hash;
0674 
0675     } else if (ngx_strcmp(value[2].data, "consistent") == 0) {
0676         uscf->peer.init_upstream = ngx_stream_upstream_init_chash;
0677 
0678     } else {
0679         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0680                            "invalid parameter \"%V\"", &value[2]);
0681         return NGX_CONF_ERROR;
0682     }
0683 
0684     return NGX_CONF_OK;
0685 }