Skip to content

Adding variable support to slice module #571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
lucasRolff opened this issue Mar 9, 2025 · 3 comments
Open

Adding variable support to slice module #571

lucasRolff opened this issue Mar 9, 2025 · 3 comments
Labels

Comments

@lucasRolff
Copy link

Describe the feature you'd like to add to nginx

It would be really nice to be able to set a variable for the slice directive in the slicing module, so it can be set/loaded from e.g. Redis (if one were to load variables from Redis via Lua for example).

Describe the problem this feature solves

Currently it's not possible to control the slice size via a variable, meaning if you want to change this for a given host, you'd need a completely new server block.

Instead it would be nice to be able to set the slicing size through a variable, and pass the variable to the slice directive.

Additional context

I use nginx with the nginx lua module, and I load a lot of my server block config from Redis into variables.
However, sometimes I want to either disable or enable slicing for a given host (e.g largefiles.cache.com) but keep it disabled for smallfiles.cache.com).

@Bit-Warrior-X
Copy link

Hi, @lucasRolff
I have solved current issue.
please contact with me

@lucasRolff
Copy link
Author

Should be possible to share your solution with the public then :)

@kavyaPerepu19
Copy link

Hi,@lucasRolff
The slice directive is defined around line 61 of the file nginx/src/http/modules/ngx_http_slice_filter_module.c
in the following lines:

static ngx_command_t  ngx_http_slice_filter_commands[] = {

    { ngx_string("slice"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_size_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_slice_loc_conf_t, size),
      NULL },

      ngx_null_command
};

Currently, the slice directive uses ngx_conf_set_size_slot as its handler, which means it only accepts a fixed size value at configuration time, not a variable.

This is the code that implements variable slice

static char *ngx_http_slice_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static size_t ngx_http_slice_get_size(ngx_http_request_t *r, ngx_http_slice_loc_conf_t *slcf);



static ngx_int_t
ngx_http_slice_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_int_t                   rc;
    ngx_chain_t                *cl;
    ngx_http_slice_ctx_t       *ctx;
    ngx_http_slice_loc_conf_t  *slcf;
    size_t                      slice_size;

    ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module);

    if (ctx == NULL || r != r->main) {
        return ngx_http_next_body_filter(r, in);
    }

    for (cl = in; cl; cl = cl->next) {
        if (cl->buf->last_buf) {
            cl->buf->last_buf = 0;
            cl->buf->last_in_chain = 1;
            cl->buf->sync = 1;
            ctx->last = 1;
        }
    }

    rc = ngx_http_next_body_filter(r, in);

    if (rc == NGX_ERROR || !ctx->last) {
        return rc;
    }

    if (ctx->sr && !ctx->sr->done) {
        return rc;
    }

    if (!ctx->active) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "missing slice response");
        return NGX_ERROR;
    }

    if (ctx->start >= ctx->end) {
        ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module);
        ngx_http_send_special(r, NGX_HTTP_LAST);
        return rc;
    }

    if (r->buffered) {
        return rc;
    }

    if (ngx_http_subrequest(r, &r->uri, &r->args, &ctx->sr, NULL,
                            NGX_HTTP_SUBREQUEST_CLONE)
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(ctx->sr, ctx, ngx_http_slice_filter_module);

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module);
    slice_size = ngx_http_slice_get_size(r, slcf);

    ctx->range.len = ngx_sprintf(ctx->range.data, "bytes=%O-%O", ctx->start,
                                 ctx->start + (off_t) slice_size - 1)
                     - ctx->range.data;

    ctx->active = 0;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http slice subrequest: \"%V\"", &ctx->range);

    return rc;
}

static ngx_int_t
ngx_http_slice_range_variable(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data)
{
    u_char                     *p;
    ngx_http_slice_ctx_t       *ctx;
    ngx_http_slice_loc_conf_t  *slcf;
    size_t                      slice_size;

    ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module);

    if (ctx == NULL) {
        if (r != r->main || r->headers_out.status) {
            v->not_found = 1;
            return NGX_OK;
        }

        slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module);
        slice_size = ngx_http_slice_get_size(r, slcf);

        if (slice_size == 0) {
            v->not_found = 1;
            return NGX_OK;
        }

        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_slice_ctx_t));
        if (ctx == NULL) {
            return NGX_ERROR;
        }

        p = ngx_pnalloc(r->pool, sizeof("bytes=-") - 1 + 2 * NGX_OFF_T_LEN);
        if (p == NULL) {
            return NGX_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module);

        ctx->start = slice_size * (ngx_http_slice_get_start(r) / slice_size);

        ctx->range.data = p;
        ctx->range.len = ngx_sprintf(p, "bytes=%O-%O", ctx->start,
                                     ctx->start + (off_t) slice_size - 1)
                         - p;
    }

    v->data = ctx->range.data;
    v->valid = 1;
    v->not_found = 0;
    v->no_cacheable = 1;
    v->len = ctx->range.len;

    return NGX_OK;
}

static char *
ngx_http_slice_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_slice_loc_conf_t  *slcf = conf;
    ngx_str_t                  *value;
    ngx_http_compile_complex_value_t   ccv;

    if (slcf->size != NGX_CONF_UNSET_SIZE || slcf->cv != NULL) {
        return "is duplicate";
    }

    value = cf->args->elts;

    if (value[1].data[0] == '$') {
        /* Variable */
        slcf->cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
        if (slcf->cv == 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 = slcf->cv;

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

        return NGX_CONF_OK;
    }

    return ngx_conf_set_size_slot(cf, cmd, conf);
}


static size_t
ngx_http_slice_get_size(ngx_http_request_t *r, ngx_http_slice_loc_conf_t *slcf)
{
    ngx_str_t  val;
    size_t     size;

    if (slcf->cv) {
        if (ngx_http_complex_value(r, slcf->cv, &val) != NGX_OK) {
            return slcf->size;
        }

        size = ngx_parse_size(&val);

        if (size == (size_t) NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "invalid slice size \"%V\"", &val);
            return slcf->size;
        }

        return size;
    }

    return slcf->size;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants