Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_slice_filter_module.c @ 6963:3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
When a slice subrequest was redirected to a new location, its context was lost.
After its completion, a new slice subrequest for the same slice was created.
This could lead to infinite loop. Now the slice module makes sure each slice
subrequest starts output with the slice context available.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 31 Mar 2017 21:47:56 +0300 |
parents | a97ad1663ef4 |
children | e3723f2a11b7 |
rev | line source |
---|---|
6317 | 1 |
2 /* | |
3 * Copyright (C) Roman Arutyunyan | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
14 size_t size; |
6317 | 15 } ngx_http_slice_loc_conf_t; |
16 | |
17 | |
18 typedef struct { | |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
19 off_t start; |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
20 off_t end; |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
21 ngx_str_t range; |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
22 ngx_str_t etag; |
6963
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
23 unsigned last:1; |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
24 unsigned active:1; |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
25 ngx_http_request_t *sr; |
6317 | 26 } ngx_http_slice_ctx_t; |
27 | |
28 | |
29 typedef struct { | |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
30 off_t start; |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
31 off_t end; |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
32 off_t complete_length; |
6317 | 33 } ngx_http_slice_content_range_t; |
34 | |
35 | |
36 static ngx_int_t ngx_http_slice_header_filter(ngx_http_request_t *r); | |
37 static ngx_int_t ngx_http_slice_body_filter(ngx_http_request_t *r, | |
38 ngx_chain_t *in); | |
39 static ngx_int_t ngx_http_slice_parse_content_range(ngx_http_request_t *r, | |
40 ngx_http_slice_content_range_t *cr); | |
41 static ngx_int_t ngx_http_slice_range_variable(ngx_http_request_t *r, | |
42 ngx_http_variable_value_t *v, uintptr_t data); | |
43 static off_t ngx_http_slice_get_start(ngx_http_request_t *r); | |
44 static void *ngx_http_slice_create_loc_conf(ngx_conf_t *cf); | |
45 static char *ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent, | |
46 void *child); | |
47 static ngx_int_t ngx_http_slice_add_variables(ngx_conf_t *cf); | |
48 static ngx_int_t ngx_http_slice_init(ngx_conf_t *cf); | |
49 | |
50 | |
51 static ngx_command_t ngx_http_slice_filter_commands[] = { | |
52 | |
53 { ngx_string("slice"), | |
54 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
55 ngx_conf_set_size_slot, | |
56 NGX_HTTP_LOC_CONF_OFFSET, | |
57 offsetof(ngx_http_slice_loc_conf_t, size), | |
58 NULL }, | |
59 | |
60 ngx_null_command | |
61 }; | |
62 | |
63 | |
64 static ngx_http_module_t ngx_http_slice_filter_module_ctx = { | |
65 ngx_http_slice_add_variables, /* preconfiguration */ | |
66 ngx_http_slice_init, /* postconfiguration */ | |
67 | |
68 NULL, /* create main configuration */ | |
69 NULL, /* init main configuration */ | |
70 | |
71 NULL, /* create server configuration */ | |
72 NULL, /* merge server configuration */ | |
73 | |
74 ngx_http_slice_create_loc_conf, /* create location configuration */ | |
75 ngx_http_slice_merge_loc_conf /* merge location configuration */ | |
76 }; | |
77 | |
78 | |
79 ngx_module_t ngx_http_slice_filter_module = { | |
80 NGX_MODULE_V1, | |
81 &ngx_http_slice_filter_module_ctx, /* module context */ | |
82 ngx_http_slice_filter_commands, /* module directives */ | |
83 NGX_HTTP_MODULE, /* module type */ | |
84 NULL, /* init master */ | |
85 NULL, /* init module */ | |
86 NULL, /* init process */ | |
87 NULL, /* init thread */ | |
88 NULL, /* exit thread */ | |
89 NULL, /* exit process */ | |
90 NULL, /* exit master */ | |
91 NGX_MODULE_V1_PADDING | |
92 }; | |
93 | |
94 | |
95 static ngx_str_t ngx_http_slice_range_name = ngx_string("slice_range"); | |
96 | |
97 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; | |
98 static ngx_http_output_body_filter_pt ngx_http_next_body_filter; | |
99 | |
100 | |
101 static ngx_int_t | |
102 ngx_http_slice_header_filter(ngx_http_request_t *r) | |
103 { | |
104 off_t end; | |
105 ngx_int_t rc; | |
106 ngx_table_elt_t *h; | |
107 ngx_http_slice_ctx_t *ctx; | |
108 ngx_http_slice_loc_conf_t *slcf; | |
109 ngx_http_slice_content_range_t cr; | |
110 | |
111 ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); | |
112 if (ctx == NULL) { | |
113 return ngx_http_next_header_filter(r); | |
114 } | |
115 | |
116 if (r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) { | |
117 if (r == r->main) { | |
118 ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); | |
119 return ngx_http_next_header_filter(r); | |
120 } | |
121 | |
122 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
123 "unexpected status code %ui in slice response", | |
124 r->headers_out.status); | |
125 return NGX_ERROR; | |
126 } | |
127 | |
128 h = r->headers_out.etag; | |
129 | |
130 if (ctx->etag.len) { | |
131 if (h == NULL | |
132 || h->value.len != ctx->etag.len | |
133 || ngx_strncmp(h->value.data, ctx->etag.data, ctx->etag.len) | |
134 != 0) | |
135 { | |
136 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
137 "etag mismatch in slice response"); | |
138 return NGX_ERROR; | |
139 } | |
140 } | |
141 | |
142 if (h) { | |
143 ctx->etag = h->value; | |
144 } | |
145 | |
146 if (ngx_http_slice_parse_content_range(r, &cr) != NGX_OK) { | |
147 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
148 "invalid range in slice response"); | |
149 return NGX_ERROR; | |
150 } | |
151 | |
152 if (cr.complete_length == -1) { | |
153 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
154 "no complete length in slice response"); | |
155 return NGX_ERROR; | |
156 } | |
157 | |
158 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
159 "http slice response range: %O-%O/%O", | |
160 cr.start, cr.end, cr.complete_length); | |
161 | |
162 slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); | |
163 | |
164 end = ngx_min(cr.start + (off_t) slcf->size, cr.complete_length); | |
165 | |
166 if (cr.start != ctx->start || cr.end != end) { | |
167 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
168 "unexpected range in slice response: %O-%O", | |
169 cr.start, cr.end); | |
170 return NGX_ERROR; | |
171 } | |
172 | |
173 ctx->start = end; | |
6963
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
174 ctx->active = 1; |
6317 | 175 |
176 r->headers_out.status = NGX_HTTP_OK; | |
177 r->headers_out.status_line.len = 0; | |
178 r->headers_out.content_length_n = cr.complete_length; | |
179 r->headers_out.content_offset = cr.start; | |
180 r->headers_out.content_range->hash = 0; | |
181 r->headers_out.content_range = NULL; | |
182 | |
183 r->allow_ranges = 1; | |
184 r->subrequest_ranges = 1; | |
185 r->single_range = 1; | |
186 | |
187 rc = ngx_http_next_header_filter(r); | |
188 | |
189 if (r != r->main) { | |
190 return rc; | |
191 } | |
192 | |
193 if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { | |
194 if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { | |
195 ctx->start = slcf->size | |
196 * (r->headers_out.content_offset / slcf->size); | |
197 } | |
198 | |
199 ctx->end = r->headers_out.content_offset | |
200 + r->headers_out.content_length_n; | |
201 | |
202 } else { | |
203 ctx->end = cr.complete_length; | |
204 } | |
205 | |
206 return rc; | |
207 } | |
208 | |
209 | |
210 static ngx_int_t | |
211 ngx_http_slice_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
212 { | |
213 ngx_int_t rc; | |
214 ngx_chain_t *cl; | |
215 ngx_http_slice_ctx_t *ctx; | |
216 ngx_http_slice_loc_conf_t *slcf; | |
217 | |
218 ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); | |
219 | |
220 if (ctx == NULL || r != r->main) { | |
221 return ngx_http_next_body_filter(r, in); | |
222 } | |
223 | |
224 for (cl = in; cl; cl = cl->next) { | |
225 if (cl->buf->last_buf) { | |
226 cl->buf->last_buf = 0; | |
6322
4f0f4f02c98f
Slice filter: terminate first slice with last_in_chain flag.
Roman Arutyunyan <arut@nginx.com>
parents:
6321
diff
changeset
|
227 cl->buf->last_in_chain = 1; |
6317 | 228 cl->buf->sync = 1; |
229 ctx->last = 1; | |
230 } | |
231 } | |
232 | |
233 rc = ngx_http_next_body_filter(r, in); | |
234 | |
235 if (rc == NGX_ERROR || !ctx->last) { | |
236 return rc; | |
237 } | |
238 | |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
239 if (ctx->sr && !ctx->sr->done) { |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
240 return rc; |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
241 } |
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
242 |
6963
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
243 if (!ctx->active) { |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
244 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
245 "missing slice response"); |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
246 return NGX_ERROR; |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
247 } |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
248 |
6317 | 249 if (ctx->start >= ctx->end) { |
250 ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); | |
251 ngx_http_send_special(r, NGX_HTTP_LAST); | |
252 return rc; | |
253 } | |
254 | |
6321
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
255 if (r->buffered) { |
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
256 return rc; |
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
257 } |
bc9ea464e354
Slice filter: never run subrequests when main request is buffered.
Roman Arutyunyan <arut@nginx.com>
parents:
6317
diff
changeset
|
258 |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
259 if (ngx_http_subrequest(r, &r->uri, &r->args, &ctx->sr, NULL, |
6907
d16ba0ea3434
Slice filter: fetch slices in cloned subrequests.
Roman Arutyunyan <arut@nginx.com>
parents:
6322
diff
changeset
|
260 NGX_HTTP_SUBREQUEST_CLONE) |
d16ba0ea3434
Slice filter: fetch slices in cloned subrequests.
Roman Arutyunyan <arut@nginx.com>
parents:
6322
diff
changeset
|
261 != NGX_OK) |
d16ba0ea3434
Slice filter: fetch slices in cloned subrequests.
Roman Arutyunyan <arut@nginx.com>
parents:
6322
diff
changeset
|
262 { |
6317 | 263 return NGX_ERROR; |
264 } | |
265 | |
6962
a97ad1663ef4
Slice filter: allowed at most one subrequest at a time.
Roman Arutyunyan <arut@nginx.com>
parents:
6907
diff
changeset
|
266 ngx_http_set_ctx(ctx->sr, ctx, ngx_http_slice_filter_module); |
6317 | 267 |
268 slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); | |
269 | |
270 ctx->range.len = ngx_sprintf(ctx->range.data, "bytes=%O-%O", ctx->start, | |
271 ctx->start + (off_t) slcf->size - 1) | |
272 - ctx->range.data; | |
273 | |
6963
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
274 ctx->active = 0; |
3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
Roman Arutyunyan <arut@nginx.com>
parents:
6962
diff
changeset
|
275 |
6317 | 276 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
277 "http slice subrequest: \"%V\"", &ctx->range); | |
278 | |
279 return rc; | |
280 } | |
281 | |
282 | |
283 static ngx_int_t | |
284 ngx_http_slice_parse_content_range(ngx_http_request_t *r, | |
285 ngx_http_slice_content_range_t *cr) | |
286 { | |
287 off_t start, end, complete_length, cutoff, cutlim; | |
288 u_char *p; | |
289 ngx_table_elt_t *h; | |
290 | |
291 h = r->headers_out.content_range; | |
292 | |
293 if (h == NULL | |
294 || h->value.len < 7 | |
295 || ngx_strncmp(h->value.data, "bytes ", 6) != 0) | |
296 { | |
297 return NGX_ERROR; | |
298 } | |
299 | |
300 p = h->value.data + 6; | |
301 | |
302 cutoff = NGX_MAX_OFF_T_VALUE / 10; | |
303 cutlim = NGX_MAX_OFF_T_VALUE % 10; | |
304 | |
305 start = 0; | |
306 end = 0; | |
307 complete_length = 0; | |
308 | |
309 while (*p == ' ') { p++; } | |
310 | |
311 if (*p < '0' || *p > '9') { | |
312 return NGX_ERROR; | |
313 } | |
314 | |
315 while (*p >= '0' && *p <= '9') { | |
316 if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { | |
317 return NGX_ERROR; | |
318 } | |
319 | |
320 start = start * 10 + *p++ - '0'; | |
321 } | |
322 | |
323 while (*p == ' ') { p++; } | |
324 | |
325 if (*p++ != '-') { | |
326 return NGX_ERROR; | |
327 } | |
328 | |
329 while (*p == ' ') { p++; } | |
330 | |
331 if (*p < '0' || *p > '9') { | |
332 return NGX_ERROR; | |
333 } | |
334 | |
335 while (*p >= '0' && *p <= '9') { | |
336 if (end >= cutoff && (end > cutoff || *p - '0' > cutlim)) { | |
337 return NGX_ERROR; | |
338 } | |
339 | |
340 end = end * 10 + *p++ - '0'; | |
341 } | |
342 | |
343 end++; | |
344 | |
345 while (*p == ' ') { p++; } | |
346 | |
347 if (*p++ != '/') { | |
348 return NGX_ERROR; | |
349 } | |
350 | |
351 while (*p == ' ') { p++; } | |
352 | |
353 if (*p != '*') { | |
354 if (*p < '0' || *p > '9') { | |
355 return NGX_ERROR; | |
356 } | |
357 | |
358 while (*p >= '0' && *p <= '9') { | |
359 if (complete_length >= cutoff | |
360 && (complete_length > cutoff || *p - '0' > cutlim)) | |
361 { | |
362 return NGX_ERROR; | |
363 } | |
364 | |
365 complete_length = complete_length * 10 + *p++ - '0'; | |
366 } | |
367 | |
368 } else { | |
369 complete_length = -1; | |
370 p++; | |
371 } | |
372 | |
373 while (*p == ' ') { p++; } | |
374 | |
375 if (*p != '\0') { | |
376 return NGX_ERROR; | |
377 } | |
378 | |
379 cr->start = start; | |
380 cr->end = end; | |
381 cr->complete_length = complete_length; | |
382 | |
383 return NGX_OK; | |
384 } | |
385 | |
386 | |
387 static ngx_int_t | |
388 ngx_http_slice_range_variable(ngx_http_request_t *r, | |
389 ngx_http_variable_value_t *v, uintptr_t data) | |
390 { | |
391 u_char *p; | |
392 ngx_http_slice_ctx_t *ctx; | |
393 ngx_http_slice_loc_conf_t *slcf; | |
394 | |
395 ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); | |
396 | |
397 if (ctx == NULL) { | |
398 if (r != r->main || r->headers_out.status) { | |
399 v->not_found = 1; | |
400 return NGX_OK; | |
401 } | |
402 | |
403 slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); | |
404 | |
405 if (slcf->size == 0) { | |
406 v->not_found = 1; | |
407 return NGX_OK; | |
408 } | |
409 | |
410 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_slice_ctx_t)); | |
411 if (ctx == NULL) { | |
412 return NGX_ERROR; | |
413 } | |
414 | |
415 ngx_http_set_ctx(r, ctx, ngx_http_slice_filter_module); | |
416 | |
417 p = ngx_pnalloc(r->pool, sizeof("bytes=-") - 1 + 2 * NGX_OFF_T_LEN); | |
418 if (p == NULL) { | |
419 return NGX_ERROR; | |
420 } | |
421 | |
422 ctx->start = slcf->size * (ngx_http_slice_get_start(r) / slcf->size); | |
423 | |
424 ctx->range.data = p; | |
425 ctx->range.len = ngx_sprintf(p, "bytes=%O-%O", ctx->start, | |
426 ctx->start + (off_t) slcf->size - 1) | |
427 - p; | |
428 } | |
429 | |
430 v->data = ctx->range.data; | |
431 v->valid = 1; | |
432 v->not_found = 0; | |
433 v->no_cacheable = 1; | |
434 v->len = ctx->range.len; | |
435 | |
436 return NGX_OK; | |
437 } | |
438 | |
439 | |
440 static off_t | |
441 ngx_http_slice_get_start(ngx_http_request_t *r) | |
442 { | |
443 off_t start, cutoff, cutlim; | |
444 u_char *p; | |
445 ngx_table_elt_t *h; | |
446 | |
447 if (r->headers_in.if_range) { | |
448 return 0; | |
449 } | |
450 | |
451 h = r->headers_in.range; | |
452 | |
453 if (h == NULL | |
454 || h->value.len < 7 | |
455 || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0) | |
456 { | |
457 return 0; | |
458 } | |
459 | |
460 p = h->value.data + 6; | |
461 | |
462 if (ngx_strchr(p, ',')) { | |
463 return 0; | |
464 } | |
465 | |
466 while (*p == ' ') { p++; } | |
467 | |
468 if (*p == '-') { | |
469 return 0; | |
470 } | |
471 | |
472 cutoff = NGX_MAX_OFF_T_VALUE / 10; | |
473 cutlim = NGX_MAX_OFF_T_VALUE % 10; | |
474 | |
475 start = 0; | |
476 | |
477 while (*p >= '0' && *p <= '9') { | |
478 if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) { | |
479 return 0; | |
480 } | |
481 | |
482 start = start * 10 + *p++ - '0'; | |
483 } | |
484 | |
485 return start; | |
486 } | |
487 | |
488 | |
489 static void * | |
490 ngx_http_slice_create_loc_conf(ngx_conf_t *cf) | |
491 { | |
492 ngx_http_slice_loc_conf_t *slcf; | |
493 | |
494 slcf = ngx_palloc(cf->pool, sizeof(ngx_http_slice_loc_conf_t)); | |
495 if (slcf == NULL) { | |
496 return NULL; | |
497 } | |
498 | |
499 slcf->size = NGX_CONF_UNSET_SIZE; | |
500 | |
501 return slcf; | |
502 } | |
503 | |
504 | |
505 static char * | |
506 ngx_http_slice_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
507 { | |
508 ngx_http_slice_loc_conf_t *prev = parent; | |
509 ngx_http_slice_loc_conf_t *conf = child; | |
510 | |
511 ngx_conf_merge_size_value(conf->size, prev->size, 0); | |
512 | |
513 return NGX_CONF_OK; | |
514 } | |
515 | |
516 | |
517 static ngx_int_t | |
518 ngx_http_slice_add_variables(ngx_conf_t *cf) | |
519 { | |
520 ngx_http_variable_t *var; | |
521 | |
522 var = ngx_http_add_variable(cf, &ngx_http_slice_range_name, 0); | |
523 if (var == NULL) { | |
524 return NGX_ERROR; | |
525 } | |
526 | |
527 var->get_handler = ngx_http_slice_range_variable; | |
528 | |
529 return NGX_OK; | |
530 } | |
531 | |
532 | |
533 static ngx_int_t | |
534 ngx_http_slice_init(ngx_conf_t *cf) | |
535 { | |
536 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
537 ngx_http_top_header_filter = ngx_http_slice_header_filter; | |
538 | |
539 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
540 ngx_http_top_body_filter = ngx_http_slice_body_filter; | |
541 | |
542 return NGX_OK; | |
543 } |