Mercurial > hg > nginx
comparison src/http/modules/ngx_http_range_filter_module.c @ 2118:c1f589732d8c
split ngx_http_range_filter_module
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Wed, 23 Jul 2008 16:18:37 +0000 |
parents | 2a92804f4109 |
children | 0799703985ef |
comparison
equal
deleted
inserted
replaced
2117:9d62abd76ea5 | 2118:c1f589732d8c |
---|---|
56 ngx_str_t boundary_header; | 56 ngx_str_t boundary_header; |
57 ngx_array_t ranges; | 57 ngx_array_t ranges; |
58 } ngx_http_range_filter_ctx_t; | 58 } ngx_http_range_filter_ctx_t; |
59 | 59 |
60 | 60 |
61 ngx_int_t ngx_http_range_parse(ngx_http_request_t *r, | |
62 ngx_http_range_filter_ctx_t *ctx); | |
63 static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r, | |
64 ngx_http_range_filter_ctx_t *ctx); | |
65 static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r, | |
66 ngx_http_range_filter_ctx_t *ctx); | |
67 static ngx_int_t ngx_http_range_test_overlapped(ngx_http_request_t *r, | |
68 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); | |
69 static ngx_int_t ngx_http_range_singlepart_body(ngx_http_request_t *r, | |
70 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); | |
71 static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, | |
72 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); | |
73 static ngx_int_t ngx_http_range_not_satisfiable(ngx_http_request_t *r); | |
74 | |
61 static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); | 75 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); | 76 static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); |
63 | 77 |
64 | 78 |
65 static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { | 79 static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { |
129 | 143 |
130 | 144 |
131 static ngx_int_t | 145 static ngx_int_t |
132 ngx_http_range_header_filter(ngx_http_request_t *r) | 146 ngx_http_range_header_filter(ngx_http_request_t *r) |
133 { | 147 { |
134 u_char *p; | |
135 size_t len; | |
136 off_t start, end; | |
137 time_t if_range; | 148 time_t if_range; |
138 ngx_int_t rc; | 149 ngx_int_t rc; |
139 ngx_uint_t suffix, i; | |
140 ngx_atomic_uint_t boundary; | |
141 ngx_table_elt_t *content_range; | |
142 ngx_http_range_t *range; | |
143 ngx_http_range_filter_ctx_t *ctx; | 150 ngx_http_range_filter_ctx_t *ctx; |
144 | 151 |
145 if (r->http_version < NGX_HTTP_VERSION_10 | 152 if (r->http_version < NGX_HTTP_VERSION_10 |
146 || r->headers_out.status != NGX_HTTP_OK | 153 || r->headers_out.status != NGX_HTTP_OK |
147 || r != r->main | 154 || r != r->main |
183 == NGX_ERROR) | 190 == NGX_ERROR) |
184 { | 191 { |
185 return NGX_ERROR; | 192 return NGX_ERROR; |
186 } | 193 } |
187 | 194 |
188 rc = 0; | 195 rc = ngx_http_range_parse(r, ctx); |
189 range = NULL; | 196 |
197 if (rc == NGX_OK) { | |
198 | |
199 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); | |
200 | |
201 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; | |
202 | |
203 if (ctx->ranges.nelts == 1) { | |
204 return ngx_http_range_singlepart_header(r, ctx); | |
205 } | |
206 | |
207 return ngx_http_range_multipart_header(r, ctx); | |
208 } | |
209 | |
210 if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) { | |
211 return ngx_http_range_not_satisfiable(r); | |
212 } | |
213 | |
214 /* rc == NGX_ERROR */ | |
215 | |
216 return rc; | |
217 | |
218 next_filter: | |
219 | |
220 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); | |
221 if (r->headers_out.accept_ranges == NULL) { | |
222 return NGX_ERROR; | |
223 } | |
224 | |
225 r->headers_out.accept_ranges->hash = 1; | |
226 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; | |
227 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; | |
228 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; | |
229 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; | |
230 | |
231 return ngx_http_next_header_filter(r); | |
232 } | |
233 | |
234 | |
235 ngx_int_t | |
236 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) | |
237 { | |
238 u_char *p; | |
239 off_t start, end; | |
240 ngx_uint_t suffix; | |
241 ngx_http_range_t *range; | |
242 | |
190 p = r->headers_in.range->value.data + 6; | 243 p = r->headers_in.range->value.data + 6; |
191 | 244 |
192 for ( ;; ) { | 245 for ( ;; ) { |
193 start = 0; | 246 start = 0; |
194 end = 0; | 247 end = 0; |
196 | 249 |
197 while (*p == ' ') { p++; } | 250 while (*p == ' ') { p++; } |
198 | 251 |
199 if (*p != '-') { | 252 if (*p != '-') { |
200 if (*p < '0' || *p > '9') { | 253 if (*p < '0' || *p > '9') { |
201 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 254 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
202 break; | |
203 } | 255 } |
204 | 256 |
205 while (*p >= '0' && *p <= '9') { | 257 while (*p >= '0' && *p <= '9') { |
206 start = start * 10 + *p++ - '0'; | 258 start = start * 10 + *p++ - '0'; |
207 } | 259 } |
208 | 260 |
209 while (*p == ' ') { p++; } | 261 while (*p == ' ') { p++; } |
210 | 262 |
211 if (*p++ != '-') { | 263 if (*p++ != '-') { |
212 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 264 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
213 break; | |
214 } | 265 } |
215 | 266 |
216 if (start >= r->headers_out.content_length_n) { | 267 if (start >= r->headers_out.content_length_n) { |
217 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 268 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
218 break; | |
219 } | 269 } |
220 | 270 |
221 while (*p == ' ') { p++; } | 271 while (*p == ' ') { p++; } |
222 | 272 |
223 if (*p == ',' || *p == '\0') { | 273 if (*p == ',' || *p == '\0') { |
228 | 278 |
229 range->start = start; | 279 range->start = start; |
230 range->end = r->headers_out.content_length_n; | 280 range->end = r->headers_out.content_length_n; |
231 | 281 |
232 if (*p++ != ',') { | 282 if (*p++ != ',') { |
233 break; | 283 return NGX_OK; |
234 } | 284 } |
235 | 285 |
236 continue; | 286 continue; |
237 } | 287 } |
238 | 288 |
240 suffix = 1; | 290 suffix = 1; |
241 p++; | 291 p++; |
242 } | 292 } |
243 | 293 |
244 if (*p < '0' || *p > '9') { | 294 if (*p < '0' || *p > '9') { |
245 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 295 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
246 break; | |
247 } | 296 } |
248 | 297 |
249 while (*p >= '0' && *p <= '9') { | 298 while (*p >= '0' && *p <= '9') { |
250 end = end * 10 + *p++ - '0'; | 299 end = end * 10 + *p++ - '0'; |
251 } | 300 } |
252 | 301 |
253 while (*p == ' ') { p++; } | 302 while (*p == ' ') { p++; } |
254 | 303 |
255 if (*p != ',' && *p != '\0') { | 304 if (*p != ',' && *p != '\0') { |
256 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 305 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
257 break; | |
258 } | 306 } |
259 | 307 |
260 if (suffix) { | 308 if (suffix) { |
261 start = r->headers_out.content_length_n - end; | 309 start = r->headers_out.content_length_n - end; |
262 end = r->headers_out.content_length_n - 1; | 310 end = r->headers_out.content_length_n - 1; |
263 } | 311 } |
264 | 312 |
265 if (start > end) { | 313 if (start > end) { |
266 rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; | 314 return NGX_HTTP_RANGE_NOT_SATISFIABLE; |
267 break; | |
268 } | 315 } |
269 | 316 |
270 range = ngx_array_push(&ctx->ranges); | 317 range = ngx_array_push(&ctx->ranges); |
271 if (range == NULL) { | 318 if (range == NULL) { |
272 return NGX_ERROR; | 319 return NGX_ERROR; |
284 } else { | 331 } else { |
285 range->end = end + 1; | 332 range->end = end + 1; |
286 } | 333 } |
287 | 334 |
288 if (*p++ != ',') { | 335 if (*p++ != ',') { |
289 break; | 336 return NGX_OK; |
290 } | 337 } |
291 } | 338 } |
292 | 339 } |
293 if (rc) { | 340 |
294 | 341 |
295 /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ | 342 static ngx_int_t |
296 | 343 ngx_http_range_singlepart_header(ngx_http_request_t *r, |
297 r->headers_out.status = rc; | 344 ngx_http_range_filter_ctx_t *ctx) |
298 | 345 { |
299 content_range = ngx_list_push(&r->headers_out.headers); | 346 ngx_table_elt_t *content_range; |
300 if (content_range == NULL) { | 347 ngx_http_range_t *range; |
301 return NGX_ERROR; | 348 |
302 } | 349 content_range = ngx_list_push(&r->headers_out.headers); |
303 | 350 if (content_range == NULL) { |
304 r->headers_out.content_range = content_range; | 351 return NGX_ERROR; |
305 | 352 } |
306 content_range->hash = 1; | 353 |
307 content_range->key.len = sizeof("Content-Range") - 1; | 354 r->headers_out.content_range = content_range; |
308 content_range->key.data = (u_char *) "Content-Range"; | 355 |
309 | 356 content_range->hash = 1; |
310 content_range->value.data = ngx_pnalloc(r->pool, | 357 content_range->key.len = sizeof("Content-Range") - 1; |
311 sizeof("bytes */") - 1 + NGX_OFF_T_LEN); | 358 content_range->key.data = (u_char *) "Content-Range"; |
312 if (content_range->value.data == NULL) { | 359 |
313 return NGX_ERROR; | 360 content_range->value.data = ngx_pnalloc(r->pool, |
314 } | 361 sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); |
315 | 362 if (content_range->value.data == NULL) { |
316 content_range->value.len = ngx_sprintf(content_range->value.data, | 363 return NGX_ERROR; |
317 "bytes */%O", | 364 } |
318 r->headers_out.content_length_n) | 365 |
319 - content_range->value.data; | 366 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ |
320 | 367 |
321 ngx_http_clear_content_length(r); | 368 range = ctx->ranges.elts; |
322 | 369 |
323 return rc; | 370 content_range->value.len = ngx_sprintf(content_range->value.data, |
324 } | 371 "bytes %O-%O/%O", |
325 | 372 range->start, range->end - 1, |
326 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); | 373 r->headers_out.content_length_n) |
327 | 374 - content_range->value.data; |
328 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; | 375 |
329 | 376 r->headers_out.content_length_n = range->end - range->start; |
330 if (ctx->ranges.nelts == 1) { | 377 |
331 | 378 if (r->headers_out.content_length) { |
332 content_range = ngx_list_push(&r->headers_out.headers); | 379 r->headers_out.content_length->hash = 0; |
333 if (content_range == NULL) { | 380 r->headers_out.content_length = NULL; |
334 return NGX_ERROR; | 381 } |
335 } | 382 |
336 | 383 return ngx_http_next_header_filter(r); |
337 r->headers_out.content_range = content_range; | 384 } |
338 | 385 |
339 content_range->hash = 1; | 386 |
340 content_range->key.len = sizeof("Content-Range") - 1; | 387 static ngx_int_t |
341 content_range->key.data = (u_char *) "Content-Range"; | 388 ngx_http_range_multipart_header(ngx_http_request_t *r, |
342 | 389 ngx_http_range_filter_ctx_t *ctx) |
343 content_range->value.data = | 390 { |
344 ngx_pnalloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); | 391 size_t len; |
345 if (content_range->value.data == NULL) { | 392 ngx_uint_t i; |
346 return NGX_ERROR; | 393 ngx_http_range_t *range; |
347 } | 394 ngx_atomic_uint_t boundary; |
348 | |
349 /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ | |
350 | |
351 content_range->value.len = ngx_sprintf(content_range->value.data, | |
352 "bytes %O-%O/%O", | |
353 range->start, range->end - 1, | |
354 r->headers_out.content_length_n) | |
355 - content_range->value.data; | |
356 | |
357 r->headers_out.content_length_n = range->end - range->start; | |
358 | |
359 if (r->headers_out.content_length) { | |
360 r->headers_out.content_length->hash = 0; | |
361 r->headers_out.content_length = NULL; | |
362 } | |
363 | |
364 return ngx_http_next_header_filter(r); | |
365 } | |
366 | |
367 | 395 |
368 /* TODO: what if no content_type ?? */ | 396 /* TODO: what if no content_type ?? */ |
369 | 397 |
370 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN | 398 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN |
371 + sizeof(CRLF "Content-Type: ") - 1 | 399 + sizeof(CRLF "Content-Type: ") - 1 |
463 r->headers_out.content_length->hash = 0; | 491 r->headers_out.content_length->hash = 0; |
464 r->headers_out.content_length = NULL; | 492 r->headers_out.content_length = NULL; |
465 } | 493 } |
466 | 494 |
467 return ngx_http_next_header_filter(r); | 495 return ngx_http_next_header_filter(r); |
468 | 496 } |
469 next_filter: | 497 |
470 | 498 |
471 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); | 499 static ngx_int_t |
472 if (r->headers_out.accept_ranges == NULL) { | 500 ngx_http_range_not_satisfiable(ngx_http_request_t *r) |
473 return NGX_ERROR; | 501 { |
474 } | 502 ngx_table_elt_t *content_range; |
475 | 503 |
476 r->headers_out.accept_ranges->hash = 1; | 504 r->headers_out.status = NGX_HTTP_RANGE_NOT_SATISFIABLE; |
477 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; | 505 |
478 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; | 506 content_range = ngx_list_push(&r->headers_out.headers); |
479 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; | 507 if (content_range == NULL) { |
480 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; | 508 return NGX_ERROR; |
481 | 509 } |
482 return ngx_http_next_header_filter(r); | 510 |
511 r->headers_out.content_range = content_range; | |
512 | |
513 content_range->hash = 1; | |
514 content_range->key.len = sizeof("Content-Range") - 1; | |
515 content_range->key.data = (u_char *) "Content-Range"; | |
516 | |
517 content_range->value.data = ngx_pnalloc(r->pool, | |
518 sizeof("bytes */") - 1 + NGX_OFF_T_LEN); | |
519 if (content_range->value.data == NULL) { | |
520 return NGX_ERROR; | |
521 } | |
522 | |
523 content_range->value.len = ngx_sprintf(content_range->value.data, | |
524 "bytes */%O", | |
525 r->headers_out.content_length_n) | |
526 - content_range->value.data; | |
527 | |
528 ngx_http_clear_content_length(r); | |
529 | |
530 return NGX_HTTP_RANGE_NOT_SATISFIABLE; | |
483 } | 531 } |
484 | 532 |
485 | 533 |
486 static ngx_int_t | 534 static ngx_int_t |
487 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | 535 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) |
488 { | 536 { |
489 off_t start, last; | |
490 ngx_buf_t *b, *buf; | |
491 ngx_uint_t i; | |
492 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; | |
493 ngx_http_range_t *range; | |
494 ngx_http_range_filter_ctx_t *ctx; | 537 ngx_http_range_filter_ctx_t *ctx; |
495 | 538 |
496 if (in == NULL) { | 539 if (in == NULL) { |
497 return ngx_http_next_body_filter(r, in); | 540 return ngx_http_next_body_filter(r, in); |
498 } | 541 } |
501 | 544 |
502 if (ctx == NULL) { | 545 if (ctx == NULL) { |
503 return ngx_http_next_body_filter(r, in); | 546 return ngx_http_next_body_filter(r, in); |
504 } | 547 } |
505 | 548 |
506 buf = in->buf; | |
507 | |
508 if (ngx_buf_special(in->buf)) { | 549 if (ngx_buf_special(in->buf)) { |
509 return ngx_http_next_body_filter(r, in); | 550 return ngx_http_next_body_filter(r, in); |
510 } | 551 } |
511 | 552 |
553 if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) { | |
554 return NGX_ERROR; | |
555 } | |
556 | |
557 if (ctx->ranges.nelts == 1) { | |
558 | |
559 /* | |
560 * the optimized version for the responses | |
561 * that are passed in the single buffer | |
562 */ | |
563 | |
564 return ngx_http_range_singlepart_body(r, ctx, in); | |
565 } | |
566 | |
567 return ngx_http_range_multipart_body(r, ctx, in); | |
568 } | |
569 | |
570 | |
571 static ngx_int_t | |
572 ngx_http_range_test_overlapped(ngx_http_request_t *r, | |
573 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) | |
574 { | |
575 off_t start, last; | |
576 ngx_buf_t *buf; | |
577 ngx_uint_t i; | |
578 ngx_http_range_t *range; | |
579 | |
512 if (ctx->offset) { | 580 if (ctx->offset) { |
513 goto overlapped; | 581 goto overlapped; |
514 } | 582 } |
515 | 583 |
516 range = ctx->ranges.elts; | 584 buf = in->buf; |
517 | 585 |
518 if (!buf->last_buf) { | 586 if (!buf->last_buf) { |
519 | 587 |
520 if (buf->in_file) { | 588 if (buf->in_file) { |
521 start = buf->file_pos + ctx->offset; | 589 start = buf->file_pos + ctx->offset; |
524 } else { | 592 } else { |
525 start = buf->pos - buf->start + ctx->offset; | 593 start = buf->pos - buf->start + ctx->offset; |
526 last = buf->last - buf->start + ctx->offset; | 594 last = buf->last - buf->start + ctx->offset; |
527 } | 595 } |
528 | 596 |
597 range = ctx->ranges.elts; | |
529 for (i = 0; i < ctx->ranges.nelts; i++) { | 598 for (i = 0; i < ctx->ranges.nelts; i++) { |
530 if (start > range[i].start || last < range[i].end) { | 599 if (start > range[i].start || last < range[i].end) { |
531 goto overlapped; | 600 goto overlapped; |
532 } | 601 } |
533 } | 602 } |
534 } | 603 } |
535 | 604 |
536 /* | |
537 * the optimized version for the responses | |
538 * that are passed in the single buffer | |
539 */ | |
540 | |
541 ctx->offset = ngx_buf_size(buf); | 605 ctx->offset = ngx_buf_size(buf); |
542 | 606 |
543 if (ctx->ranges.nelts == 1) { | 607 return NGX_OK; |
544 | 608 |
545 if (buf->in_file) { | 609 overlapped: |
546 buf->file_pos = range->start; | 610 |
547 buf->file_last = range->end; | 611 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
548 } | 612 "range in overlapped buffers"); |
549 | 613 |
550 if (ngx_buf_in_memory(buf)) { | 614 return NGX_ERROR; |
551 buf->pos = buf->start + (size_t) range->start; | 615 } |
552 buf->last = buf->start + (size_t) range->end; | 616 |
553 } | 617 |
554 | 618 static ngx_int_t |
555 return ngx_http_next_body_filter(r, in); | 619 ngx_http_range_singlepart_body(ngx_http_request_t *r, |
556 } | 620 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) |
621 { | |
622 ngx_buf_t *buf; | |
623 ngx_http_range_t *range; | |
624 | |
625 buf = in->buf; | |
626 range = ctx->ranges.elts; | |
627 | |
628 if (buf->in_file) { | |
629 buf->file_pos = range->start; | |
630 buf->file_last = range->end; | |
631 } | |
632 | |
633 if (ngx_buf_in_memory(buf)) { | |
634 buf->pos = buf->start + (size_t) range->start; | |
635 buf->last = buf->start + (size_t) range->end; | |
636 } | |
637 | |
638 return ngx_http_next_body_filter(r, in); | |
639 } | |
640 | |
641 | |
642 static ngx_int_t | |
643 ngx_http_range_multipart_body(ngx_http_request_t *r, | |
644 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) | |
645 { | |
646 ngx_buf_t *b, *buf; | |
647 ngx_uint_t i; | |
648 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; | |
649 ngx_http_range_t *range; | |
557 | 650 |
558 ll = &out; | 651 ll = &out; |
652 buf = in->buf; | |
653 range = ctx->ranges.elts; | |
559 | 654 |
560 for (i = 0; i < ctx->ranges.nelts; i++) { | 655 for (i = 0; i < ctx->ranges.nelts; i++) { |
561 | 656 |
562 /* | 657 /* |
563 * The boundary header of the range: | 658 * The boundary header of the range: |
669 hcl->next = NULL; | 764 hcl->next = NULL; |
670 | 765 |
671 *ll = hcl; | 766 *ll = hcl; |
672 | 767 |
673 return ngx_http_next_body_filter(r, out); | 768 return ngx_http_next_body_filter(r, out); |
674 | |
675 overlapped: | |
676 | |
677 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
678 "range in overlapped buffers"); | |
679 | |
680 return NGX_ERROR; | |
681 } | 769 } |
682 | 770 |
683 | 771 |
684 static ngx_int_t | 772 static ngx_int_t |
685 ngx_http_range_header_filter_init(ngx_conf_t *cf) | 773 ngx_http_range_header_filter_init(ngx_conf_t *cf) |