static ngx_int_t
ngx_http_eval_parse_param(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, ngx_str_t *param) {
    u_char                    *p, *src, *dst;

    ngx_str_t                  name;
    ngx_str_t                  value;

    p = (u_char *) ngx_strchr(param->data, '=');

    if(p == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "eval: invalid param \"%V\"", param);
        return NGX_ERROR;
    }

    name.data = param->data;
    name.len = p - param->data;

    value.data = p + 1;
    value.len = param->len - (p - param->data) - 1;

    src = dst = value.data;

    ngx_unescape_uri_patched(&dst, &src, value.len, NGX_UNESCAPE_URI);

    value.len = dst - value.data;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "eval param: \"%V\"=\"%V\"", &name, &value);

    return ngx_http_eval_set_variable_value(r, ctx, &name, &value);
}
Exemple #2
0
static ngx_int_t
ngx_http_push_stream_channels_statistics_handler(ngx_http_request_t *r)
{
    char                               *pos = NULL;
    ngx_str_t                          *id = NULL;
    ngx_http_push_stream_channel_t     *channel = NULL;
    ngx_http_push_stream_loc_conf_t    *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module);

    r->keepalive = cf->keepalive;
    ngx_http_push_stream_set_expires(r, NGX_HTTP_PUSH_STREAM_EXPIRES_EPOCH, 0);

    // only accept GET method
    if (!(r->method & NGX_HTTP_GET)) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET);
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL);
    }

    ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_TAG, &NGX_HTTP_PUSH_STREAM_TAG);
    ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_COMMIT, &NGX_HTTP_PUSH_STREAM_COMMIT);

    // get and check channel id value
    id = ngx_http_push_stream_get_channel_id(r, cf);
    if ((id == NULL) || (id == NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID)) {
        if (id == NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID) {
            return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE);
        }
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    // if not specify a channel id, get info about all channels in a resumed way
    if (id == NGX_HTTP_PUSH_STREAM_UNSET_CHANNEL_ID) {
        return ngx_http_push_stream_send_response_all_channels_info_summarized(r);
    }

    if ((pos = ngx_strchr(id->data, '*')) != NULL) {
        ngx_str_t *aux = NULL;
        if (pos != (char *) id->data) {
            *pos = '\0';
            id->len  = ngx_strlen(id->data);
            aux = id;
        }
        return ngx_http_push_stream_send_response_all_channels_info_detailed(r, aux);
    }

    // if specify a channel id equals to ALL, get info about all channels in a detailed way
    if (ngx_memn2cmp(id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) {
        return ngx_http_push_stream_send_response_all_channels_info_detailed(r, NULL);
    }

    // if specify a channel id != ALL, get info about specified channel if it exists
    // search for a existing channel with this id
    channel = ngx_http_push_stream_find_channel(id, r->connection->log);

    if (channel == NULL) {
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_FOUND, NULL);
    }

    return ngx_http_push_stream_send_response_channel_info(r, channel);
}
static ngx_int_t
ngx_http_push_stream_channels_statistics_handler(ngx_http_request_t *r)
{
    ngx_http_push_stream_main_conf_t   *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module);
    char                               *pos = NULL;

    ngx_http_push_stream_requested_channel_t       *requested_channels, *requested_channel;
    ngx_queue_t                                     *q;


    ngx_http_push_stream_set_expires(r, NGX_HTTP_PUSH_STREAM_EXPIRES_EPOCH, 0);

    // only accept GET method
    if (!(r->method & NGX_HTTP_GET)) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET);
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL);
    }

    ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_TAG, &NGX_HTTP_PUSH_STREAM_TAG);
    ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_COMMIT, &NGX_HTTP_PUSH_STREAM_COMMIT);

    //get channels ids
    requested_channels = ngx_http_push_stream_parse_channels_ids_from_path(r, r->pool);

    // if not specify a channel id, get info about all channels in a resumed way
    if ((requested_channels == NULL) || ngx_queue_empty(&requested_channels->queue)) {
        return ngx_http_push_stream_send_response_all_channels_info_summarized(r);
    }

    for (q = ngx_queue_head(&requested_channels->queue); q != ngx_queue_sentinel(&requested_channels->queue); q = ngx_queue_next(q)) {
        requested_channel = ngx_queue_data(q, ngx_http_push_stream_requested_channel_t, queue);

        // could not have a large size
        if ((mcf->max_channel_id_length != NGX_CONF_UNSET_UINT) && (requested_channel->id->len > mcf->max_channel_id_length)) {
            ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: channel id is larger than allowed %d", requested_channel->id->len);
            return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE);
        }

        if ((pos = ngx_strchr(requested_channel->id->data, '*')) != NULL) {
            ngx_str_t *aux = NULL;
            if (pos != (char *) requested_channel->id->data) {
                *pos = '\0';
                requested_channel->id->len  = ngx_strlen(requested_channel->id->data);
                aux = requested_channel->id;
            }
            return ngx_http_push_stream_send_response_all_channels_info_detailed(r, aux);
        }

        // if specify a channel id equals to ALL, get info about all channels in a detailed way
        if (ngx_memn2cmp(requested_channel->id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, requested_channel->id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) {
            return ngx_http_push_stream_send_response_all_channels_info_detailed(r, NULL);
        }

        requested_channel->channel = ngx_http_push_stream_find_channel(requested_channel->id, r->connection->log, mcf);
    }

    // if specify a channels ids != ALL, get info about specified channels if they exists
    return ngx_http_push_stream_send_response_channels_info_detailed(r, requested_channels);
}
static ngx_int_t
ngx_http_vhost_traffic_status_display_handler(ngx_http_request_t *r)
{
    size_t                                     len;
    u_char                                    *p;
    ngx_int_t                                  rc;
    ngx_http_vhost_traffic_status_ctx_t       *ctx;

    ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module);

    if (!ctx->enable) {
        return NGX_HTTP_NOT_IMPLEMENTED;
    }

    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    len = 0;

    p = (u_char *) ngx_strchr(r->uri.data, '/');

    if (p) {
        p = (u_char *) ngx_strchr(p + 1, '/');
        len = r->uri.len - (p - r->uri.data);
    }

    /* control processing handler */
    if (p && len >= sizeof("/control") - 1) {
        p = r->uri.data + r->uri.len - sizeof("/control") + 1;
        if (ngx_strncasecmp(p, (u_char *) "/control", sizeof("/control") - 1) == 0) {
            rc = ngx_http_vhost_traffic_status_display_handler_control(r);
            goto done;
        }
    }

    /* default processing handler */
    rc = ngx_http_vhost_traffic_status_display_handler_default(r);

done:

    return rc;
}
static ngx_int_t
ngx_http_tfs_parse_session_id(ngx_str_t *session_id, uint64_t *app_id)
{
  char        *first_pos;
  const char  separator_key = '-';

  first_pos = ngx_strchr(session_id->data, separator_key);
  if (first_pos == NULL) {
      return NGX_ERROR;
  }

  return ngx_http_tfs_atoull(session_id->data, ((u_char *)first_pos - session_id->data),
                             (unsigned long long *) app_id);
}
static void
ngx_rtmp_cmd_fill_args(u_char name[NGX_RTMP_MAX_NAME], 
        u_char args[NGX_RTMP_MAX_ARGS])
{
    u_char      *p;

    p = (u_char *)ngx_strchr(name, '?');
    if (p == NULL) {
        return;
    }

    *p++ = 0;
    ngx_cpystrn(args, p, NGX_RTMP_MAX_ARGS);
}
static off_t
ngx_http_slice_get_start(ngx_http_request_t *r)
{
    off_t             start, cutoff, cutlim;
    u_char           *p;
    ngx_table_elt_t  *h;

    if (r->headers_in.if_range) {
        return 0;
    }

    h = r->headers_in.range;

    if (h == NULL
        || h->value.len < 7
        || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0)
    {
        return 0;
    }

    p = h->value.data + 6;

    if (ngx_strchr(p, ',')) {
        return 0;
    }

    while (*p == ' ') { p++; }

    if (*p == '-') {
        return 0;
    }

    cutoff = NGX_MAX_OFF_T_VALUE / 10;
    cutlim = NGX_MAX_OFF_T_VALUE % 10;

    start = 0;

    while (*p >= '0' && *p <= '9') {
        if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) {
            return 0;
        }

        start = start * 10 + *p++ - '0';
    }

    return start;
}
/* This funcion returns pointer to a static buffer */
static void
ngx_rtmp_record_make_path(ngx_rtmp_session_t *s,
                          ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path)
{
    ngx_rtmp_record_ctx_t          *ctx;
    ngx_rtmp_record_app_conf_t     *rracf;
    u_char                         *p, *l;
    struct tm                       tm;

    static u_char                   buf[NGX_TIME_T_LEN + 1];
    static u_char                   pbuf[NGX_MAX_PATH + 1];

    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module);

    rracf = rctx->conf;

    /* create file path */
    p = pbuf;
    l = pbuf + sizeof(pbuf) - 1;

    p = ngx_cpymem(p, rracf->path.data,
                ngx_min(rracf->path.len, (size_t)(l - p - 1)));
    *p++ = '/';
    p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name),
                (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT);

    /* append timestamp */
    if (rracf->unique) {
        p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T",
                       rctx->timestamp) - buf, l - p));
    }

    if (ngx_strchr(rracf->suffix.data, '%')) {
        ngx_libc_localtime(rctx->timestamp, &tm);
        p += strftime((char *) p, l - p, (char *) rracf->suffix.data, &tm);
    } else {
        p = ngx_cpymem(p, rracf->suffix.data,
                ngx_min(rracf->suffix.len, (size_t)(l - p)));
    }

    *p = 0;
    path->data = pbuf;
    path->len  = p - pbuf;

    ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
                   "record: %V path: '%V'", &rracf->id, path);
}
static char *
ngx_rtmp_exec_prepare_arg(ngx_rtmp_session_t *s, ngx_str_t *arg)
{
    ngx_rtmp_core_app_conf_t       *cacf;
    ngx_rtmp_exec_ctx_t            *ctx;
    u_char                         *p, *pp;
    ngx_str_t                       result;

    cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module);
    ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module);

    /* substitute $app/${app} & $name/${name} */
    ngx_str_set(&result, "");
    pp = arg->data;
    for ( ;; ) {
        p = (u_char *)ngx_strchr(pp, '$');
        ngx_rtmp_exec_append(&result, pp, p ? p - pp : 0);
        if (p == NULL) {
            return (char *)result.data;
        }
        pp = p + 1;
        if (p != arg->data && p[-1] == '\\') {
            goto dollar;
        }
        if (!ngx_strncmp(p + 1, "app", sizeof("app") - 1)
            || !ngx_strncmp(p + 1, "{app}", sizeof("{app}") - 1)) 
        {
            ngx_rtmp_exec_append(&result, cacf->name.data, cacf->name.len);
            pp += (p[1] == '{' ? sizeof("{app}") - 1 : sizeof("app") - 1);
            continue;
        }
        if (!ngx_strncmp(p + 1, "name", sizeof("name") - 1)
            || !ngx_strncmp(p + 1, "{name}", sizeof("{name}") - 1)) 
        {
            ngx_rtmp_exec_append(&result, ctx->name, 0);
            pp += (p[1] == '{' ? sizeof("{name}") - 1 : sizeof("name") - 1);
            continue;
        }
dollar:
        ngx_rtmp_exec_append(&result, (u_char *)"$", 1);
    }
}
Exemple #10
0
void
ngx_debug_init()
{
#if (NGX_DEBUG_MALLOC)

#if __FreeBSD_version >= 500014
    _malloc_options = "J";
#else
    malloc_options = "J";
#endif

    ngx_debug_malloc = 1;

#else
    char  *mo;

    mo = getenv("MALLOC_OPTIONS");

    if (mo && ngx_strchr(mo, 'J')) {
        ngx_debug_malloc = 1;
    }
#endif
}
static char *
ngx_http_limit_req2_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    u_char                         *p;
    size_t                          len;
    ssize_t                         size;
    ngx_str_t                      *value, name, s;
    ngx_int_t                       rate, scale;
    ngx_uint_t                      i;
    ngx_array_t                    *variables;
    ngx_shm_zone_t                 *shm_zone;
    ngx_http_limit_req2_ctx_t      *ctx;
    ngx_http_limit_req2_variable_t *v;

    value = cf->args->elts;

    ctx = NULL;
    v = NULL;
    size = 0;
    rate = 1;
    scale = 1;
    name.len = 0;

    variables = ngx_array_create(cf->pool, 5,
                                 sizeof(ngx_http_limit_req2_variable_t));
    if (variables == NULL) {
        return NGX_CONF_ERROR;
    }

    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            name.len = p - name.data;

            s.data = p + 1;
            s.len = value[i].data + value[i].len - s.data;

            size = ngx_parse_size(&s);

            if (size == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            if (size < (ssize_t) (8 * ngx_pagesize)) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "zone \"%V\" is too small", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "rate=", 5) == 0) {

            len = value[i].len;
            p = value[i].data + len - 3;

            if (ngx_strncmp(p, "r/s", 3) == 0) {
                scale = 1;
                len -= 3;

            } else if (ngx_strncmp(p, "r/m", 3) == 0) {
                scale = 60;
                len -= 3;
            }

            rate = ngx_atoi(value[i].data + 5, len - 5);
            if (rate <= NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid rate \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (value[i].data[0] == '$') {

            value[i].len--;
            value[i].data++;

            v = ngx_array_push(variables);
            if (v == NULL) {
                return NGX_CONF_ERROR;
            }

            v->index = ngx_http_get_variable_index(cf, &value[i]);
            if (v->index == NGX_ERROR) {
                return NGX_CONF_ERROR;
            }

            v->var = value[i];

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }


    if (variables->nelts == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "no variable is defined for %V \"%V\"",
                           &cmd->name, &name);
        return NGX_CONF_ERROR;
    }

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req2_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }
    ctx->rate = rate * 1000 / scale;
    ctx->limit_vars = variables;

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_http_limit_req2_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (shm_zone->data) {

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   "limit_req2_zone \"%V\" is already bound to variable \"%V\"",
                   &value[1], &v->var);
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_http_limit_req2_init_zone;
    shm_zone->data = ctx;

    return NGX_CONF_OK;
}
Exemple #12
0
static char *
ngx_http_ip_behavior_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    u_char                         *p;
    size_t                          len;
    ssize_t                         size;
    ngx_str_t                      *value, name, s;
    ngx_shm_zone_t                 *shm_zone;
    ngx_http_ip_behavior_ctx_t     *ctx;
    ngx_uint_t                      i;
    ngx_int_t                       sample_base;
    ngx_int_t                       sample_cycle;
    ngx_int_t                       unit;

    value = cf->args->elts;

    ctx = NULL;
    size = 0;
    name.len = 0;
    sample_base = 50;
    sample_cycle = 5;
    unit = 1;

    for (i = 1; i < cf->args->nelts; i++) {
        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                        "invalid zone size \"%V\"", &value[1]);
                return NGX_CONF_ERROR;
            }

            name.len = p - name.data;

            s.data = p + 1;
            s.len = value[i].data + value[i].len - s.data;

            size = ngx_parse_size(&s);

            if (size == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                        "invalid zone size \"%V\"", &value[1]);
                return NGX_CONF_ERROR;
            }

            if (size < (ssize_t) (8 * ngx_pagesize)) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                        "zone \"%V\" is too small", &value[1]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "sample_base=", 12) == 0) {

            sample_base = ngx_atoi(value[i].data + 12, value[i].len - 12);
            if (sample_base <= 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid sample_base \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "sample_cycle=", 13) == 0) {
            len = value[i].len;
            p = value[i].data + len - 1;

            if (ngx_strncmp(p, "s", 1) == 0) {
                unit = 1;
                len--;
            } else if (ngx_strncmp(p, "m", 1) == 0) {
                unit = 60;
                len--;
            } else {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid sample_cycle unit \"%V\"",
                                   &value[i]);
                return NGX_CONF_ERROR;
            }

            sample_cycle = ngx_atoi(value[i].data + 13, len - 13);
            if (sample_cycle <= 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid sample_cycle \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            sample_cycle = sample_cycle * 1000 * unit;

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);

        return NGX_CONF_ERROR;
    }

    if (name.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "\"%V\" must have \"zone\" parameter",
                &cmd->name);
        return NGX_CONF_ERROR;
    }

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_ip_behavior_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_http_ip_behavior_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (shm_zone->data) {
        ctx = shm_zone->data;

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "%V \"%V\" is duplicated",
                           &cmd->name, &name);
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_http_ip_behavior_init_zone;
    shm_zone->data = ctx;

    ctx->sample_base = sample_base;
    ctx->sample_cycle = sample_cycle;

    return NGX_CONF_OK;
}
static int htoi(char* h) {
    char ok[] = "0123456789AaBbCcDdEeFf";

    if (ngx_strchr(ok, h[0]) == NULL || ngx_strchr(ok,h[1]) == NULL) { return -1; }
    return h_digit(h[0])*16 + h_digit(h[1]);
}
static char *
ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_referer_conf_t  *rlcf = conf;

    u_char                    *p;
    ngx_str_t                 *value, uri, name;
    ngx_uint_t                 i, n;
    ngx_http_variable_t       *var;
    ngx_http_server_name_t    *sn;
    ngx_http_core_srv_conf_t  *cscf;

    ngx_str_set(&name, "invalid_referer");

    var = ngx_http_add_variable(cf, &name,
                                NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH);
    if (var == NULL) {
        return NGX_CONF_ERROR;
    }

    var->get_handler = ngx_http_referer_variable;

    if (rlcf->keys == NULL) {
        rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t));
        if (rlcf->keys == NULL) {
            return NGX_CONF_ERROR;
        }

        rlcf->keys->pool = cf->pool;
        rlcf->keys->temp_pool = cf->pool;

        if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {
        if (value[i].len == 0) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid referer \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strcmp(value[i].data, "none") == 0) {
            rlcf->no_referer = 1;
            continue;
        }

        if (ngx_strcmp(value[i].data, "blocked") == 0) {
            rlcf->blocked_referer = 1;
            continue;
        }

        ngx_str_null(&uri);

        if (ngx_strcmp(value[i].data, "server_names") == 0) {

            cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);

            sn = cscf->server_names.elts;
            for (n = 0; n < cscf->server_names.nelts; n++) {

#if (NGX_PCRE)
                if (sn[n].regex) {

                    if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name,
                                                   sn[n].regex->regex)
                        != NGX_OK)
                    {
                        return NGX_CONF_ERROR;
                    }

                    continue;
                }
#endif

                if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri)
                    != NGX_OK)
                {
                    return NGX_CONF_ERROR;
                }
            }

            continue;
        }

        if (value[i].data[0] == '~') {
            if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK)
            {
                return NGX_CONF_ERROR;
            }

            continue;
        }

        p = (u_char *) ngx_strchr(value[i].data, '/');

        if (p) {
            uri.len = (value[i].data + value[i].len) - p;
            uri.data = p;
            value[i].len = p - value[i].data;
        }

        if (ngx_http_add_referer(cf, rlcf->keys, &value[i], &uri) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }

    return NGX_CONF_OK;
}
static char *
ngx_tcp_socketfd_shm_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_tcp_core_main_conf_t      *cmcf = conf;
    socketfd_shm_t                *socketfd_shm;
    ngx_str_t                      s, name, *value;
    u_char                        *p;
    ssize_t                        size;
    ngx_uint_t                     i;

    socketfd_shm = ngx_pcalloc(cf->pool, sizeof(socketfd_shm_t));
    if (cmcf->socketfd_shm == NULL) {
        return NGX_CONF_ERROR;
    }
    socketfd_shm->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
    if (socketfd_shm->path == NULL) {
        return NGX_CONF_ERROR;
    }
    socketfd_shm->max_socketfd_value = &cmcf->max_socketfd_value;

    value = cf->args->elts;

    socketfd_shm->path->name = value[1];

    if (socketfd_shm->path->name.data[socketfd_shm->path->name.len - 1] 
        == '/') {
        socketfd_shm->path->name.len--;
    }

    if (ngx_conf_full_name(cf->cycle, &socketfd_shm->path->name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    size = 0;
    for (i = 2; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {

            name.data = value[i].data + 10;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p) {
                name.len = p - name.data;

                p++;

                s.len = value[i].data + value[i].len - p;
                s.data = p;

                size = ngx_parse_size(&s);
                if (size > 8191) {
                    continue;
                }
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid keys zone size \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }
    }

    if (name.len == 0 || size == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"keys_zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }
    
    socketfd_shm->path->manager = NULL;
    socketfd_shm->path->loader = NULL;
    socketfd_shm->path->data = socketfd_shm;
    socketfd_shm->path->conf_file = cf->conf_file->file.name.data;
    socketfd_shm->path->line = cf->conf_file->line;

    if (ngx_add_path(cf, &socketfd_shm->path) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    socketfd_shm->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
    if (socketfd_shm->shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (socketfd_shm->shm_zone->data) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate zone \"%V\"", &name);
        return NGX_CONF_ERROR;
    }

    socketfd_shm->shm_zone->init = ngx_tcp_socketfd_shm_init;
    socketfd_shm->shm_zone->data = socketfd_shm;

    cmcf->socketfd_shm = socketfd_shm;

    return NGX_CONF_OK;
}
static char *
ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    u_char                            *p;
    size_t                             len;
    ssize_t                            size;
    ngx_str_t                         *value, name, s;
    ngx_int_t                          rate, scale;
    ngx_uint_t                         i;
    ngx_shm_zone_t                    *shm_zone;
    ngx_http_limit_req_ctx_t          *ctx;
    ngx_http_compile_complex_value_t   ccv;
#if (T_LIMIT_REQ_RATE_VAR)
    ngx_http_limit_req_variable_t      rate_var;
#endif

    value = cf->args->elts;

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

#if (T_LIMIT_REQ)
    {
    u_char      *p;
    size_t      len;
    ngx_str_t   v1;

    len = 0;
    for (i = 1; i < cf->args->nelts; i++) {
        if (i == 1 || value[i].data[0] == '$') {
            len += value[i].len;
        }
        break;
    }

    p = ngx_palloc(cf->pool, len);
    if (p == NULL) {
        return NGX_CONF_ERROR;
    }

    v1.len = len;
    v1.data = p;

    for (i = 1; i < cf->args->nelts; i++) {
        if (i == 1 || value[i].data[0] == '$') {
            p = ngx_cpymem(p, value[i].data, value[i].len);
        }
        break;

    }

    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

    ccv.cf = cf;
    ccv.value = &v1;
    ccv.complex_value = &ctx->key;

    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
    }
#else

    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

    ccv.cf = cf;
    ccv.value = &value[1];
    ccv.complex_value = &ctx->key;

    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
#endif

    size = 0;
    rate = 1;
    scale = 1;
    name.len = 0;

#if (T_LIMIT_REQ_RATE_VAR)
    memset(&rate_var, 0x0, sizeof(rate_var));
#endif

    for (i = 2; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            name.len = p - name.data;

            s.data = p + 1;
            s.len = value[i].data + value[i].len - s.data;

            size = ngx_parse_size(&s);

            if (size == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            if (size < (ssize_t) (8 * ngx_pagesize)) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "zone \"%V\" is too small", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "rate=", 5) == 0) {
#if (T_LIMIT_REQ_RATE_VAR)
            if (value[i].data[5] == '$') {

                value[i].data += 6;
                value[i].len -= 6;
                rate_var.index = ngx_http_get_variable_index(cf, &value[i]);

                if (rate_var.index == NGX_ERROR) {
                    return NGX_CONF_ERROR;
                }

                rate_var.var = value[i];

                continue;
            }
#endif

            len = value[i].len;
            p = value[i].data + len - 3;

            if (ngx_strncmp(p, "r/s", 3) == 0) {
                scale = 1;
                len -= 3;

            } else if (ngx_strncmp(p, "r/m", 3) == 0) {
                scale = 60;
                len -= 3;
            }

            rate = ngx_atoi(value[i].data + 5, len - 5);
            if (rate <= 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid rate \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

#if (T_LIMIT_REQ)
        if (value[i].data[0] == '$') {
            continue;
        }
#endif

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    ctx->rate = rate * 1000 / scale;

#if (T_LIMIT_REQ_RATE_VAR)
    ctx->rate_var = rate_var;
#endif

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_http_limit_req_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (shm_zone->data) {
        ctx = shm_zone->data;

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "%V \"%V\" is already bound to key \"%V\"",
                           &cmd->name, &name, &ctx->key.value);
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_http_limit_req_init_zone;
    shm_zone->data = ctx;

    return NGX_CONF_OK;
}
static char *
ngx_http_session_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    u_char                        *p;
    size_t                         size;
    ngx_str_t                     *value, name, s;
    ngx_uint_t                     i;
    ngx_shm_zone_t                *shm_zone;
    ngx_http_session_store_ctx_t  *ctx;

    value = cf->args->elts;

    ctx = NULL;
    size = 0;
    name.len = 0;

    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p) {
                *p = '\0';

                name.len = p - name.data;

                p++;

                s.len = value[i].data + value[i].len - p;
                s.data = p;

                size = ngx_parse_size(&s);
                if (size > 8191) {
                    continue;
                }
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid zone size \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (value[i].data[0] == '$') {

            value[i].len--;
            value[i].data++;

            ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_session_store_ctx_t));
            if (ctx == NULL) {
                return NGX_CONF_ERROR;
            }

            ctx->index = ngx_http_get_variable_index(cf, &value[i]);
            if (ctx->index == NGX_ERROR) {
                return NGX_CONF_ERROR;
            }

            ctx->var = value[i];

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0 || size == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    if (ctx == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "no variable is defined for session_zone \"%V\"",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_http_session_store_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_http_session_store_init_zone;
    shm_zone->data = ctx;

    return NGX_CONF_OK;
}
static char *
ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    u_char                       *p;
    ssize_t                       size;
    ngx_str_t                    *value, name, s;
    ngx_uint_t                    i;
    ngx_shm_zone_t               *shm_zone;
    ngx_stream_limit_conn_ctx_t  *ctx;

    value = cf->args->elts;

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_limit_conn_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    size = 0;
    name.len = 0;

    for (i = 2; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            name.len = p - name.data;

            s.data = p + 1;
            s.len = value[i].data + value[i].len - s.data;

            size = ngx_parse_size(&s);

            if (size == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            if (size < (ssize_t) (8 * ngx_pagesize)) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "zone \"%V\" is too small", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_stream_limit_conn_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (shm_zone->data) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "%V \"%V\" is already bound to key "
                           "\"$binary_remote_addr\"",
                           &cmd->name, &name);
        return NGX_CONF_ERROR;
    }

    if (ngx_strcmp(value[1].data, "$binary_remote_addr") != 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "unsupported key \"%V\", use "
                           "$binary_remote_addr", &value[1]);
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_stream_limit_conn_init_zone;
    shm_zone->data = ctx;

    return NGX_CONF_OK;
}
static char *
ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__);
    u_char                     *p;
    ssize_t                     size;
    ngx_str_t                  *value, name, s;
    ngx_uint_t                  i;
    ngx_shm_zone_t             *shm_zone;
    ngx_http_limit_conn_ctx_t  *ctx;

    value = cf->args->elts;

    ctx = NULL;
    size = 0;
    name.len = 0;

    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            name.len = p - name.data;

            s.data = p + 1;
            s.len = value[i].data + value[i].len - s.data;

            size = ngx_parse_size(&s);

            if (size == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            if (size < (ssize_t) (8 * ngx_pagesize)) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "zone \"%V\" is too small", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (value[i].data[0] == '$') {

            value[i].len--;
            value[i].data++;

            ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
            if (ctx == NULL) {
                return NGX_CONF_ERROR;
            }

            ctx->index = ngx_http_get_variable_index(cf, &value[i]);
            if (ctx->index == NGX_ERROR) {
                return NGX_CONF_ERROR;
            }

            ctx->var = value[i];

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    if (ctx == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "no variable is defined for %V \"%V\"",
                           &cmd->name, &name);
        return NGX_CONF_ERROR;
    }

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_http_limit_conn_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (shm_zone->data) {
        ctx = shm_zone->data;

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "%V \"%V\" is already bound to variable \"%V\"",
                           &cmd->name, &name, &ctx->var);
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_http_limit_conn_init_zone;
    shm_zone->data = ctx;

    return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_push_stream_publisher_handler(ngx_http_request_t *r)
{
    ngx_http_push_stream_main_conf_t   *mcf = ngx_http_get_module_main_conf(r, ngx_http_push_stream_module);
    ngx_http_push_stream_loc_conf_t    *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module);
    ngx_http_push_stream_module_ctx_t  *ctx;

    ngx_http_push_stream_requested_channel_t       *requested_channels, *requested_channel;
    ngx_str_t                                       vv_allowed_origins = ngx_null_string;
    ngx_queue_t                                     *q;

    ngx_http_push_stream_set_expires(r, NGX_HTTP_PUSH_STREAM_EXPIRES_EPOCH, 0);


    if (cf->allowed_origins != NULL) {
        ngx_http_push_stream_complex_value(r, cf->allowed_origins, &vv_allowed_origins);
    }

    if (vv_allowed_origins.len > 0) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, &vv_allowed_origins);
        const ngx_str_t *header_value = (cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) ? &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_DELETE_METHODS : &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_METHODS;
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_METHODS, header_value);
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, &NGX_HTTP_PUSH_STREAM_ALLOWED_HEADERS);
    }

    if (r->method & NGX_HTTP_OPTIONS) {
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_OK, NULL);
    }

    // only accept GET, POST, PUT and DELETE methods if enable publisher administration
    if ((cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && !(r->method & (NGX_HTTP_GET|NGX_HTTP_POST|NGX_HTTP_PUT|NGX_HTTP_DELETE))) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_DELETE_METHODS);
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL);
    }

    // only accept GET, POST and PUT methods if NOT enable publisher administration
    if ((cf->location_type != NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && !(r->method & (NGX_HTTP_GET|NGX_HTTP_POST|NGX_HTTP_PUT))) {
        ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_PUT_METHODS);
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_NOT_ALLOWED, NULL);
    }

    if ((ctx = ngx_http_push_stream_add_request_context(r)) == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: unable to create request context");
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL);
    }

    //get channels ids
    requested_channels = ngx_http_push_stream_parse_channels_ids_from_path(r, r->pool);
    if ((requested_channels == NULL) || ngx_queue_empty(&requested_channels->queue)) {
        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: the push_stream_channels_path is required but is not set");
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_NO_CHANNEL_ID_MESSAGE);
    }

    for (q = ngx_queue_head(&requested_channels->queue); q != ngx_queue_sentinel(&requested_channels->queue); q = ngx_queue_next(q)) {
        requested_channel = ngx_queue_data(q, ngx_http_push_stream_requested_channel_t, queue);

        // check if channel id isn't equals to ALL or contain wildcard
        if ((ngx_memn2cmp(requested_channel->id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, requested_channel->id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) || (ngx_strchr(requested_channel->id->data, '*') != NULL)) {
            return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_CHANNEL_ID_NOT_AUTHORIZED_MESSAGE);
        }

        // could not have a large size
        if ((mcf->max_channel_id_length != NGX_CONF_UNSET_UINT) && (requested_channel->id->len > mcf->max_channel_id_length)) {
            ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: channel id is larger than allowed %d", requested_channel->id->len);
            return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_BAD_REQUEST, &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE);
        }

        if (r->method & (NGX_HTTP_POST|NGX_HTTP_PUT)) {
            // create the channel if doesn't exist
            requested_channel->channel = ngx_http_push_stream_get_channel(requested_channel->id, r->connection->log, mcf);
            if (requested_channel->channel == NULL) {
                return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL);
            }

            if (requested_channel->channel == NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: number of channels were exceeded");
                return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED_MESSAGE);
            }
        } else {
            requested_channel->channel = ngx_http_push_stream_find_channel(requested_channel->id, r->connection->log, mcf);
        }

        if ((r->method != NGX_HTTP_GET) && (requested_channel->channel != NULL) && requested_channel->channel->for_events) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: only internal routines can change events channel");
            return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_INTERNAL_ONLY_EVENTS_CHANNEL_MESSAGE);
        }
    }

    ctx->requested_channels = requested_channels;

    if (r->method & (NGX_HTTP_POST|NGX_HTTP_PUT)) {
        return ngx_http_push_stream_publisher_handle_after_read_body(r, ngx_http_push_stream_publisher_body_handler);
    }

    if ((cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && (r->method == NGX_HTTP_DELETE)) {
        return ngx_http_push_stream_publisher_handle_after_read_body(r, ngx_http_push_stream_publisher_delete_handler);
    }

    return ngx_http_push_stream_send_response_channels_info_detailed(r, requested_channels);
}
static ngx_int_t
ngx_apikey_access_filter_handler( ngx_http_request_t *r ) {

	ngx_apikey_access_filter_loc_conf_t  *lcf = NULL;
	
	ngx_int_t	rc;

	u_char		*last = NULL;

	ngx_str_t 	auth_header_key		= ngx_string("X-AuthAPI");
	ngx_str_t 	auth_header_value	= ngx_null_string;
	
	ngx_str_t 	client_id			= ngx_null_string;
	ngx_str_t	issued_time			= ngx_null_string;
	ngx_str_t	client_digest		= ngx_null_string;
	
	
	/* If the module isn't enabled..let's the request go! */	
    lcf = ngx_http_get_module_loc_conf(r, ngx_apikey_access_filter_module);
    if ( !lcf->enable ) {
		return NGX_OK;
    }
	// ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uri = %V", &r->uri );

	/* Let's look for the request token in the cookies */
	rc = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &auth_header_key, &auth_header_value);
	if ( rc != NGX_DECLINED ) {
		ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
			"found auth token in cookie with value ( %s )", auth_header_value.data );
	} else {
	/* Nothing in the cookies ? let's search the request headers */
		ngx_table_elt_t	*token_header = ngx_apikey_find_request_header( r, auth_header_key.data, auth_header_key.len );
		if ( token_header ) {
			u_char *last = NULL;
			auth_header_value.len = ngx_strlen( token_header->value.data );
			auth_header_value.data = ngx_pcalloc( r->pool, auth_header_value.len + 1 );
			last = ngx_copy( auth_header_value.data, token_header->value.data, auth_header_value.len );
			*last = (u_char)'\0';
			
			//ngx_str_set( &auth_token_value, token_header->value.data );
			ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
				"found auth token in header with value ( %s ) - (%d)", auth_header_value.data, auth_header_value.len );
		}
	}
	
	/* Nothing found? Access Denied! */
	if ( auth_header_value.data == NULL ) {
		ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth token not found neither in request header or cookie" );
		return NGX_HTTP_FORBIDDEN;
	}

	/* Let's parse plain token */
	last =  (u_char *)ngx_strchr( auth_header_value.data, '|' );
	if ( last == NULL ) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(%s) while parsing auth token", __func__ );
        return NGX_HTTP_FORBIDDEN;
	}
	
	/* Token parsing: client_id */
	client_id.len = (last - auth_header_value.data);
	client_id.data = ngx_pcalloc( r->pool, client_id.len + 1 );
	if ( client_id.data == NULL ) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(%s) failed allocating memory", __func__ );
		return NGX_ERROR;
	}
	last = (u_char *)ngx_copy( client_id.data, auth_header_value.data, client_id.len );
	*last = (u_char)'\0';
	ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "client id: %s - (%d)", client_id.data, client_id.len );

	/* Token parsing: client_issued_time */
	last = (u_char *)ngx_strchr( auth_header_value.data + (client_id.len + 1), (u_char)'|' );
	if ( last == NULL ) {
		ngx_pfree( r->pool, client_id.data );
		ngx_pfree( r->pool, auth_header_value.data );
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(%s) while parsing auth token", __func__ );
        return NGX_HTTP_FORBIDDEN;
	}

	issued_time.len = ( last - auth_header_value.data - (client_id.len + 1) );
	issued_time.data = ngx_pcalloc( r->pool, issued_time.len + 1 );
	if ( issued_time.data == NULL ) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(%s) failed allocating memory", __func__ );
		return NGX_ERROR;
	}
	last = ngx_copy( issued_time.data, auth_header_value.data + client_id.len + 1, issued_time.len  );
	*last = (u_char)'\0';
	ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "request time: %V", &issued_time );

	/* Token parsing: digest */
	client_digest.len = (auth_header_value.len - (client_id.len + 1) - (issued_time.len + 1) );
	if ( client_digest.len <= 1 ) {
		ngx_pfree( r->pool, client_id.data );
		ngx_pfree( r->pool, auth_header_value.data );
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(%s) while parsing auth token", __func__ );
        return NGX_HTTP_FORBIDDEN;
	}

	client_digest.data = ngx_pcalloc( r->pool, client_digest.len + 1 );
	if ( client_digest.data == NULL ) {
		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(%s) failed allocating memory", __func__ );
		return NGX_ERROR;
	}
	last = ngx_copy( client_digest.data, auth_header_value.data + (client_id.len + 1) + (issued_time.len + 1), client_digest.len  );
	*last = (u_char)'\0';
	ngx_log_debug( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "client digest: %V", &client_digest );

	/* Verify the token digest */
	rc = ngx_apikey_verify( r, &client_id, &issued_time, &client_digest );

	return (rc != NGX_OK) ? NGX_HTTP_FORBIDDEN : NGX_OK;
}
static ngx_int_t
ngx_http_push_stream_validate_channels(ngx_http_request_t *r, ngx_http_push_stream_requested_channel_t *channels_ids, ngx_int_t *status_code, ngx_str_t **explain_error_message)
{
    ngx_http_push_stream_main_conf_t               *mcf = ngx_http_push_stream_module_main_conf;
    ngx_http_push_stream_loc_conf_t                *cf = ngx_http_get_module_loc_conf(r, ngx_http_push_stream_module);
    ngx_http_push_stream_requested_channel_t       *cur = channels_ids;
    ngx_uint_t                                      subscribed_channels_qtd = 0;
    ngx_uint_t                                      subscribed_broadcast_channels_qtd = 0;
    ngx_flag_t                                      is_broadcast_channel;
    ngx_http_push_stream_channel_t                 *channel;

    while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) {
        // could not be ALL channel or contain wildcard
        if ((ngx_memn2cmp(cur->id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, cur->id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) || (ngx_strchr(cur->id->data, '*') != NULL)) {
            *status_code = NGX_HTTP_FORBIDDEN;
            *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_NO_CHANNEL_ID_NOT_AUTHORIZED_MESSAGE;
            return NGX_ERROR;
        }

        // could not have a large size
        if ((mcf->max_channel_id_length != NGX_CONF_UNSET_UINT) && (cur->id->len > mcf->max_channel_id_length)) {
            ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "push stream module: channel id is larger than allowed %d", cur->id->len);
            *status_code = NGX_HTTP_BAD_REQUEST;
            *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_LARGE_CHANNEL_ID_MESSAGE;
            return NGX_ERROR;
        }

        // count subscribed channel and broadcasts
        subscribed_channels_qtd++;
        is_broadcast_channel = 0;
        if ((mcf->broadcast_channel_prefix.len > 0) && (ngx_strncmp(cur->id->data, mcf->broadcast_channel_prefix.data, mcf->broadcast_channel_prefix.len) == 0)) {
            is_broadcast_channel = 1;
            subscribed_broadcast_channels_qtd++;
        }

        // check if channel exists when authorized_channels_only is on
        if (cf->authorized_channels_only && !is_broadcast_channel && (((channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log)) == NULL) || (channel->stored_messages == 0))) {
            *status_code = NGX_HTTP_FORBIDDEN;
            *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_CANNOT_CREATE_CHANNELS;
            return NGX_ERROR;
        }

        // check if channel is full of subscribers
        if ((mcf->max_subscribers_per_channel != NGX_CONF_UNSET_UINT) && (((channel = ngx_http_push_stream_find_channel(cur->id, r->connection->log)) != NULL) && (channel->subscribers >= mcf->max_subscribers_per_channel))) {
            *status_code = NGX_HTTP_FORBIDDEN;
            *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_SUBSCRIBERS_PER_CHANNEL;
            return NGX_ERROR;
        }
    }

    // check if number of subscribed broadcast channels is acceptable
    if ((cf->broadcast_channel_max_qtd != NGX_CONF_UNSET_UINT) && (subscribed_broadcast_channels_qtd > 0) && ((subscribed_broadcast_channels_qtd > cf->broadcast_channel_max_qtd) || (subscribed_broadcast_channels_qtd == subscribed_channels_qtd))) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push stream module: max subscribed broadcast channels exceeded");
        *status_code = NGX_HTTP_FORBIDDEN;
        *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_TOO_MUCH_BROADCAST_CHANNELS;
        return NGX_ERROR;
    }

    // create the channels in advance, if doesn't exist, to ensure max number of channels in the server
    cur = channels_ids;
    while ((cur = (ngx_http_push_stream_requested_channel_t *) ngx_queue_next(&cur->queue)) != channels_ids) {
        channel = ngx_http_push_stream_get_channel(cur->id, r->connection->log, cf);
        if (channel == NULL) {
            ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: unable to allocate memory for new channel");
            *status_code = NGX_HTTP_INTERNAL_SERVER_ERROR;
            *explain_error_message = NULL;
            return NGX_ERROR;
        }

        if (channel == NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED) {
            ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: number of channels were exceeded");
            *status_code = NGX_HTTP_FORBIDDEN;
            *explain_error_message = (ngx_str_t *) &NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED_MESSAGE;
            return NGX_ERROR;
        }
    }

    return NGX_OK;
}
static char *
ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    u_char                            *p;
    size_t                             len;
    ssize_t                            size;
    ngx_str_t                         *value, name, s;
    ngx_int_t                          rate, scale;
    ngx_uint_t                         i;
    ngx_shm_zone_t                    *shm_zone;
    ngx_http_limit_req_ctx_t          *ctx;
    ngx_http_compile_complex_value_t   ccv;

    value = cf->args->elts;

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

    ccv.cf = cf;
    ccv.value = &value[1];
    ccv.complex_value = &ctx->key;

    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    size = 0;
    rate = 1;
    scale = 1;
    name.len = 0;

    for (i = 2; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            name.data = value[i].data + 5;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            name.len = p - name.data;

            s.data = p + 1;
            s.len = value[i].data + value[i].len - s.data;

            size = ngx_parse_size(&s);

            if (size == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid zone size \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            if (size < (ssize_t) (8 * ngx_pagesize)) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "zone \"%V\" is too small", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "rate=", 5) == 0) {

            len = value[i].len;
            p = value[i].data + len - 3;

            if (ngx_strncmp(p, "r/s", 3) == 0) {
                scale = 1;
                len -= 3;

            } else if (ngx_strncmp(p, "r/m", 3) == 0) {
                scale = 60;
                len -= 3;
            }

            rate = ngx_atoi(value[i].data + 5, len - 5);
            if (rate <= 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid rate \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    ctx->rate = rate * 1000 / scale;

    shm_zone = ngx_shared_memory_add(cf, &name, size,
                                     &ngx_http_limit_req_module);
    if (shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (shm_zone->data) {
        ctx = shm_zone->data;

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "%V \"%V\" is already bound to key \"%V\"",
                           &cmd->name, &name, &ctx->key.value);
        return NGX_CONF_ERROR;
    }

    shm_zone->init = ngx_http_limit_req_init_zone;
    shm_zone->data = ctx;

    return NGX_CONF_OK;
}
ngx_int_t
convert_image(ngx_http_request_t *r, convert_options_t *option_info,
    Image **image)
{
    ngx_uint_t                          i;

    ngx_http_gm_convert_option_t      *options;
    ngx_http_gm_convert_option_t      *option;

    RectangleInfo                      geometry;
    RectangleInfo                      geometry_info;
    ExceptionInfo                      exception;

    Image                             *resize_image = NULL;
    u_char                            *resize_geometry = NULL;
    u_char                            *need_crop_resize = NULL;

    Image                             *rotate_image = NULL;
    u_char                            *rotate_degrees = NULL;
    ngx_int_t                          degrees;
    ngx_int_t                          degrees_suffix_len = 0;

    dd("entering");

    options = option_info->options->elts;

    for (i = 0; i < option_info->options->nelts; ++i) {
        option = &options[i];

        if (option->type == NGX_HTTP_GM_RESIZE_OPTION) {
            dd("starting resize");

            resize_geometry = ngx_http_gm_get_str_value(r,
                    option->resize_geometry_cv, &option->resize_geometry);

            need_crop_resize = (u_char *)ngx_strchr(resize_geometry, 'c');
            if (need_crop_resize != NULL) {
                *need_crop_resize = '^';
            }

            if (resize_geometry == NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "gm filter: resize image, get resize geometry failed");
                return  NGX_ERROR;
            }

            if (ngx_strncmp(resize_geometry, "no", 2) == 0) {
                continue;
            }


            (void) GetImageGeometry(*image, (char *)resize_geometry, 1,
                                    &geometry);

            if ((geometry.width == (*image)->columns) &&
                (geometry.height == (*image)->rows))
                continue;

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "resize image geometry: \"%s\"", resize_geometry);

            GetExceptionInfo(&exception);
            resize_image = ResizeImage(*image, geometry.width, geometry.height,
                (*image)->filter,(*image)->blur, &exception);

            if (resize_image == (Image *) NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "gm filter: resize image failed, "
                              "arg: \"%s\" severity: \"%O\" "
                              "reason: \"%s\", description: \"%s\"",
                              resize_geometry, exception.severity,
                              exception.reason, exception.description);

                DestroyExceptionInfo(&exception);

                return NGX_ERROR;
            }

            DestroyImage(*image);
            *image = resize_image;
            DestroyExceptionInfo(&exception);

            if (need_crop_resize != NULL) {
                GetGeometry((char *)resize_geometry,
                            &geometry_info.x, &geometry_info.y,
                            (unsigned long *)(&geometry_info.width),
                            (unsigned long *)(&geometry_info.height));

                if (geometry_info.width > (*image)->columns ||
                        geometry_info.height > (*image)->rows) {
                    continue;
                }

                geometry_info.x = ((*image)->columns - geometry_info.width) / 2;
                geometry_info.y = ((*image)->rows - geometry_info.height) / 2;

                GetExceptionInfo(&exception);
                resize_image = CropImage(*image, &geometry_info, &exception);


                if (resize_image == (Image *) NULL) {
                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                "gm filter: resize croping image failed, "
                                "arg: \"%s\" severity: \"%O\" "
                                "reason: \"%s\", description: \"%s\"",
                                resize_geometry, exception.severity,
                                exception.reason, exception.description);

                    DestroyExceptionInfo(&exception);

                    return NGX_ERROR;
                }

                DestroyImage(*image);
                *image = resize_image;
                DestroyExceptionInfo(&exception);
            }

        } else if (option->type == NGX_HTTP_GM_ROTATE_OPTION) {
            dd("starting rotate");

            rotate_degrees = ngx_http_gm_get_str_value(r,
                    option->rotate_degrees_cv, &option->rotate_degrees);

            if (rotate_degrees == NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                        "gm filter: rotate image, get rotate degrees failed");
                return  NGX_ERROR;
            }

            if (ngx_strchr(rotate_degrees,'>') != (char *) NULL) {
                if ((*image)->columns <= (*image)->rows)
                    continue;
                degrees_suffix_len = 1;
            }

            if (ngx_strchr(rotate_degrees,'<') != (char *) NULL) {
                if ((*image)->columns >= (*image)->rows)
                    continue;
                degrees_suffix_len = 1;
            }

            degrees = 0;
            degrees = ngx_atoi(rotate_degrees,
                               ngx_strlen(rotate_degrees) - degrees_suffix_len);

            if (degrees == 0) {
                continue;
            }

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "rotate image degrees: \"%O\"", degrees);

            GetExceptionInfo(&exception);


            rotate_image=RotateImage(*image, degrees, &exception);
            if (rotate_image == (Image *) NULL) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "gm filter: rotate image failed, "
                              "degrees: \"%s\" severity: \"%O\" "
                              "reason: \"%s\", description: \"%s\"",
                              option->rotate_degrees, exception.severity,
                              exception.reason, exception.description);

                DestroyExceptionInfo(&exception);

                return NGX_ERROR;
            }

            DestroyImage(*image);
            *image = rotate_image;

            DestroyExceptionInfo(&exception);

        } else {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "gm filter: convert command, unkonwn option");
            return NGX_ERROR;
        }
    }

    return NGX_OK;
}
Exemple #25
0
static char *
ngx_http_naxsi_cr_loc_conf(ngx_conf_t *cf, ngx_command_t *cmd,
			   void *conf)
{

  ngx_http_dummy_loc_conf_t	*alcf = conf, **bar;  
  ngx_http_dummy_main_conf_t    *main_cf;
  ngx_str_t			*value;
  ngx_http_check_rule_t		*rule_c;
  unsigned int	i;
  u_char			*var_end;

  

  if (!alcf || !cf)
    return (NGX_CONF_ERROR); 
  value = cf->args->elts;
  main_cf = ngx_http_conf_get_module_main_conf(cf, ngx_http_naxsi_module);
  if (!alcf->pushed) { 
    bar = ngx_array_push(main_cf->locations);
    if (!bar)
      return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
    *bar = alcf;
    alcf->pushed = 1;
  }
  
  if (ngx_strcmp(value[0].data, TOP_CHECK_RULE_T) &&
      ngx_strcmp(value[0].data, TOP_CHECK_RULE_N))
    return (NGX_CONF_ERROR);
  
/* #ifdef _debug_readconf */
/*   ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,  */
/* 		     "pushing rule %d in check rules", rule.rule_id);   */
/* #endif */

  i = 0;
  if (!alcf->check_rules)
    alcf->check_rules = ngx_array_create(cf->pool, 2, 
					 sizeof(ngx_http_check_rule_t));
  if (!alcf->check_rules)
    return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
  rule_c = ngx_array_push(alcf->check_rules);
  if (!rule_c) return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
  memset(rule_c, 0, sizeof(ngx_http_check_rule_t));
  /* process the first word : score rule */
  if (value[1].data[i] == '$') {
    var_end = (u_char *) ngx_strchr((value[1].data)+i, ' ');
    if (!var_end) { /* LCOV_EXCL_START */
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
      /* LCOV_EXCL_STOP */
    }
    rule_c->sc_tag.len = var_end - value[1].data;
    rule_c->sc_tag.data = ngx_pcalloc(cf->pool, rule_c->sc_tag.len + 1);
    if (!rule_c->sc_tag.data)
      return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
    memcpy(rule_c->sc_tag.data, value[1].data, rule_c->sc_tag.len);
    i += rule_c->sc_tag.len + 1;
  } else {
    /* LCOV_EXCL_START */
    ngx_http_dummy_line_conf_error(cf, value);
    return (NGX_CONF_ERROR); 
    /* LCOV_EXCL_STOP */
  }
  // move to next word
  while (value[1].data[i] && value[1].data[i] == ' ')
    i++;
  // get the comparison type
  if (value[1].data[i] == '>' && value[1].data[i+1] == '=')
    rule_c->cmp = SUP_OR_EQUAL;
  else if (value[1].data[i] == '>' && value[1].data[i+1] != '=')
    rule_c->cmp = SUP;
  else if (value[1].data[i] == '<' && value[1].data[i+1] == '=')
    rule_c->cmp = INF_OR_EQUAL;
  else if (value[1].data[i] == '<' && value[1].data[i+1] != '=')
    rule_c->cmp = INF;
  else {
    ngx_http_dummy_line_conf_error(cf, value);
    return (NGX_CONF_ERROR);
  }
  // move to next word
  while (value[1].data[i] && !(value[1].data[i] >= '0' && 
			       value[1].data[i] <= '9') && (value[1].data[i] != '-'))
    i++;
  NX_LOG_DEBUG(_debug_readconf,  NGX_LOG_EMERG, cf, 0,
	       "XX-special score in checkrule:%s from (%d)",
	       value[1].data, atoi((const char *)value[1].data+i));
  // get the score
  rule_c->sc_score = atoi((const char *)(value[1].data+i));
  /* process the second word : Action rule */
  if (ngx_strstr(value[2].data, "BLOCK"))
    rule_c->block = 1;
  else if (ngx_strstr(value[2].data,"ALLOW"))
    rule_c->allow = 1;
  else if (ngx_strstr(value[2].data, "LOG"))
    rule_c->log = 1;
  else if (ngx_strstr(value[2].data, "DROP"))
    rule_c->drop = 1;
  else {
    /* LCOV_EXCL_START */
    ngx_http_dummy_line_conf_error(cf, value);
    return (NGX_CONF_ERROR);
    /* LCOV_EXCL_STOP */
  }
  return (NGX_CONF_OK);
}
/*
 *	Q:	怎样找到函数中创建的 ngx_http_file_cache_t?
 *	A:	1. 可以通过path中的data字段找到此cache
 *		2. 通过共享内存区 shm_zone.data 字段找到
 */
