Mercurial > hg > nginx-ranges
annotate src/http/modules/ngx_http_range_filter_module.c @ 391:1d9bef53cd8e
Range filter: late_ranges functionality.
Add one more filtering point after postpone filter. This allows to serve
range capable replies with subrequests. It's not as efficient as range
filtering for static data (i.e. doesn't save us from reading data from
disk if some filter needs them in memory), but it may save some network
bandwidth for us and for our users.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 21 Jul 2008 05:33:01 +0400 |
parents | a5f67d82aea3 |
children | 77df96611112 |
rev | line source |
---|---|
50 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 /* | |
13 * the single part format: | |
14 * | |
15 * "HTTP/1.0 206 Partial Content" CRLF | |
16 * ... header ... | |
17 * "Content-Type: image/jpeg" CRLF | |
18 * "Content-Length: SIZE" CRLF | |
19 * "Content-Range: bytes START-END/SIZE" CRLF | |
20 * CRLF | |
21 * ... data ... | |
22 * | |
23 * | |
24 * the mutlipart format: | |
25 * | |
26 * "HTTP/1.0 206 Partial Content" CRLF | |
27 * ... header ... | |
28 * "Content-Type: multipart/byteranges; boundary=0123456789" CRLF | |
29 * CRLF | |
30 * CRLF | |
31 * "--0123456789" CRLF | |
32 * "Content-Type: image/jpeg" CRLF | |
33 * "Content-Range: bytes START0-END0/SIZE" CRLF | |
34 * CRLF | |
35 * ... data ... | |
36 * CRLF | |
37 * "--0123456789" CRLF | |
38 * "Content-Type: image/jpeg" CRLF | |
39 * "Content-Range: bytes START1-END1/SIZE" CRLF | |
40 * CRLF | |
41 * ... data ... | |
42 * CRLF | |
43 * "--0123456789--" CRLF | |
44 */ | |
45 | |
46 | |
47 typedef struct { | |
272 | 48 off_t start; |
49 off_t end; | |
50 ngx_str_t content_range; | |
51 } ngx_http_range_t; | |
52 | |
53 | |
54 typedef struct { | |
55 off_t offset; | |
56 ngx_str_t boundary_header; | |
57 ngx_array_t ranges; | |
50 | 58 } ngx_http_range_filter_ctx_t; |
59 | |
60 | |
230 | 61 static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); |
62 static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); | |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
63 static ngx_int_t ngx_http_range_late_filter_init(ngx_conf_t *cf); |
50 | 64 |
65 | |
66 static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { | |
58 | 67 NULL, /* preconfiguration */ |
230 | 68 ngx_http_range_header_filter_init, /* postconfiguration */ |
50 | 69 |
70 NULL, /* create main configuration */ | |
71 NULL, /* init main configuration */ | |
72 | |
73 NULL, /* create server configuration */ | |
74 NULL, /* merge server configuration */ | |
75 | |
76 NULL, /* create location configuration */ | |
77 NULL, /* merge location configuration */ | |
78 }; | |
79 | |
80 | |
81 ngx_module_t ngx_http_range_header_filter_module = { | |
58 | 82 NGX_MODULE_V1, |
50 | 83 &ngx_http_range_header_filter_module_ctx, /* module context */ |
84 NULL, /* module directives */ | |
85 NGX_HTTP_MODULE, /* module type */ | |
90 | 86 NULL, /* init master */ |
230 | 87 NULL, /* init module */ |
90 | 88 NULL, /* init process */ |
89 NULL, /* init thread */ | |
90 NULL, /* exit thread */ | |
91 NULL, /* exit process */ | |
92 NULL, /* exit master */ | |
93 NGX_MODULE_V1_PADDING | |
50 | 94 }; |
95 | |
96 | |
97 static ngx_http_module_t ngx_http_range_body_filter_module_ctx = { | |
58 | 98 NULL, /* preconfiguration */ |
230 | 99 ngx_http_range_body_filter_init, /* postconfiguration */ |
50 | 100 |
101 NULL, /* create main configuration */ | |
102 NULL, /* init main configuration */ | |
103 | |
104 NULL, /* create server configuration */ | |
105 NULL, /* merge server configuration */ | |
106 | |
107 NULL, /* create location configuration */ | |
108 NULL, /* merge location configuration */ | |
109 }; | |
110 | |
111 | |
112 ngx_module_t ngx_http_range_body_filter_module = { | |
58 | 113 NGX_MODULE_V1, |
50 | 114 &ngx_http_range_body_filter_module_ctx, /* module context */ |
115 NULL, /* module directives */ | |
116 NGX_HTTP_MODULE, /* module type */ | |
90 | 117 NULL, /* init master */ |
230 | 118 NULL, /* init module */ |
90 | 119 NULL, /* init process */ |
120 NULL, /* init thread */ | |
121 NULL, /* exit thread */ | |
122 NULL, /* exit process */ | |
123 NULL, /* exit master */ | |
124 NGX_MODULE_V1_PADDING | |
50 | 125 }; |
126 | |
127 | |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
128 static ngx_http_module_t ngx_http_range_late_filter_module_ctx = { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
129 NULL, /* preconfiguration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
130 ngx_http_range_late_filter_init, /* postconfiguration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
131 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
132 NULL, /* create main configuration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
133 NULL, /* init main configuration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
134 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
135 NULL, /* create server configuration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
136 NULL, /* merge server configuration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
137 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
138 NULL, /* create location configuration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
139 NULL, /* merge location configuration */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
140 }; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
141 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
142 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
143 ngx_module_t ngx_http_range_late_filter_module = { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
144 NGX_MODULE_V1, |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
145 &ngx_http_range_late_filter_module_ctx, /* module context */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
146 NULL, /* module directives */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
147 NGX_HTTP_MODULE, /* module type */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
148 NULL, /* init master */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
149 NULL, /* init module */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
150 NULL, /* init process */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
151 NULL, /* init thread */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
152 NULL, /* exit thread */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
153 NULL, /* exit process */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
154 NULL, /* exit master */ |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
155 NGX_MODULE_V1_PADDING |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
156 }; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
157 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
158 |
50 | 159 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
160 static ngx_http_output_body_filter_pt ngx_http_next_body_early_filter; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
161 static ngx_http_output_body_filter_pt ngx_http_next_body_late_filter; |
50 | 162 |
163 | |
164 static ngx_int_t | |
165 ngx_http_range_header_filter(ngx_http_request_t *r) | |
166 { | |
167 u_char *p; | |
168 size_t len; | |
169 off_t start, end; | |
346 | 170 time_t if_range; |
50 | 171 ngx_int_t rc; |
172 ngx_uint_t suffix, i; | |
173 ngx_atomic_uint_t boundary; | |
174 ngx_table_elt_t *content_range; | |
175 ngx_http_range_t *range; | |
176 ngx_http_range_filter_ctx_t *ctx; | |
177 | |
178 if (r->http_version < NGX_HTTP_VERSION_10 | |
179 || r->headers_out.status != NGX_HTTP_OK | |
146 | 180 || r != r->main |
50 | 181 || r->headers_out.content_length_n == -1 |
130 | 182 || !r->allow_ranges) |
50 | 183 { |
184 return ngx_http_next_header_filter(r); | |
185 } | |
186 | |
187 if (r->headers_in.range == NULL | |
188 || r->headers_in.range->value.len < 7 | |
286 | 189 || ngx_strncasecmp(r->headers_in.range->value.data, |
190 (u_char *) "bytes=", 6) | |
191 != 0) | |
50 | 192 { |
346 | 193 goto next_filter; |
194 } | |
195 | |
196 if (r->headers_in.if_range && r->headers_out.last_modified_time != -1) { | |
197 | |
198 if_range = ngx_http_parse_time(r->headers_in.if_range->value.data, | |
199 r->headers_in.if_range->value.len); | |
50 | 200 |
346 | 201 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
202 "http ir:%d lm:%d", | |
203 if_range, r->headers_out.last_modified_time); | |
50 | 204 |
346 | 205 if (if_range != r->headers_out.last_modified_time) { |
206 goto next_filter; | |
207 } | |
50 | 208 } |
209 | |
272 | 210 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t)); |
211 if (ctx == NULL) { | |
212 return NGX_ERROR; | |
213 } | |
214 | |
215 if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t)) | |
216 == NGX_ERROR) | |
50 | 217 { |
218 return NGX_ERROR; | |
219 } | |
220 | |
221 rc = 0; | |
222 range = NULL; | |
223 p = r->headers_in.range->value.data + 6; | |
224 | |
225 for ( ;; ) { | |
226 start = 0; | |
227 end = 0; | |
228 suffix = 0; | |
229 | |
230 while (*p == ' ') { p++; } | |
231 | |
232 if (*p != '-') { | |
233 if (*p < '0' || *p > '9') { | |
234 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
235 break; | |
236 } | |
237 | |
238 while (*p >= '0' && *p <= '9') { | |
239 start = start * 10 + *p++ - '0'; | |
240 } | |
241 | |
242 while (*p == ' ') { p++; } | |
243 | |
244 if (*p++ != '-') { | |
245 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
246 break; | |
247 } | |
248 | |
249 if (start >= r->headers_out.content_length_n) { | |
250 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
251 break; | |
252 } | |
253 | |
254 while (*p == ' ') { p++; } | |
255 | |
256 if (*p == ',' || *p == '\0') { | |
272 | 257 range = ngx_array_push(&ctx->ranges); |
50 | 258 if (range == NULL) { |
259 return NGX_ERROR; | |
260 } | |
261 | |
262 range->start = start; | |
263 range->end = r->headers_out.content_length_n; | |
264 | |
265 if (*p++ != ',') { | |
266 break; | |
267 } | |
268 | |
269 continue; | |
270 } | |
271 | |
272 } else { | |
273 suffix = 1; | |
274 p++; | |
275 } | |
276 | |
277 if (*p < '0' || *p > '9') { | |
278 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
279 break; | |
280 } | |
281 | |
282 while (*p >= '0' && *p <= '9') { | |
283 end = end * 10 + *p++ - '0'; | |
284 } | |
285 | |
286 while (*p == ' ') { p++; } | |
287 | |
288 if (*p != ',' && *p != '\0') { | |
289 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
290 break; | |
291 } | |
292 | |
293 if (suffix) { | |
294 start = r->headers_out.content_length_n - end; | |
295 end = r->headers_out.content_length_n - 1; | |
296 } | |
297 | |
298 if (start > end) { | |
299 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
300 break; | |
301 } | |
302 | |
272 | 303 range = ngx_array_push(&ctx->ranges); |
50 | 304 if (range == NULL) { |
305 return NGX_ERROR; | |
306 } | |
307 | |
308 range->start = start; | |
309 | |
310 if (end >= r->headers_out.content_length_n) { | |
311 /* | |
312 * Download Accelerator sends the last byte position | |
313 * that equals to the file length | |
314 */ | |
315 range->end = r->headers_out.content_length_n; | |
316 | |
317 } else { | |
318 range->end = end + 1; | |
319 } | |
320 | |
321 if (*p++ != ',') { | |
322 break; | |
323 } | |
324 } | |
325 | |
326 if (rc) { | |
327 | |
328 /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ | |
329 | |
330 r->headers_out.status = rc; | |
331 | |
332 content_range = ngx_list_push(&r->headers_out.headers); | |
333 if (content_range == NULL) { | |
334 return NGX_ERROR; | |
335 } | |
336 | |
337 r->headers_out.content_range = content_range; | |
338 | |
58 | 339 content_range->hash = 1; |
50 | 340 content_range->key.len = sizeof("Content-Range") - 1; |
341 content_range->key.data = (u_char *) "Content-Range"; | |
342 | |
382 | 343 content_range->value.data = ngx_pnalloc(r->pool, |
50 | 344 sizeof("bytes */") - 1 + NGX_OFF_T_LEN); |
345 if (content_range->value.data == NULL) { | |
346 return NGX_ERROR; | |
347 } | |
348 | |
349 content_range->value.len = ngx_sprintf(content_range->value.data, | |
350 "bytes */%O", | |
351 r->headers_out.content_length_n) | |
352 - content_range->value.data; | |
353 | |
126 | 354 ngx_http_clear_content_length(r); |
50 | 355 |
356 return rc; | |
357 } | |
358 | |
272 | 359 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); |
360 | |
50 | 361 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; |
362 | |
272 | 363 if (ctx->ranges.nelts == 1) { |
50 | 364 |
365 content_range = ngx_list_push(&r->headers_out.headers); | |
366 if (content_range == NULL) { | |
367 return NGX_ERROR; | |
368 } | |
369 | |
370 r->headers_out.content_range = content_range; | |
371 | |
58 | 372 content_range->hash = 1; |
50 | 373 content_range->key.len = sizeof("Content-Range") - 1; |
374 content_range->key.data = (u_char *) "Content-Range"; | |
375 | |
376 content_range->value.data = | |
382 | 377 ngx_pnalloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); |
50 | 378 if (content_range->value.data == NULL) { |
379 return NGX_ERROR; | |
380 } | |
381 | |
382 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ | |
383 | |
384 content_range->value.len = ngx_sprintf(content_range->value.data, | |
385 "bytes %O-%O/%O", | |
386 range->start, range->end - 1, | |
387 r->headers_out.content_length_n) | |
388 - content_range->value.data; | |
389 | |
390 r->headers_out.content_length_n = range->end - range->start; | |
391 | |
272 | 392 if (r->headers_out.content_length) { |
393 r->headers_out.content_length->hash = 0; | |
394 r->headers_out.content_length = NULL; | |
395 } | |
396 | |
50 | 397 return ngx_http_next_header_filter(r); |
398 } | |
399 | |
400 | |
401 /* TODO: what if no content_type ?? */ | |
402 | |
403 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN | |
404 + sizeof(CRLF "Content-Type: ") - 1 | |
58 | 405 + r->headers_out.content_type.len |
50 | 406 + sizeof(CRLF "Content-Range: bytes ") - 1; |
407 | |
408 if (r->headers_out.charset.len) { | |
409 len += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
410 } | |
411 | |
382 | 412 ctx->boundary_header.data = ngx_pnalloc(r->pool, len); |
50 | 413 if (ctx->boundary_header.data == NULL) { |
414 return NGX_ERROR; | |
415 } | |
416 | |
417 boundary = ngx_next_temp_number(0); | |
418 | |
419 /* | |
420 * The boundary header of the range: | |
421 * CRLF | |
422 * "--0123456789" CRLF | |
423 * "Content-Type: image/jpeg" CRLF | |
424 * "Content-Range: bytes " | |
425 */ | |
426 | |
427 if (r->headers_out.charset.len) { | |
428 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, | |
429 CRLF "--%0muA" CRLF | |
430 "Content-Type: %V; charset=%V" CRLF | |
431 "Content-Range: bytes ", | |
432 boundary, | |
58 | 433 &r->headers_out.content_type, |
50 | 434 &r->headers_out.charset) |
435 - ctx->boundary_header.data; | |
436 | |
437 r->headers_out.charset.len = 0; | |
438 | |
439 } else { | |
440 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, | |
441 CRLF "--%0muA" CRLF | |
442 "Content-Type: %V" CRLF | |
443 "Content-Range: bytes ", | |
444 boundary, | |
58 | 445 &r->headers_out.content_type) |
50 | 446 - ctx->boundary_header.data; |
447 } | |
448 | |
58 | 449 r->headers_out.content_type.data = |
382 | 450 ngx_pnalloc(r->pool, |
451 sizeof("Content-Type: multipart/byteranges; boundary=") - 1 | |
452 + NGX_ATOMIC_T_LEN); | |
50 | 453 |
58 | 454 if (r->headers_out.content_type.data == NULL) { |
50 | 455 return NGX_ERROR; |
456 } | |
457 | |
458 /* "Content-Type: multipart/byteranges; boundary=0123456789" */ | |
459 | |
58 | 460 r->headers_out.content_type.len = |
461 ngx_sprintf(r->headers_out.content_type.data, | |
50 | 462 "multipart/byteranges; boundary=%0muA", |
463 boundary) | |
58 | 464 - r->headers_out.content_type.data; |
50 | 465 |
466 | |
467 /* the size of the last boundary CRLF "--0123456789--" CRLF */ | |
468 | |
469 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1; | |
470 | |
272 | 471 range = ctx->ranges.elts; |
472 for (i = 0; i < ctx->ranges.nelts; i++) { | |
50 | 473 |
474 /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */ | |
475 | |
476 range[i].content_range.data = | |
382 | 477 ngx_pnalloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4); |
50 | 478 |
479 if (range[i].content_range.data == NULL) { | |
480 return NGX_ERROR; | |
481 } | |
482 | |
483 range[i].content_range.len = ngx_sprintf(range[i].content_range.data, | |
484 "%O-%O/%O" CRLF CRLF, | |
485 range[i].start, range[i].end - 1, | |
486 r->headers_out.content_length_n) | |
487 - range[i].content_range.data; | |
488 | |
489 len += ctx->boundary_header.len + range[i].content_range.len | |
490 + (size_t) (range[i].end - range[i].start); | |
491 } | |
492 | |
493 r->headers_out.content_length_n = len; | |
272 | 494 |
495 if (r->headers_out.content_length) { | |
496 r->headers_out.content_length->hash = 0; | |
497 r->headers_out.content_length = NULL; | |
498 } | |
50 | 499 |
500 return ngx_http_next_header_filter(r); | |
346 | 501 |
502 next_filter: | |
503 | |
504 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); | |
505 if (r->headers_out.accept_ranges == NULL) { | |
506 return NGX_ERROR; | |
507 } | |
508 | |
509 r->headers_out.accept_ranges->hash = 1; | |
510 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; | |
511 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; | |
512 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; | |
513 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; | |
514 | |
515 return ngx_http_next_header_filter(r); | |
50 | 516 } |
517 | |
518 | |
519 static ngx_int_t | |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
520 ngx_http_range_body_generic_filter(ngx_http_request_t *r, ngx_chain_t *in, |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
521 ngx_http_output_body_filter_pt ngx_http_next_body_filter) |
50 | 522 { |
272 | 523 off_t start, last; |
524 ngx_buf_t *b, *buf; | |
50 | 525 ngx_uint_t i; |
390
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
526 ngx_chain_t *out, *cl, *hcl, *rcl, *dcl, **ll; |
50 | 527 ngx_http_range_t *range; |
528 ngx_http_range_filter_ctx_t *ctx; | |
529 | |
272 | 530 if (in == NULL) { |
531 return ngx_http_next_body_filter(r, in); | |
532 } | |
533 | |
534 ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); | |
535 | |
536 if (ctx == NULL) { | |
537 return ngx_http_next_body_filter(r, in); | |
538 } | |
539 | |
540 buf = in->buf; | |
541 | |
542 if (ngx_buf_special(in->buf)) { | |
50 | 543 return ngx_http_next_body_filter(r, in); |
544 } | |
545 | |
390
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
546 range = ctx->ranges.elts; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
547 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
548 if (ctx->ranges.nelts > 1) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
549 goto multipart; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
550 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
551 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
552 /* |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
553 * the optimized version for the responses |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
554 * that are passed in the single buffer |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
555 */ |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
556 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
557 out = NULL; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
558 ll = &out; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
559 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
560 for (cl = in; cl; cl = cl->next) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
561 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
562 buf = cl->buf; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
563 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
564 start = ctx->offset; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
565 last = ctx->offset + ngx_buf_size(buf); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
566 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
567 ctx->offset = last; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
568 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
569 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
570 "range body filter: %O-%O", start, last); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
571 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
572 if (ngx_buf_special(buf)) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
573 /* pass anyway */ |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
574 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
575 "range body filter: pass special"); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
576 *ll = cl; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
577 ll = &cl->next; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
578 continue; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
579 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
580 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
581 if (range->end <= start || range->start >= last) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
582 /* skip buffer */ |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
583 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
584 "range body filter: skip"); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
585 buf->pos = buf->last; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
586 continue; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
587 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
588 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
589 if (range->start > start) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
590 if (buf->in_file) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
591 buf->file_pos += range->start - start; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
592 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
593 if (ngx_buf_in_memory(buf)) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
594 buf->pos += (size_t) (range->start - start); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
595 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
596 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
597 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
598 if (range->end <= last) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
599 if (buf->in_file) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
600 buf->file_last -= last - range->end; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
601 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
602 if (ngx_buf_in_memory(buf)) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
603 buf->last -= (size_t) (last - range->end); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
604 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
605 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
606 /* we are done */ |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
607 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
608 buf->last_buf = 1; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
609 *ll = cl; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
610 cl->next = NULL; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
611 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
612 break; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
613 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
614 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
615 *ll = cl; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
616 ll = &cl->next; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
617 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
618 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
619 if (out == NULL) { |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
620 return NGX_OK; |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
621 } |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
622 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
623 return ngx_http_next_body_filter(r, out); |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
624 |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
625 multipart: |
a5f67d82aea3
Range filter: support for multiple buffers (single range only).
Maxim Dounin <mdounin@mdounin.ru>
parents:
382
diff
changeset
|
626 |
272 | 627 if (ctx->offset) { |
628 goto overlapped; | |
629 } | |
630 | |
631 if (!buf->last_buf) { | |
632 | |
633 if (buf->in_file) { | |
634 start = buf->file_pos + ctx->offset; | |
635 last = buf->file_last + ctx->offset; | |
636 | |
637 } else { | |
638 start = buf->pos - buf->start + ctx->offset; | |
639 last = buf->last - buf->start + ctx->offset; | |
640 } | |
641 | |
642 for (i = 0; i < ctx->ranges.nelts; i++) { | |
643 if (start > range[i].start || last < range[i].end) { | |
644 goto overlapped; | |
645 } | |
646 } | |
647 } | |
648 | |
649 ctx->offset = ngx_buf_size(buf); | |
650 | |
651 ll = &out; | |
652 | |
653 for (i = 0; i < ctx->ranges.nelts; i++) { | |
50 | 654 |
272 | 655 /* |
656 * The boundary header of the range: | |
657 * CRLF | |
658 * "--0123456789" CRLF | |
659 * "Content-Type: image/jpeg" CRLF | |
660 * "Content-Range: bytes " | |
661 */ | |
50 | 662 |
272 | 663 b = ngx_calloc_buf(r->pool); |
664 if (b == NULL) { | |
665 return NGX_ERROR; | |
666 } | |
50 | 667 |
272 | 668 b->memory = 1; |
669 b->pos = ctx->boundary_header.data; | |
670 b->last = ctx->boundary_header.data + ctx->boundary_header.len; | |
50 | 671 |
272 | 672 hcl = ngx_alloc_chain_link(r->pool); |
673 if (hcl == NULL) { | |
674 return NGX_ERROR; | |
675 } | |
50 | 676 |
272 | 677 hcl->buf = b; |
50 | 678 |
679 | |
272 | 680 /* "SSSS-EEEE/TTTT" CRLF CRLF */ |
50 | 681 |
682 b = ngx_calloc_buf(r->pool); | |
683 if (b == NULL) { | |
684 return NGX_ERROR; | |
685 } | |
686 | |
687 b->temporary = 1; | |
272 | 688 b->pos = range[i].content_range.data; |
689 b->last = range[i].content_range.data + range[i].content_range.len; | |
690 | |
691 rcl = ngx_alloc_chain_link(r->pool); | |
692 if (rcl == NULL) { | |
693 return NGX_ERROR; | |
694 } | |
695 | |
696 rcl->buf = b; | |
697 | |
698 | |
699 /* the range data */ | |
700 | |
701 b = ngx_calloc_buf(r->pool); | |
702 if (b == NULL) { | |
703 return NGX_ERROR; | |
704 } | |
50 | 705 |
272 | 706 b->in_file = buf->in_file; |
707 b->temporary = buf->temporary; | |
708 b->memory = buf->memory; | |
709 b->mmap = buf->mmap; | |
710 b->file = buf->file; | |
711 | |
712 if (buf->in_file) { | |
282 | 713 b->file_pos = range[i].start; |
714 b->file_last = range[i].end; | |
272 | 715 } |
716 | |
717 if (ngx_buf_in_memory(buf)) { | |
282 | 718 b->pos = buf->start + (size_t) range[i].start; |
719 b->last = buf->start + (size_t) range[i].end; | |
272 | 720 } |
721 | |
722 dcl = ngx_alloc_chain_link(r->pool); | |
723 if (dcl == NULL) { | |
50 | 724 return NGX_ERROR; |
725 } | |
726 | |
272 | 727 dcl->buf = b; |
50 | 728 |
729 *ll = hcl; | |
272 | 730 hcl->next = rcl; |
731 rcl->next = dcl; | |
732 ll = &dcl->next; | |
733 } | |
50 | 734 |
272 | 735 /* the last boundary CRLF "--0123456789--" CRLF */ |
736 | |
737 b = ngx_calloc_buf(r->pool); | |
738 if (b == NULL) { | |
739 return NGX_ERROR; | |
740 } | |
741 | |
742 b->temporary = 1; | |
743 b->last_buf = 1; | |
744 | |
382 | 745 b->pos = ngx_pnalloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN |
746 + sizeof("--" CRLF) - 1); | |
272 | 747 if (b->pos == NULL) { |
748 return NGX_ERROR; | |
50 | 749 } |
750 | |
300 | 751 b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, |
752 sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN); | |
272 | 753 *b->last++ = '-'; *b->last++ = '-'; |
754 *b->last++ = CR; *b->last++ = LF; | |
755 | |
756 hcl = ngx_alloc_chain_link(r->pool); | |
757 if (hcl == NULL) { | |
758 return NGX_ERROR; | |
759 } | |
50 | 760 |
272 | 761 hcl->buf = b; |
762 hcl->next = NULL; | |
763 | |
764 *ll = hcl; | |
765 | |
766 return ngx_http_next_body_filter(r, out); | |
767 | |
768 overlapped: | |
769 | |
770 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
771 "range in overlapped buffers"); | |
772 | |
773 return NGX_ERROR; | |
50 | 774 } |
775 | |
776 | |
777 static ngx_int_t | |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
778 ngx_http_range_body_early_filter(ngx_http_request_t *r, ngx_chain_t *in) |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
779 { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
780 if (!r->allow_ranges || r->late_ranges) { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
781 return ngx_http_next_body_early_filter(r, in); |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
782 } |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
783 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
784 return ngx_http_range_body_generic_filter(r, in, |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
785 ngx_http_next_body_early_filter); |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
786 } |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
787 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
788 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
789 static ngx_int_t |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
790 ngx_http_range_body_late_filter(ngx_http_request_t *r, ngx_chain_t *in) |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
791 { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
792 if (!r->allow_ranges || !r->late_ranges) { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
793 return ngx_http_next_body_late_filter(r, in); |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
794 } |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
795 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
796 return ngx_http_range_body_generic_filter(r, in, |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
797 ngx_http_next_body_late_filter); |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
798 } |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
799 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
800 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
801 static ngx_int_t |
230 | 802 ngx_http_range_header_filter_init(ngx_conf_t *cf) |
50 | 803 { |
804 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
805 ngx_http_top_header_filter = ngx_http_range_header_filter; | |
806 | |
807 return NGX_OK; | |
808 } | |
809 | |
810 | |
811 static ngx_int_t | |
230 | 812 ngx_http_range_body_filter_init(ngx_conf_t *cf) |
50 | 813 { |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
814 ngx_http_next_body_early_filter = ngx_http_top_body_filter; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
815 ngx_http_top_body_filter = ngx_http_range_body_early_filter; |
50 | 816 |
817 return NGX_OK; | |
818 } | |
391
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
819 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
820 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
821 static ngx_int_t |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
822 ngx_http_range_late_filter_init(ngx_conf_t *cf) |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
823 { |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
824 ngx_http_next_body_late_filter = ngx_http_top_body_filter; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
825 ngx_http_top_body_filter = ngx_http_range_body_late_filter; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
826 |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
827 return NGX_OK; |
1d9bef53cd8e
Range filter: late_ranges functionality.
Maxim Dounin <mdounin@mdounin.ru>
parents:
390
diff
changeset
|
828 } |