1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Roman Arutyunyan
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevtypedef struct {
14e18a033bSKonstantin Ananyev    size_t               size;
15e18a033bSKonstantin Ananyev} ngx_http_slice_loc_conf_t;
16e18a033bSKonstantin Ananyev
17e18a033bSKonstantin Ananyev
18e18a033bSKonstantin Ananyevtypedef struct {
19e18a033bSKonstantin Ananyev    off_t                start;
20e18a033bSKonstantin Ananyev    off_t                end;
21e18a033bSKonstantin Ananyev    ngx_str_t            range;
22e18a033bSKonstantin Ananyev    ngx_str_t            etag;
23e18a033bSKonstantin Ananyev    unsigned             last:1;
24e18a033bSKonstantin Ananyev    unsigned             active:1;
25e18a033bSKonstantin Ananyev    ngx_http_request_t  *sr;
26e18a033bSKonstantin Ananyev} ngx_http_slice_ctx_t;
27e18a033bSKonstantin Ananyev
28e18a033bSKonstantin Ananyev
29e18a033bSKonstantin Ananyevtypedef struct {
30e18a033bSKonstantin Ananyev    off_t                start;
31e18a033bSKonstantin Ananyev    off_t                end;
32e18a033bSKonstantin Ananyev    off_t                complete_length;
33e18a033bSKonstantin Ananyev} ngx_http_slice_content_range_t;
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_slice_header_filter(ngx_http_request_t *r);
37e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_slice_body_filter(ngx_http_request_t *r,
38e18a033bSKonstantin Ananyev    ngx_chain_t *in);
39e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_slice_parse_content_range(ngx_http_request_t *r,
40e18a033bSKonstantin Ananyev    ngx_http_slice_content_range_t *cr);
41e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_slice_range_variable(ngx_http_request_t *r,
42e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
43e18a033bSKonstantin Ananyevstatic off_t ngx_http_slice_get_start(ngx_http_request_t *r);
44e18a033bSKonstantin Ananyevstatic void *ngx_http_slice_create_loc_conf(ngx_conf_t *cf);
45e18a033bSKonstantin Ananyevstatic char *ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent,
46e18a033bSKonstantin Ananyev    void *child);
47e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_slice_add_variables(ngx_conf_t *cf);
48e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_slice_init(ngx_conf_t *cf);
49e18a033bSKonstantin Ananyev
50e18a033bSKonstantin Ananyev
51e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_slice_filter_commands[] = {
52e18a033bSKonstantin Ananyev
53e18a033bSKonstantin Ananyev    { ngx_string("slice"),
54e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
55e18a033bSKonstantin Ananyev      ngx_conf_set_size_slot,
56e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
57e18a033bSKonstantin Ananyev      offsetof(ngx_http_slice_loc_conf_t, size),
58e18a033bSKonstantin Ananyev      NULL },
59e18a033bSKonstantin Ananyev
60e18a033bSKonstantin Ananyev      ngx_null_command
61e18a033bSKonstantin Ananyev};
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyev
64e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_slice_filter_module_ctx = {
65e18a033bSKonstantin Ananyev    ngx_http_slice_add_variables,          /* preconfiguration */
66e18a033bSKonstantin Ananyev    ngx_http_slice_init,                   /* postconfiguration */
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
69e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
70e18a033bSKonstantin Ananyev
71e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
72e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
73e18a033bSKonstantin Ananyev
74e18a033bSKonstantin Ananyev    ngx_http_slice_create_loc_conf,        /* create location configuration */
75e18a033bSKonstantin Ananyev    ngx_http_slice_merge_loc_conf          /* merge location configuration */
76e18a033bSKonstantin Ananyev};
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyevngx_module_t  ngx_http_slice_filter_module = {
80e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
81e18a033bSKonstantin Ananyev    &ngx_http_slice_filter_module_ctx,     /* module context */
82e18a033bSKonstantin Ananyev    ngx_http_slice_filter_commands,        /* module directives */
83e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
84e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
85e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
86e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
87e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
88e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
89e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
90e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
91e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
92e18a033bSKonstantin Ananyev};
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyev
95e18a033bSKonstantin Ananyevstatic ngx_str_t  ngx_http_slice_range_name = ngx_string("slice_range");
96e18a033bSKonstantin Ananyev
97e18a033bSKonstantin Ananyevstatic ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
98e18a033bSKonstantin Ananyevstatic ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
99e18a033bSKonstantin Ananyev
100e18a033bSKonstantin Ananyev
101e18a033bSKonstantin Ananyevstatic ngx_int_t
102e18a033bSKonstantin Ananyevngx_http_slice_header_filter(ngx_http_request_t *r)
103e18a033bSKonstantin Ananyev{
104e18a033bSKonstantin Ananyev    off_t                            end;
105e18a033bSKonstantin Ananyev    ngx_int_t                        rc;
106e18a033bSKonstantin Ananyev    ngx_table_elt_t                 *h;
107e18a033bSKonstantin Ananyev    ngx_http_slice_ctx_t            *ctx;
108e18a033bSKonstantin Ananyev    ngx_http_slice_loc_conf_t       *slcf;
109e18a033bSKonstantin Ananyev    ngx_http_slice_content_range_t   cr;
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module);
112e18a033bSKonstantin Ananyev    if (ctx == NULL) {
113e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
114e18a033bSKonstantin Ananyev    }
115e18a033bSKonstantin Ananyev
116e18a033bSKonstantin Ananyev    if (r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) {
117e18a033bSKonstantin Ananyev        if (r == r->main) {
118e18a033bSKonstantin Ananyev            ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module);
119e18a033bSKonstantin Ananyev            return ngx_http_next_header_filter(r);
120e18a033bSKonstantin Ananyev        }
121e18a033bSKonstantin Ananyev
122e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
123e18a033bSKonstantin Ananyev                      "unexpected status code %ui in slice response",
124e18a033bSKonstantin Ananyev                      r->headers_out.status);
125e18a033bSKonstantin Ananyev        return NGX_ERROR;
126e18a033bSKonstantin Ananyev    }
127e18a033bSKonstantin Ananyev
128e18a033bSKonstantin Ananyev    h = r->headers_out.etag;
129e18a033bSKonstantin Ananyev
130e18a033bSKonstantin Ananyev    if (ctx->etag.len) {
131e18a033bSKonstantin Ananyev        if (h == NULL
132e18a033bSKonstantin Ananyev            || h->value.len != ctx->etag.len
133e18a033bSKonstantin Ananyev            || ngx_strncmp(h->value.data, ctx->etag.data, ctx->etag.len)
134e18a033bSKonstantin Ananyev               != 0)
135e18a033bSKonstantin Ananyev        {
136e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
137e18a033bSKonstantin Ananyev                          "etag mismatch in slice response");
138e18a033bSKonstantin Ananyev            return NGX_ERROR;
139e18a033bSKonstantin Ananyev        }
140e18a033bSKonstantin Ananyev    }
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev    if (h) {
143e18a033bSKonstantin Ananyev        ctx->etag = h->value;
144e18a033bSKonstantin Ananyev    }
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev    if (ngx_http_slice_parse_content_range(r, &cr) != NGX_OK) {
147e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
148e18a033bSKonstantin Ananyev                      "invalid range in slice response");
149e18a033bSKonstantin Ananyev        return NGX_ERROR;
150e18a033bSKonstantin Ananyev    }
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev    if (cr.complete_length == -1) {
153e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
154e18a033bSKonstantin Ananyev                      "no complete length in slice response");
155e18a033bSKonstantin Ananyev        return NGX_ERROR;
156e18a033bSKonstantin Ananyev    }
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
159e18a033bSKonstantin Ananyev                   "http slice response range: %O-%O/%O",
160e18a033bSKonstantin Ananyev                   cr.start, cr.end, cr.complete_length);
161e18a033bSKonstantin Ananyev
162e18a033bSKonstantin Ananyev    slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module);
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev    end = ngx_min(cr.start + (off_t) slcf->size, cr.complete_length);
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev    if (cr.start != ctx->start || cr.end != end) {
167e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
168e18a033bSKonstantin Ananyev                      "unexpected range in slice response: %O-%O",
169e18a033bSKonstantin Ananyev                      cr.start, cr.end);
170e18a033bSKonstantin Ananyev        return NGX_ERROR;
171e18a033bSKonstantin Ananyev    }
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev    ctx->start = end;
174e18a033bSKonstantin Ananyev    ctx->active = 1;
175e18a033bSKonstantin Ananyev
176e18a033bSKonstantin Ananyev    r->headers_out.status = NGX_HTTP_OK;
177e18a033bSKonstantin Ananyev    r->headers_out.status_line.len = 0;
178e18a033bSKonstantin Ananyev    r->headers_out.content_length_n = cr.complete_length;
179e18a033bSKonstantin Ananyev    r->headers_out.content_offset = cr.start;
180e18a033bSKonstantin Ananyev    r->headers_out.content_range->hash = 0;
181e18a033bSKonstantin Ananyev    r->headers_out.content_range = NULL;
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    r->allow_ranges = 1;
184e18a033bSKonstantin Ananyev    r->subrequest_ranges = 1;
185e18a033bSKonstantin Ananyev    r->single_range = 1;
186e18a033bSKonstantin Ananyev
187e18a033bSKonstantin Ananyev    rc = ngx_http_next_header_filter(r);
188e18a033bSKonstantin Ananyev
189e18a033bSKonstantin Ananyev    if (r != r->main) {
190e18a033bSKonstantin Ananyev        return rc;
191e18a033bSKonstantin Ananyev    }
192e18a033bSKonstantin Ananyev
193e18a033bSKonstantin Ananyev    if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) {
194e18a033bSKonstantin Ananyev        if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) {
195e18a033bSKonstantin Ananyev            ctx->start = slcf->size
196e18a033bSKonstantin Ananyev                         * (r->headers_out.content_offset / slcf->size);
197e18a033bSKonstantin Ananyev        }
198e18a033bSKonstantin Ananyev
199e18a033bSKonstantin Ananyev        ctx->end = r->headers_out.content_offset
200e18a033bSKonstantin Ananyev                   + r->headers_out.content_length_n;
201e18a033bSKonstantin Ananyev
202e18a033bSKonstantin Ananyev    } else {
203e18a033bSKonstantin Ananyev        ctx->end = cr.complete_length;
204e18a033bSKonstantin Ananyev    }
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyev    return rc;
207e18a033bSKonstantin Ananyev}
208e18a033bSKonstantin Ananyev
209e18a033bSKonstantin Ananyev
210e18a033bSKonstantin Ananyevstatic ngx_int_t
211e18a033bSKonstantin Ananyevngx_http_slice_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
212e18a033bSKonstantin Ananyev{
213e18a033bSKonstantin Ananyev    ngx_int_t                   rc;
214e18a033bSKonstantin Ananyev    ngx_chain_t                *cl;
215e18a033bSKonstantin Ananyev    ngx_http_slice_ctx_t       *ctx;
216e18a033bSKonstantin Ananyev    ngx_http_slice_loc_conf_t  *slcf;
217e18a033bSKonstantin Ananyev
218e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module);
219e18a033bSKonstantin Ananyev
220e18a033bSKonstantin Ananyev    if (ctx == NULL || r != r->main) {
221e18a033bSKonstantin Ananyev        return ngx_http_next_body_filter(r, in);
222e18a033bSKonstantin Ananyev    }
223e18a033bSKonstantin Ananyev
224e18a033bSKonstantin Ananyev    for (cl = in; cl; cl = cl->next) {
225e18a033bSKonstantin Ananyev        if (cl->buf->last_buf) {
226e18a033bSKonstantin Ananyev            cl->buf->last_buf = 0;
227e18a033bSKonstantin Ananyev            cl->buf->last_in_chain = 1;
228e18a033bSKonstantin Ananyev            cl->buf->sync = 1;
229e18a033bSKonstantin Ananyev            ctx->last = 1;
230e18a033bSKonstantin Ananyev        }
231e18a033bSKonstantin Ananyev    }
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev    rc = ngx_http_next_body_filter(r, in);
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR || !ctx->last) {
236e18a033bSKonstantin Ananyev        return rc;
237e18a033bSKonstantin Ananyev    }
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev    if (ctx->sr && !ctx->sr->done) {
240e18a033bSKonstantin Ananyev        return rc;
241e18a033bSKonstantin Ananyev    }
242e18a033bSKonstantin Ananyev
243e18a033bSKonstantin Ananyev    if (!ctx->active) {
244e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
245e18a033bSKonstantin Ananyev                      "missing slice response");
246e18a033bSKonstantin Ananyev        return NGX_ERROR;
247e18a033bSKonstantin Ananyev    }
248e18a033bSKonstantin Ananyev
249e18a033bSKonstantin Ananyev    if (ctx->start >= ctx->end) {
250e18a033bSKonstantin Ananyev        ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module);
251e18a033bSKonstantin Ananyev        ngx_http_send_special(r, NGX_HTTP_LAST);
252e18a033bSKonstantin Ananyev        return rc;
253e18a033bSKonstantin Ananyev    }
254e18a033bSKonstantin Ananyev
255e18a033bSKonstantin Ananyev    if (r->buffered) {
256e18a033bSKonstantin Ananyev        return rc;
257e18a033bSKonstantin Ananyev    }
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev    if (ngx_http_subrequest(r, &r->uri, &r->args, &ctx->sr, NULL,
260e18a033bSKonstantin Ananyev                            NGX_HTTP_SUBREQUEST_CLONE)
261e18a033bSKonstantin Ananyev        != NGX_OK)
262e18a033bSKonstantin Ananyev    {
263e18a033bSKonstantin Ananyev        return NGX_ERROR;
264e18a033bSKonstantin Ananyev    }
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev    ngx_http_set_ctx(ctx->sr, ctx, ngx_http_slice_filter_module);
267e18a033bSKonstantin Ananyev
268e18a033bSKonstantin Ananyev    slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module);
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev    ctx->range.len = ngx_sprintf(ctx->range.data, "bytes=%O-%O", ctx->start,
271e18a033bSKonstantin Ananyev                                 ctx->start + (off_t) slcf->size - 1)
272e18a033bSKonstantin Ananyev                     - ctx->range.data;
273e18a033bSKonstantin Ananyev
274e18a033bSKonstantin Ananyev    ctx->active = 0;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
277e18a033bSKonstantin Ananyev                   "http slice subrequest: \"%V\"", &ctx->range);
278e18a033bSKonstantin Ananyev
279e18a033bSKonstantin Ananyev    return rc;
280e18a033bSKonstantin Ananyev}
281e18a033bSKonstantin Ananyev
282e18a033bSKonstantin Ananyev
283e18a033bSKonstantin Ananyevstatic ngx_int_t
284e18a033bSKonstantin Ananyevngx_http_slice_parse_content_range(ngx_http_request_t *r,
285e18a033bSKonstantin Ananyev    ngx_http_slice_content_range_t *cr)
286e18a033bSKonstantin Ananyev{
287e18a033bSKonstantin Ananyev    off_t             start, end, complete_length, cutoff, cutlim;
288e18a033bSKonstantin Ananyev    u_char           *p;
289e18a033bSKonstantin Ananyev    ngx_table_elt_t  *h;
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyev    h = r->headers_out.content_range;
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyev    if (h == NULL
294e18a033bSKonstantin Ananyev        || h->value.len < 7
295e18a033bSKonstantin Ananyev        || ngx_strncmp(h->value.data, "bytes ", 6) != 0)
296e18a033bSKonstantin Ananyev    {
297e18a033bSKonstantin Ananyev        return NGX_ERROR;
298e18a033bSKonstantin Ananyev    }
299e18a033bSKonstantin Ananyev
300e18a033bSKonstantin Ananyev    p = h->value.data + 6;
301e18a033bSKonstantin Ananyev
302e18a033bSKonstantin Ananyev    cutoff = NGX_MAX_OFF_T_VALUE / 10;
303e18a033bSKonstantin Ananyev    cutlim = NGX_MAX_OFF_T_VALUE % 10;
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev    start = 0;
306e18a033bSKonstantin Ananyev    end = 0;
307e18a033bSKonstantin Ananyev    complete_length = 0;
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev    while (*p == ' ') { p++; }
310e18a033bSKonstantin Ananyev
311e18a033bSKonstantin Ananyev    if (*p < '0' || *p > '9') {
312e18a033bSKonstantin Ananyev        return NGX_ERROR;
313e18a033bSKonstantin Ananyev    }
314e18a033bSKonstantin Ananyev
315e18a033bSKonstantin Ananyev    while (*p >= '0' && *p <= '9') {
316e18a033bSKonstantin Ananyev        if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) {
317e18a033bSKonstantin Ananyev            return NGX_ERROR;
318e18a033bSKonstantin Ananyev        }
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev        start = start * 10 + *p++ - '0';
321e18a033bSKonstantin Ananyev    }
322e18a033bSKonstantin Ananyev
323e18a033bSKonstantin Ananyev    while (*p == ' ') { p++; }
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev    if (*p++ != '-') {
326e18a033bSKonstantin Ananyev        return NGX_ERROR;
327e18a033bSKonstantin Ananyev    }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev    while (*p == ' ') { p++; }
330e18a033bSKonstantin Ananyev
331e18a033bSKonstantin Ananyev    if (*p < '0' || *p > '9') {
332e18a033bSKonstantin Ananyev        return NGX_ERROR;
333e18a033bSKonstantin Ananyev    }
334e18a033bSKonstantin Ananyev
335e18a033bSKonstantin Ananyev    while (*p >= '0' && *p <= '9') {
336e18a033bSKonstantin Ananyev        if (end >= cutoff && (end > cutoff || *p - '0' > cutlim)) {
337e18a033bSKonstantin Ananyev            return NGX_ERROR;
338e18a033bSKonstantin Ananyev        }
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev        end = end * 10 + *p++ - '0';
341e18a033bSKonstantin Ananyev    }
342e18a033bSKonstantin Ananyev
343e18a033bSKonstantin Ananyev    end++;
344e18a033bSKonstantin Ananyev
345e18a033bSKonstantin Ananyev    while (*p == ' ') { p++; }
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev    if (*p++ != '/') {
348e18a033bSKonstantin Ananyev        return NGX_ERROR;
349e18a033bSKonstantin Ananyev    }
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev    while (*p == ' ') { p++; }
352e18a033bSKonstantin Ananyev
353e18a033bSKonstantin Ananyev    if (*p != '*') {
354e18a033bSKonstantin Ananyev        if (*p < '0' || *p > '9') {
355e18a033bSKonstantin Ananyev            return NGX_ERROR;
356e18a033bSKonstantin Ananyev        }
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev        while (*p >= '0' && *p <= '9') {
359e18a033bSKonstantin Ananyev            if (complete_length >= cutoff
360e18a033bSKonstantin Ananyev                && (complete_length > cutoff || *p - '0' > cutlim))
361e18a033bSKonstantin Ananyev            {
362e18a033bSKonstantin Ananyev                return NGX_ERROR;
363e18a033bSKonstantin Ananyev            }
364e18a033bSKonstantin Ananyev
365e18a033bSKonstantin Ananyev            complete_length = complete_length * 10 + *p++ - '0';
366e18a033bSKonstantin Ananyev        }
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyev    } else {
369e18a033bSKonstantin Ananyev        complete_length = -1;
370e18a033bSKonstantin Ananyev        p++;
371e18a033bSKonstantin Ananyev    }
372e18a033bSKonstantin Ananyev
373e18a033bSKonstantin Ananyev    while (*p == ' ') { p++; }
374e18a033bSKonstantin Ananyev
375e18a033bSKonstantin Ananyev    if (*p != '\0') {
376e18a033bSKonstantin Ananyev        return NGX_ERROR;
377e18a033bSKonstantin Ananyev    }
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyev    cr->start = start;
380e18a033bSKonstantin Ananyev    cr->end = end;
381e18a033bSKonstantin Ananyev    cr->complete_length = complete_length;
382e18a033bSKonstantin Ananyev
383e18a033bSKonstantin Ananyev    return NGX_OK;
384e18a033bSKonstantin Ananyev}
385e18a033bSKonstantin Ananyev
386e18a033bSKonstantin Ananyev
387e18a033bSKonstantin Ananyevstatic ngx_int_t
388e18a033bSKonstantin Ananyevngx_http_slice_range_variable(ngx_http_request_t *r,
389e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
390e18a033bSKonstantin Ananyev{
391e18a033bSKonstantin Ananyev    u_char                     *p;
392e18a033bSKonstantin Ananyev    ngx_http_slice_ctx_t       *ctx;
393e18a033bSKonstantin Ananyev    ngx_http_slice_loc_conf_t  *slcf;
394e18a033bSKonstantin Ananyev
395e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module);
396e18a033bSKonstantin Ananyev
397e18a033bSKonstantin Ananyev    if (ctx == NULL) {
398e18a033bSKonstantin Ananyev        if (r != r->main || r->headers_out.status) {
399e18a033bSKonstantin Ananyev            v->not_found = 1;
400e18a033bSKonstantin Ananyev            return NGX_OK;
401e18a033bSKonstantin Ananyev        }
402e18a033bSKonstantin Ananyev
403e18a033bSKonstantin Ananyev        slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module);
404e18a033bSKonstantin Ananyev
405e18a033bSKonstantin Ananyev        if (slcf->size == 0) {
406e18a033bSKonstantin Ananyev            v->not_found = 1;
407e18a033bSKonstantin Ananyev            return NGX_OK;
408e18a033bSKonstantin Ananyev        }
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_slice_ctx_t));
411e18a033bSKonstantin Ananyev        if (ctx == NULL) {
412e18a033bSKonstantin Ananyev            return NGX_ERROR;
413e18a033bSKonstantin Ananyev        }
414e18a033bSKonstantin Ananyev
415e18a033bSKonstantin Ananyev        ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module);
416e18a033bSKonstantin Ananyev
417