char *
ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    off_t                   max_size;				//	cache磁盘空间大小
    u_char                 *last, *p;
    time_t                  inactive;				//	cache不活跃的时间
    ssize_t                 size;					//	共享内存区的大小(必须大于8k)
    ngx_str_t               s, name, *value;		//	name: 共享内存区的名称
    ngx_int_t               loader_files;
    ngx_msec_t              loader_sleep, loader_threshold;
    ngx_uint_t              i, n;
    ngx_http_file_cache_t  *cache;

    cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
    if (cache == NULL) {
        return NGX_CONF_ERROR;
    }

    cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
    if (cache->path == NULL) {
        return NGX_CONF_ERROR;
    }

    inactive = 600;							//	不活跃时间默认是10分钟
    loader_files = 100;
    loader_sleep = 50;
    loader_threshold = 200;

    name.len = 0;
    size = 0;
    max_size = NGX_MAX_OFF_T_VALUE;

    value = cf->args->elts;

	//	cache路径, 如果以"/"结尾将被自动去掉
    cache->path->name = value[1];			

    if (cache->path->name.data[cache->path->name.len - 1] == '/') {
        cache->path->name.len--;
    }

	//	获取cache的完整路径
    if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
    }


    for (i = 2; i < cf->args->nelts; i++) {

		//	设置子目录数和子目录的文件名长度
        if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {

            p = value[i].data + 7;
            last = value[i].data + value[i].len;

            for (n = 0; n < 3 && p < last; n++) {

                if (*p > '0' && *p < '3') {

                    cache->path->level[n] = *p++ - '0';
                    cache->path->len += cache->path->level[n] + 1;

                    if (p == last) {
                        break;
                    }

                    if (*p++ == ':' && n < 2 && p != last) {
                        continue;
                    }

                    goto invalid_levels;
                }

                goto invalid_levels;
            }

            if (cache->path->len < 10 + 3) {
                continue;
            }

        invalid_levels:

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid \"levels\" \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }


		//	设置cache的共享存储区
        if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {

            name.data = value[i].data + 10;					//	共享内存区的名字

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p) {
                *p = '\0';

                name.len = p - name.data;					//	共享内存区的名字长度

                p++;

                s.len = value[i].data + value[i].len - p;	//	共享内存区的大小
                s.data = p;

                size = ngx_parse_size(&s);					//	申请的共享内存区大小(必须大于8K)
                if (size > 8191) {							
                    continue;
                }
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid keys zone size \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

		//	设置cache不活跃的时间
        if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            inactive = ngx_parse_time(&s, 1);
            if (inactive == (time_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid inactive value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }


		//	设置缓存磁盘空间大小 max_size
        if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            max_size = ngx_parse_offset(&s);
            if (max_size < 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid max_size value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }


		//	loader_files
        if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {

            loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
            if (loader_files == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid loader_files value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

		//	loader_sleep
        if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) {

            s.len = value[i].len - 13;
            s.data = value[i].data + 13;

            loader_sleep = ngx_parse_time(&s, 0);
            if (loader_sleep == (ngx_msec_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid loader_sleep value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }


		//	loader_threshold
        if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {

            s.len = value[i].len - 17;
            s.data = value[i].data + 17;

            loader_threshold = ngx_parse_time(&s, 0);
            if (loader_threshold == (ngx_msec_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid loader_threshold value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }	//	for

    if (name.len == 0 || size == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"keys_zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    cache->path->manager = ngx_http_file_cache_manager;
    cache->path->loader = ngx_http_file_cache_loader;
    cache->path->data = cache;								//	设置 ngx_http_file_cache_t 结构
    cache->path->conf_file = cf->conf_file->file.name.data;
    cache->path->line = cf->conf_file->line;
    cache->loader_files = loader_files;
    cache->loader_sleep = loader_sleep;
    cache->loader_threshold = loader_threshold;

	//	添加目录到系统管理目录表中
    if (ngx_add_path(cf, &cache->path) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

	//	添加共享内存到系统管理表中
    cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
    if (cache->shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

	/*	e.g. "proxy_cache" 与 "proxy_cache_path" 这两个指令的使用是有顺序的, 
			 "proxy_cache" 指令仅初始化共享内存信息,cache->shm_zone->data字段设置为NULL,
			  如果data字段被设置,说明重复定义了共享内存区	*/
    if (cache->shm_zone->data) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate zone \"%V\"", &name);
        return NGX_CONF_ERROR;
    }


    cache->shm_zone->init = ngx_http_file_cache_init;
    cache->shm_zone->data = cache;

    cache->inactive = inactive;
    cache->max_size = max_size;

    return NGX_CONF_OK;
}
Exemple #27
0
char *
ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    off_t                   max_size;
    u_char                 *last, *p;
    time_t                  inactive;
    ssize_t                 size;
    ngx_str_t               s, name, *value;
    ngx_uint_t              i, n;
    ngx_http_file_cache_t  *cache;

    cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
    if (cache == NULL) {
        return NGX_CONF_ERROR;
    }

    cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
    if (cache->path == NULL) {
        return NGX_CONF_ERROR;
    }

    inactive = 600;

    name.len = 0;
    size = 0;
    max_size = NGX_MAX_OFF_T_VALUE;

    value = cf->args->elts;

    cache->path->name = value[1];

    if (cache->path->name.data[cache->path->name.len - 1] == '/') {
        cache->path->name.len--;
    }

    if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    for (i = 2; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {

            p = value[i].data + 7;
            last = value[i].data + value[i].len;

            for (n = 0; n < 3 && p < last; n++) {

                if (*p > '0' && *p < '3') {

                    cache->path->level[n] = *p++ - '0';
                    cache->path->len += cache->path->level[n] + 1;

                    if (p == last) {
                        break;
                    }

                    if (*p++ == ':' && n < 2 && p != last) {
                        continue;
                    }

                    goto invalid_levels;
                }

                goto invalid_levels;
            }

            if (cache->path->len < 10 + 3) {
                continue;
            }

        invalid_levels:

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid \"levels\" \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {

            name.data = value[i].data + 10;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p) {
                *p = '\0';

                name.len = p - name.data;

                p++;

                s.len = value[i].data + value[i].len - p;
                s.data = p;

                size = ngx_parse_size(&s);
                if (size > 8191) {
                    continue;
                }
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid keys zone size \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            inactive = ngx_parse_time(&s, 1);
            if (inactive < 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid inactive value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            max_size = ngx_parse_offset(&s);
            if (max_size < 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid max_size value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }

    if (name.len == 0 || size == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"keys_zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    cache->path->manager = ngx_http_file_cache_manager;
    cache->path->loader = ngx_http_file_cache_loader;
    cache->path->data = cache;

    if (ngx_add_path(cf, &cache->path) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
    if (cache->shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (cache->shm_zone->data) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate zone \"%V\"", &name);
        return NGX_CONF_ERROR;
    }


    cache->shm_zone->init = ngx_http_file_cache_init;
    cache->shm_zone->data = cache;

    cache->inactive = inactive;
    cache->max_size = max_size;

    return NGX_CONF_OK;
}
Exemple #28
0
static ngx_int_t
ngx_http_push_stream_publisher_handle_post(ngx_http_push_stream_loc_conf_t *cf, ngx_http_request_t *r, ngx_str_t *id)
{
    ngx_int_t                           rc;
    ngx_http_push_stream_channel_t     *channel = NULL;

    // check if channel id isn't equals to ALL or contain wildcard
    if ((ngx_memn2cmp(id->data, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.data, id->len, NGX_HTTP_PUSH_STREAM_ALL_CHANNELS_INFO_ID.len) == 0) || (ngx_strchr(id->data, '*') != NULL)) {
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_NO_CHANNEL_ID_NOT_AUTHORIZED_MESSAGE);
    }

    // create the channel if doesn't exist
    channel = ngx_http_push_stream_get_channel(id, r->connection->log, cf);
    if (channel == NULL) {
        ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: unable to allocate memory for new channel");
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_INTERNAL_SERVER_ERROR, NULL);
    }

    if (channel == NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED) {
        ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, "push stream module: number of channels were exceeded");
        return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_FORBIDDEN, &NGX_HTTP_PUSH_STREAM_NUMBER_OF_CHANNELS_EXCEEDED_MESSAGE);
    }

    /*
     * Instruct ngx_http_read_subscriber_request_body to store the request
     * body entirely in a memory buffer or in a file.
     */
    r->request_body_in_single_buf = 0;
    r->request_body_in_persistent_file = 1;
    r->request_body_in_clean_file = 0;
    r->request_body_file_log_level = 0;

    // parse the body message and return
    rc = ngx_http_read_client_request_body(r, ngx_http_push_stream_publisher_body_handler);
    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    return NGX_DONE;
}
//#define readconf_debug
static char *
ngx_http_dummy_read_conf(ngx_conf_t *cf, ngx_command_t *cmd, 
			 void *conf)
{
  ngx_http_dummy_loc_conf_t	*alcf = conf, **bar;
  
  ngx_http_dummy_main_conf_t	*main_cf;
  ngx_str_t			*value;
  ngx_http_rule_t		rule, *rule_r;
  ngx_http_check_rule_t		*rule_c;
  ngx_http_custom_rule_location_t	*location;
  unsigned int	i;
  u_char			*var_end;
  
#ifdef readconf_debug
  if (cf) {
    value = cf->args->elts;
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "TOP READ CONF %V %V", 
		       &(value[0]), &(value[1]));  
  }
#endif
  if (!alcf || !cf)
    return (NGX_CONF_ERROR); 
  value = cf->args->elts;
  main_cf = ngx_http_conf_get_module_main_conf(cf, ngx_http_naxsi_module);
  if (!alcf->pushed) { 
    bar = ngx_array_push(main_cf->locations);
    if (!bar)
      return (NGX_CONF_ERROR);
    *bar = alcf;
    alcf->pushed = 1;
  }
  /* store denied URL for location */
  if (!ngx_strcmp(value[0].data, TOP_DENIED_URL_T) && value[1].len) {
    alcf->denied_url = ngx_pcalloc(cf->pool, sizeof(ngx_str_t));
    if (!alcf->denied_url)
      return (NGX_CONF_ERROR);
    alcf->denied_url->data = ngx_pcalloc(cf->pool, value[1].len+1);
    if (!alcf->denied_url->data)
      return (NGX_CONF_ERROR);
    memcpy(alcf->denied_url->data, value[1].data, value[1].len);
    alcf->denied_url->len = value[1].len;
    return (NGX_CONF_OK);
  }
  /* it's a flagrule, just a hack to enable/disable mod */
  if (!ngx_strcmp(value[0].data, TOP_ENABLED_FLAG_T)) {
    alcf->enabled = 1;
    return (NGX_CONF_OK);
  }
  /* it's a flagrule, just a hack to enable/disable mod */
  if (!ngx_strcmp(value[0].data, TOP_DISABLED_FLAG_T)) {
    alcf->force_disabled = 1;
    return (NGX_CONF_OK);
  }
  /* it's a flagrule, currently just a hack to enable/disable learning mode */
  if (!ngx_strcmp(value[0].data, TOP_LEARNING_FLAG_T)) {
    alcf->learning = 1;
    return (NGX_CONF_OK);
  }
  if (!ngx_strcmp(value[0].data, TOP_BASIC_RULE_T)) {
#ifdef readconf_debug
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "XX-TOP READ CONF %s", 
		       value[0].data);  
#endif
    memset(&rule, 0, sizeof(ngx_http_rule_t));
    if (ngx_http_dummy_cfg_parse_one_rule(cf, value, &rule, 
					   cf->args->nelts) != NGX_CONF_OK)
      {
	ngx_http_dummy_line_conf_error(cf, value);
	return (NGX_CONF_ERROR);
      }
    /* push in whitelist rules, as it have a whitelist ID array */
    if (rule.wl_id) {
#ifdef readconf_debug
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			 "pushing rule %d in whitelist rules", 
			 rule.rule_id);  
#endif
      if (alcf->whitelist_rules == NULL) {
	alcf->whitelist_rules = ngx_array_create(cf->pool, 2,
						 sizeof(ngx_http_rule_t));
	if (alcf->whitelist_rules == NULL) {
	  return NGX_CONF_ERROR;
	}
      }
      rule_r = ngx_array_push(alcf->whitelist_rules);
      if (!rule_r) {
	return (NGX_CONF_ERROR);
      }
      memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
    }
    /* else push in appropriate ruleset */
    else {
      if (rule.br->headers) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in header rules", 
			   rule.rule_id);  
#endif
	if (alcf->header_rules == NULL)  {
	  alcf->header_rules = ngx_array_create(cf->pool, 2,
						sizeof(ngx_http_rule_t));
	  if (alcf->header_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->header_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in body match rules (POST/PUT) */
      if (rule.br->body || rule.br->body_var) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in body rules", rule.rule_id);  
#endif
	if (alcf->body_rules == NULL) {
	  alcf->body_rules = ngx_array_create(cf->pool, 2,
					      sizeof(ngx_http_rule_t));
	  if (alcf->body_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->body_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in generic rules, as it's matching the URI */
      if (rule.br->url) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in generic rules", 
			   rule.rule_id);  
#endif
	if (alcf->generic_rules == NULL) {
	  alcf->generic_rules = ngx_array_create(cf->pool, 2,
						 sizeof(ngx_http_rule_t));
	  if (alcf->generic_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->generic_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in GET arg rules, but we should push in POST rules too  */
      if (rule.br->args_var || rule.br->args) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in GET rules", rule.rule_id);  
#endif
	if (alcf->get_rules == NULL) {
	  alcf->get_rules = ngx_array_create(cf->pool, 2,
					     sizeof(ngx_http_rule_t));
	  if (alcf->get_rules == NULL) 
	    return NGX_CONF_ERROR;
	}
	rule_r = ngx_array_push(alcf->get_rules);
	if (!rule_r) return (NGX_CONF_ERROR);
	memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
      }
      /* push in custom locations. It's a rule matching a VAR_NAME or an EXACT_URI :
	 - GET_VAR, POST_VAR, URI */
      if (rule.br->custom_location) {
#ifdef readconf_debug
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
			   "pushing rule %d in custom_location rules", 
			   rule.rule_id);  
#endif
	location = rule.br->custom_locations->elts;
	for (i = 0; i < rule.br->custom_locations->nelts; i++) {
	  if (location[i].args_var) {
	    if (alcf->get_rules == NULL) {
	      alcf->get_rules = ngx_array_create(cf->pool, 2,
						 sizeof(ngx_http_rule_t));
	      if (alcf->get_rules == NULL) 
		return NGX_CONF_ERROR;
	    }
	    rule_r = ngx_array_push(alcf->get_rules);
	    if (!rule_r) return (NGX_CONF_ERROR);
	    memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
	  }
	  if (location[i].body_var) {
	    if (alcf->body_rules == NULL) {
	      alcf->body_rules = ngx_array_create(cf->pool, 2,
						  sizeof(ngx_http_rule_t));
	      if (alcf->body_rules == NULL) 
		return NGX_CONF_ERROR;
	    }
	    rule_r = ngx_array_push(alcf->body_rules);
	    if (!rule_r) return (NGX_CONF_ERROR);
	    memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
		      
	  }
	  if (location[i].headers_var) {
	    if (alcf->header_rules == NULL) {
	      alcf->header_rules = ngx_array_create(cf->pool, 2,
						    sizeof(ngx_http_rule_t));
	      if (alcf->header_rules == NULL) 
		return NGX_CONF_ERROR;
	    }
	    rule_r = ngx_array_push(alcf->header_rules);
	    if (!rule_r) return (NGX_CONF_ERROR);
	    memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
	  }
	}
      }
    }
    return (NGX_CONF_OK);
  }
  /* this should be moved in a function, plus this code is not safe. */
  else if (!ngx_strcmp(value[0].data, TOP_CHECK_RULE_T)) {
#ifdef readconf_debug
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
		       "pushing rule %d in check rules", rule.rule_id);  
#endif
    i = 0;
    if (!alcf->check_rules)
      alcf->check_rules = ngx_array_create(cf->pool, 2, 
					   sizeof(ngx_http_check_rule_t));
    if (!alcf->check_rules)
      return (NGX_CONF_ERROR);
    rule_c = ngx_array_push(alcf->check_rules);
    if (!rule_c) return (NGX_CONF_ERROR);
    memset(rule_c, 0, sizeof(ngx_http_check_rule_t));
    /* process the first word : score rule */
    if (value[1].data[i] == '$') {
#ifdef MDBG
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "XX-special score rule !");
#endif
	var_end = (u_char *) ngx_strchr((value[1].data)+i, ' ');
	if (!var_end) {
	  ngx_http_dummy_line_conf_error(cf, value);
	  return (NGX_CONF_ERROR);
	}
	rule_c->sc_tag.data = ngx_pcalloc(cf->pool, var_end - value[1].data +1);
	if (!rule_c->sc_tag.data)
	  return (NGX_CONF_ERROR);
	memcpy(rule_c->sc_tag.data, value[1].data, (var_end - value[1].data));
	i += (var_end - value[1].data) + 1;
	rule_c->sc_tag.len = (var_end - value[1].data);
      }
    else {
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
    }
    // move to next word
    while (value[1].data[i] && value[1].data[i] == ' ')
      i++;
    // get the comparison type
    if (value[1].data[i] == '>' && value[1].data[i+1] == '=')
      rule_c->cmp = SUP_OR_EQUAL;
    else if (value[1].data[i] == '>' && value[1].data[i+1] != '=')
      rule_c->cmp = SUP;
    else if (value[1].data[i] == '<' && value[1].data[i+1] == '=')
      rule_c->cmp = INF_OR_EQUAL;
    else if (value[1].data[i] == '<' && value[1].data[i+1] != '=')
      rule_c->cmp = INF;
    else {
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
    }
    // move to next word
    while (value[1].data[i] && !(value[1].data[i] >= '0' && 
				 value[1].data[i] <= '9') && (value[1].data[i] != '-'))
      i++;
#ifdef readconf_debug
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
		       "XX-special score in checkrule:%s from (%d)", 
		       value[1].data, atoi((const char *)value[1].data+i));
#endif
    // get the score
    rule_c->sc_score = atoi((const char *)(value[1].data+i));
    /* process the second word : Action rule */
    if (!ngx_strstr(value[2].data, "BLOCK"))
      rule_c->block = 1;
    else if (!ngx_strstr(value[2].data, "ALLOW"))
      rule_c->block = 1;
    else if (!ngx_strstr(value[2].data, "LOG"))
      rule_c->block = 1;
    else {
      ngx_http_dummy_line_conf_error(cf, value);
      return (NGX_CONF_ERROR);
    }
    return (NGX_CONF_OK);
  }
  ngx_http_dummy_line_conf_error(cf, value);
  return (NGX_CONF_ERROR);
}
static ngx_int_t
ngx_http_autoindex_handler(ngx_http_request_t *r)
{
    u_char                         *last, *filename, scale;
    off_t                           length;
    size_t                          len, utf_len, allocated, root;
    ngx_tm_t                        tm;
    ngx_err_t                       err;
    ngx_buf_t                      *b;
    ngx_int_t                       rc, size;
    ngx_str_t                       path;
    ngx_dir_t                       dir;
    ngx_uint_t                      i, level, utf8;
    ngx_pool_t                     *pool;
    ngx_time_t                     *tp;
    ngx_chain_t                     out;
    ngx_array_t                     entries;
    ngx_http_autoindex_entry_t     *entry;
    ngx_http_autoindex_loc_conf_t  *alcf;

    static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

    if (r->uri.data[r->uri.len - 1] != '/') {
        return NGX_DECLINED;
    }

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_DECLINED;
    }

    alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);

    if (!alcf->enable) {
        return NGX_DECLINED;
    }

    /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */

    last = ngx_http_map_uri_to_path(r, &path, &root,
                                    NGX_HTTP_AUTOINDEX_PREALLOCATE);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    allocated = path.len;
    path.len = last - path.data;
    if (path.len > 1) {
        path.len--;
    }
    path.data[path.len] = '\0';

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http autoindex: \"%s\"", path.data);

    if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
        err = ngx_errno;

        if (err == NGX_ENOENT
            || err == NGX_ENOTDIR
            || err == NGX_ENAMETOOLONG)
        {
            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;

        } else if (err == NGX_EACCES) {
            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;

        } else {
            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_log_error(level, r->connection->log, err,
                      ngx_open_dir_n " \"%s\" failed", path.data);

        return rc;
    }

#if (NGX_SUPPRESS_WARN)

    /* MSVC thinks 'entries' may be used without having been initialized */
    ngx_memzero(&entries, sizeof(ngx_array_t));

#endif

    /* TODO: pool should be temporary pool */
    pool = r->pool;

    if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t))
        != NGX_OK)
    {
        return ngx_http_autoindex_error(r, &dir, &path);
    }

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_type_len = sizeof("text/html") - 1;
    ngx_str_set(&r->headers_out.content_type, "text/html");

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        if (ngx_close_dir(&dir) == NGX_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                          ngx_close_dir_n " \"%V\" failed", &path);
        }

        return rc;
    }

    filename = path.data;
    filename[path.len] = '/';

    if (r->headers_out.charset.len == 5
        && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
           == 0)
    {
        utf8 = 1;

    } else {
        utf8 = 0;
    }

    for ( ;; ) {
        ngx_set_errno(0);

        if (ngx_read_dir(&dir) == NGX_ERROR) {
            err = ngx_errno;

            if (err != NGX_ENOMOREFILES) {
                ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
                              ngx_read_dir_n " \"%V\" failed", &path);
                return ngx_http_autoindex_error(r, &dir, &path);
            }

            break;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http autoindex file: \"%s\"", ngx_de_name(&dir));

        len = ngx_de_namelen(&dir);

        if (ngx_de_name(&dir)[0] == '.') {
            continue;
        }

        if (!dir.valid_info) {

            /* 1 byte for '/' and 1 byte for terminating '\0' */

            if (path.len + 1 + len + 1 > allocated) {
                allocated = path.len + 1 + len + 1
                                     + NGX_HTTP_AUTOINDEX_PREALLOCATE;

                filename = ngx_pnalloc(pool, allocated);
                if (filename == NULL) {
                    return ngx_http_autoindex_error(r, &dir, &path);
                }

                last = ngx_cpystrn(filename, path.data, path.len + 1);
                *last++ = '/';
            }

            ngx_cpystrn(last, ngx_de_name(&dir), len + 1);

            if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
                err = ngx_errno;

                if (err != NGX_ENOENT) {
                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
                                  ngx_de_info_n " \"%s\" failed", filename);

                    if (err == NGX_EACCES) {
                        continue;
                    }

                    return ngx_http_autoindex_error(r, &dir, &path);
                }

                if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                                  ngx_de_link_info_n " \"%s\" failed",
                                  filename);
                    return ngx_http_autoindex_error(r, &dir, &path);
                }
            }
        }

        entry = ngx_array_push(&entries);
        if (entry == NULL) {
            return ngx_http_autoindex_error(r, &dir, &path);
        }

        entry->name.len = len;

        entry->name.data = ngx_pnalloc(pool, len + 1);
        if (entry->name.data == NULL) {
            return ngx_http_autoindex_error(r, &dir, &path);
        }

        ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);

        entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
                                           NGX_ESCAPE_HTML);

        if (utf8) {
            entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
        } else {
            entry->utf_len = len;
        }

        entry->colon = (ngx_strchr(entry->name.data, ':') != NULL);

        entry->dir = ngx_de_is_dir(&dir);
        entry->mtime = ngx_de_mtime(&dir);
        entry->size = ngx_de_size(&dir);
    }

    if (ngx_close_dir(&dir) == NGX_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                      ngx_close_dir_n " \"%s\" failed", &path);
    }

    len = sizeof(title) - 1
          + r->uri.len
          + sizeof(header) - 1
          + r->uri.len
          + sizeof("</h1>") - 1
          + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1
          + sizeof("</pre><hr>") - 1
          + sizeof(tail) - 1;

    entry = entries.elts;
    for (i = 0; i < entries.nelts; i++) {
        len += sizeof("<a href=\"") - 1
            + entry[i].name.len + entry[i].escape
            + 1                                          /* 1 is for "/" */
            + sizeof("\">") - 1
            + entry[i].name.len - entry[i].utf_len + entry[i].colon * 2
            + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 2
            + sizeof("</a>") - 1
            + sizeof(" 28-Sep-1970 12:00 ") - 1
            + 20                                         /* the file size */
            + 2;
    }

    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (entries.nelts > 1) {
        ngx_qsort(entry, (size_t) entries.nelts,
                  sizeof(ngx_http_autoindex_entry_t),
                  ngx_http_autoindex_cmp_entries);
    }

    b->last = ngx_cpymem(b->last, title, sizeof(title) - 1);
    b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
    b->last = ngx_cpymem(b->last, header, sizeof(header) - 1);
    b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
    b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1);

    b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF,
                         sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1);

    tp = ngx_timeofday();

    for (i = 0; i < entries.nelts; i++) {
        b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);

        if (entry[i].colon) {
            *b->last++ = '.';
            *b->last++ = '/';
        }

        if (entry[i].escape) {
            ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len,
                           NGX_ESCAPE_HTML);

            b->last += entry[i].name.len + entry[i].escape;

        } else {
            b->last = ngx_cpymem(b->last, entry[i].name.data,
                                 entry[i].name.len);
        }

        if (entry[i].dir) {
            *b->last++ = '/';
        }

        *b->last++ = '"';
        *b->last++ = '>';

        len = entry[i].utf_len;

        if (entry[i].name.len != len) {
            if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
                utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1;

            } else {
                utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1;
            }

            b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data,
                                       utf_len, entry[i].name.len + 1);
            last = b->last;

        } else {
            b->last = ngx_cpystrn(b->last, entry[i].name.data,
                                  NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
            last = b->last - 3;
        }

        if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
            b->last = ngx_cpymem(last, "..&gt;</a>", sizeof("..&gt;</a>") - 1);

        } else {
            if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
                *b->last++ = '/';
                len++;
            }

            b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1);
            ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len);
            b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len;
        }

        *b->last++ = ' ';

        ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm);

        b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ",
                              tm.ngx_tm_mday,
                              months[tm.ngx_tm_mon - 1],
                              tm.ngx_tm_year,
                              tm.ngx_tm_hour,
                              tm.ngx_tm_min);

        if (alcf->exact_size) {
            if (entry[i].dir) {
                b->last = ngx_cpymem(b->last,  "                  -",
                                     sizeof("                  -") - 1);
            } else {
                b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
            }

        } else {
            if (entry[i].dir) {
                b->last = ngx_cpymem(b->last,  "      -",
                                     sizeof("      -") - 1);

            } else {
                length = entry[i].size;

                if (length > 1024 * 1024 * 1024 - 1) {
                    size = (ngx_int_t) (length / (1024 * 1024 * 1024));
                    if ((length % (1024 * 1024 * 1024))
                                                > (1024 * 1024 * 1024 / 2 - 1))
                    {
                        size++;
                    }
                    scale = 'G';

                } else if (length > 1024 * 1024 - 1) {
                    size = (ngx_int_t) (length / (1024 * 1024));
                    if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
                        size++;
                    }
                    scale = 'M';

                } else if (length > 9999) {
                    size = (ngx_int_t) (length / 1024);
                    if (length % 1024 > 511) {
                        size++;
                    }
                    scale = 'K';

                } else {
                    size = (ngx_int_t) length;
                    scale = '\0';
                }

                if (scale) {
                    b->last = ngx_sprintf(b->last, "%6i%c", size, scale);

                } else {
                    b->last = ngx_sprintf(b->last, " %6i", size);
                }
            }
        }

        *b->last++ = CR;
        *b->last++ = LF;
    }

    /* TODO: free temporary pool */

    b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);

    b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);

    if (r == r->main) {
        b->last_buf = 1;
    }

    b->last_in_chain = 1;

    out.buf = b;
    out.next = NULL;

    return ngx_http_output_filter(r, &out);
}