| |
| |
| // TODO : generalize this into a generic list module, with weight |
| |
| |
| typedef struct { |
| ngx_uint_t weight; |
| ngx_str_t s; |
| ngx_conf_t *cf; |
| } ndk_upstream_list_parse_t; |
| |
| |
| |
| static ngx_int_t |
| ndk_upstream_list_parse_weight (ndk_upstream_list_parse_t *ulp) |
| { |
| size_t i; |
| ngx_str_t *s; |
| |
| s = &ulp->s; |
| |
| for (i=0; i<s->len; i++) { |
| |
| if (s->data[i] < '0' || s->data[i] > '9') |
| break; |
| } |
| |
| if (!i) { |
| ulp->weight = 1; |
| return NGX_OK; |
| } |
| |
| if (i == s->len) { |
| ngx_conf_log_error (NGX_LOG_EMERG, ulp->cf, 0, |
| "upstream list just consists of number \"%V\"", s); |
| |
| return NGX_ERROR; |
| } |
| |
| if (s->data[i] != ':') { |
| ngx_conf_log_error (NGX_LOG_EMERG, ulp->cf, 0, |
| "upstream list not correct format \"%V\"", s); |
| |
| return NGX_ERROR; |
| } |
| |
| |
| ulp->weight = ngx_atoi (s->data, i); |
| |
| s->data += (i + 1); |
| s->len -= (i + 1); |
| |
| return NGX_OK; |
| } |
| |
| |
| |
| static char * |
| ndk_upstream_list (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
| { |
| // TODO : change this for getting upstream pointer if available |
| |
| ngx_uint_t buckets, count, i, j; |
| ngx_str_t *value, **bucket, *us; |
| ngx_array_t *ula; |
| ndk_upstream_list_t *ul, *ule; |
| ndk_upstream_list_parse_t ulp; |
| |
| ndk_http_main_conf_t *mcf; |
| |
| mcf = ngx_http_conf_get_module_main_conf (cf, ndk_http_module); |
| |
| ula = mcf->upstreams; |
| |
| // create array of upstream lists it doesn't already exist |
| |
| if (ula == NULL) { |
| |
| ula = ngx_array_create (cf->pool, 4, sizeof (ndk_upstream_list_t)); |
| if (ula == NULL) |
| return NGX_CONF_ERROR; |
| |
| mcf->upstreams = ula; |
| } |
| |
| |
| // check to see if the list already exists |
| |
| value = cf->args->elts; |
| value++; |
| |
| ul = ula->elts; |
| ule = ul + ula->nelts; |
| |
| for ( ; ul<ule; ul++) { |
| |
| if (ul->name.len == value->len && |
| ngx_strncasecmp (ul->name.data, value->data, value->len) == 0) { |
| |
| ngx_conf_log_error (NGX_LOG_EMERG, cf, 0, |
| "duplicate upstream list name \"%V\"", value); |
| |
| return NGX_CONF_ERROR; |
| } |
| } |
| |
| |
| // create a new list |
| |
| ul = ngx_array_push (ula); |
| if (ul == NULL) |
| return NGX_CONF_ERROR; |
| |
| ul->name = *value; |
| |
| |
| |
| // copy all the upstream names |
| |
| count = cf->args->nelts - 2; |
| |
| us = ngx_palloc (cf->pool, count * sizeof (ngx_str_t)); |
| if (us == NULL) |
| return NGX_CONF_ERROR; |
| |
| ngx_memcpy (us, value + 1, count * sizeof (ngx_str_t)); |
| |
| |
| // calculate the total number of buckets |
| |
| buckets = 0; |
| |
| ulp.cf = cf; |
| |
| for (i=0; i<count; i++, us++) { |
| |
| ulp.s = *us; |
| |
| if (ndk_upstream_list_parse_weight (&ulp) != NGX_OK) |
| return NGX_CONF_ERROR; |
| |
| buckets += ulp.weight; |
| } |
| |
| |
| // allocate space for all buckets |
| |
| bucket = ngx_palloc (cf->pool, buckets * sizeof (ngx_str_t **)); |
| if (bucket == NULL) |
| return NGX_CONF_ERROR; |
| |
| ul->elts = bucket; |
| ul->nelts = buckets; |
| |
| |
| // set values for each bucket |
| |
| us -= count; |
| |
| for (i=0; i<count; i++, us++) { |
| |
| ulp.s = *us; |
| |
| if (ndk_upstream_list_parse_weight (&ulp) != NGX_OK) |
| return NGX_CONF_ERROR; |
| |
| us->data = ulp.s.data; |
| us->len = ulp.s.len; |
| |
| // TODO : check format of upstream |
| // TODO : add automatic adding of http:// in upstreams? |
| |
| for (j=0; j<ulp.weight; j++, bucket++) { |
| |
| *bucket = us; |
| } |
| } |
| |
| return NGX_CONF_OK; |
| } |
| |
| |
| ndk_upstream_list_t * |
| ndk_get_upstream_list (ndk_http_main_conf_t *mcf, u_char *data, size_t len) |
| { |
| ndk_upstream_list_t *ul, *ule; |
| ngx_array_t *ua = mcf->upstreams; |
| |
| if (ua == NULL) { |
| return NULL; |
| } |
| |
| ul = ua->elts; |
| ule = ul + ua->nelts; |
| |
| for (; ul < ule; ul++) { |
| if (ul->name.len == len && ngx_strncasecmp(ul->name.data, data, len) == 0) |
| { |
| return ul; |
| } |
| } |
| |
| return NULL; |
| } |
| |