comparison src/http/modules/ngx_http_range_filter_module.c @ 390:0b6053502c55 NGINX_0_7_7

nginx 0.7.7 *) Change: now the EAGAIN error returned by connect() is not considered as temporary error. *) Change: now the $ssl_client_cert variable value is a certificate with TAB character intended before each line except first one; an unchanged certificate is available in the $ssl_client_raw_cert variable. *) Feature: the "ask" parameter in the "ssl_verify_client" directive. *) Feature: byte-range processing improvements. Thanks to Maxim Dounin. *) Feature: the "directio" directive. *) Feature: MacOSX 1.5 sendfile() support. *) Bugfix: now in MacOSX and Cygwin locations are tested in case insensitive mode; however, the compare is provided by single-byte locales only. *) Bugfix: mail proxy SSL connections hanged, if select, poll, or /dev/poll methods were used. *) Bugfix: UTF-8 encoding usage in the ngx_http_autoindex_module.
author Igor Sysoev <http://sysoev.ru>
date Wed, 30 Jul 2008 00:00:00 +0400
parents 984bb0b1399b
children b246022ef454
comparison
equal deleted inserted replaced
389:930e48a26dde 390:0b6053502c55
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_not_satisfiable(ngx_http_request_t *r);
68 static ngx_int_t ngx_http_range_test_overlapped(ngx_http_request_t *r,
69 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in);
70 static ngx_int_t ngx_http_range_singlepart_body(ngx_http_request_t *r,
71 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in);
72 static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r,
73 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in);
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
368 /* TODO: what if no content_type ?? */
369 395
370 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN 396 len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
371 + sizeof(CRLF "Content-Type: ") - 1 397 + sizeof(CRLF "Content-Type: ") - 1
372 + r->headers_out.content_type.len 398 + r->headers_out.content_type.len
373 + sizeof(CRLF "Content-Range: bytes ") - 1; 399 + sizeof(CRLF "Content-Range: bytes ") - 1;
401 &r->headers_out.charset) 427 &r->headers_out.charset)
402 - ctx->boundary_header.data; 428 - ctx->boundary_header.data;
403 429
404 r->headers_out.charset.len = 0; 430 r->headers_out.charset.len = 0;
405 431
406 } else { 432 } else if (r->headers_out.content_type.len) {
407 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, 433 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
408 CRLF "--%0muA" CRLF 434 CRLF "--%0muA" CRLF
409 "Content-Type: %V" CRLF 435 "Content-Type: %V" CRLF
410 "Content-Range: bytes ", 436 "Content-Range: bytes ",
411 boundary, 437 boundary,
412 &r->headers_out.content_type) 438 &r->headers_out.content_type)
413 - ctx->boundary_header.data; 439 - ctx->boundary_header.data;
440
441 } else {
442 ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
443 CRLF "--%0muA" CRLF
444 "Content-Range: bytes ",
445 boundary)
446 - ctx->boundary_header.data;
414 } 447 }
415 448
416 r->headers_out.content_type.data = 449 r->headers_out.content_type.data =
417 ngx_pnalloc(r->pool, 450 ngx_pnalloc(r->pool,
418 sizeof("Content-Type: multipart/byteranges; boundary=") - 1 451 sizeof("Content-Type: multipart/byteranges; boundary=") - 1
463 r->headers_out.content_length->hash = 0; 496 r->headers_out.content_length->hash = 0;
464 r->headers_out.content_length = NULL; 497 r->headers_out.content_length = NULL;
465 } 498 }
466 499
467 return ngx_http_next_header_filter(r); 500 return ngx_http_next_header_filter(r);
468 501 }
469 next_filter: 502
470 503
471 r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); 504 static ngx_int_t
472 if (r->headers_out.accept_ranges == NULL) { 505 ngx_http_range_not_satisfiable(ngx_http_request_t *r)
473 return NGX_ERROR; 506 {
474 } 507 ngx_table_elt_t *content_range;
475 508
476 r->headers_out.accept_ranges->hash = 1; 509 r->headers_out.status = NGX_HTTP_RANGE_NOT_SATISFIABLE;
477 r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; 510
478 r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; 511 content_range = ngx_list_push(&r->headers_out.headers);
479 r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; 512 if (content_range == NULL) {
480 r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; 513 return NGX_ERROR;
481 514 }
482 return ngx_http_next_header_filter(r); 515
516 r->headers_out.content_range = content_range;
517
518 content_range->hash = 1;
519 content_range->key.len = sizeof("Content-Range") - 1;
520 content_range->key.data = (u_char *) "Content-Range";
521
522 content_range->value.data = ngx_pnalloc(r->pool,
523 sizeof("bytes */") - 1 + NGX_OFF_T_LEN);
524 if (content_range->value.data == NULL) {
525 return NGX_ERROR;
526 }
527
528 content_range->value.len = ngx_sprintf(content_range->value.data,
529 "bytes */%O",
530 r->headers_out.content_length_n)
531 - content_range->value.data;
532
533 ngx_http_clear_content_length(r);
534
535 return NGX_HTTP_RANGE_NOT_SATISFIABLE;
483 } 536 }
484 537
485 538
486 static ngx_int_t 539 static ngx_int_t
487 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 540 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
488 { 541 {
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; 542 ngx_http_range_filter_ctx_t *ctx;
495 543
496 if (in == NULL) { 544 if (in == NULL) {
497 return ngx_http_next_body_filter(r, in); 545 return ngx_http_next_body_filter(r, in);
498 } 546 }
501 549
502 if (ctx == NULL) { 550 if (ctx == NULL) {
503 return ngx_http_next_body_filter(r, in); 551 return ngx_http_next_body_filter(r, in);
504 } 552 }
505 553
506 buf = in->buf; 554 if (ctx->ranges.nelts == 1) {
555 return ngx_http_range_singlepart_body(r, ctx, in);
556 }
557
558 /*
559 * multipart ranges are supported only if whole body is in a single buffer
560 */
507 561
508 if (ngx_buf_special(in->buf)) { 562 if (ngx_buf_special(in->buf)) {
509 return ngx_http_next_body_filter(r, in); 563 return ngx_http_next_body_filter(r, in);
510 } 564 }
511 565
566 if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) {
567 return NGX_ERROR;
568 }
569
570 return ngx_http_range_multipart_body(r, ctx, in);
571 }
572
573
574 static ngx_int_t
575 ngx_http_range_test_overlapped(ngx_http_request_t *r,
576 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
577 {
578 off_t start, last;
579 ngx_buf_t *buf;
580 ngx_uint_t i;
581 ngx_http_range_t *range;
582
512 if (ctx->offset) { 583 if (ctx->offset) {
513 goto overlapped; 584 goto overlapped;
514 } 585 }
515 586
516 range = ctx->ranges.elts; 587 buf = in->buf;
517 588
518 if (!buf->last_buf) { 589 if (!buf->last_buf) {
519 590
520 if (buf->in_file) { 591 if (buf->in_file) {
521 start = buf->file_pos + ctx->offset; 592 start = buf->file_pos + ctx->offset;
524 } else { 595 } else {
525 start = buf->pos - buf->start + ctx->offset; 596 start = buf->pos - buf->start + ctx->offset;
526 last = buf->last - buf->start + ctx->offset; 597 last = buf->last - buf->start + ctx->offset;
527 } 598 }
528 599
600 range = ctx->ranges.elts;
529 for (i = 0; i < ctx->ranges.nelts; i++) { 601 for (i = 0; i < ctx->ranges.nelts; i++) {
530 if (start > range[i].start || last < range[i].end) { 602 if (start > range[i].start || last < range[i].end) {
531 goto overlapped; 603 goto overlapped;
532 } 604 }
533 } 605 }
534 } 606 }
535 607
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); 608 ctx->offset = ngx_buf_size(buf);
542 609
543 if (ctx->ranges.nelts == 1) { 610 return NGX_OK;
544 611
545 if (buf->in_file) { 612 overlapped:
546 buf->file_pos = range->start; 613
547 buf->file_last = range->end; 614 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
548 } 615 "range in overlapped buffers");
549 616
550 if (ngx_buf_in_memory(buf)) { 617 return NGX_ERROR;
551 buf->pos = buf->start + (size_t) range->start; 618 }
552 buf->last = buf->start + (size_t) range->end; 619
553 } 620
554 621 static ngx_int_t
555 return ngx_http_next_body_filter(r, in); 622 ngx_http_range_singlepart_body(ngx_http_request_t *r,
556 } 623 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
557 624 {
625 off_t start, last;
626 ngx_buf_t *buf;
627 ngx_chain_t *out, *cl, **ll;
628 ngx_http_range_t *range;
629
630 out = NULL;
558 ll = &out; 631 ll = &out;
632 range = ctx->ranges.elts;
633
634 for (cl = in; cl; cl = cl->next) {
635
636 buf = cl->buf;
637
638 start = ctx->offset;
639 last = ctx->offset + ngx_buf_size(buf);
640
641 ctx->offset = last;
642
643 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
644 "http range body buf: %O-%O", start, last);
645
646 if (ngx_buf_special(buf)) {
647 *ll = cl;
648 ll = &cl->next;
649 continue;
650 }
651
652 if (range->end <= start || range->start >= last) {
653
654 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
655 "http range body skip");
656
657 buf->pos = buf->last;
658 continue;
659 }
660
661 if (range->start > start) {
662
663 if (buf->in_file) {
664 buf->file_pos += range->start - start;
665 }
666
667 if (ngx_buf_in_memory(buf)) {
668 buf->pos += (size_t) (range->start - start);
669 }
670 }
671
672 if (range->end <= last) {
673
674 if (buf->in_file) {
675 buf->file_last -= last - range->end;
676 }
677
678 if (ngx_buf_in_memory(buf)) {
679 buf->last -= (size_t) (last - range->end);
680 }
681
682 buf->last_buf = 1;
683 *ll = cl;
684 cl->next = NULL;
685
686 break;
687 }
688
689 *ll = cl;
690 ll = &cl->next;
691 }
692
693 if (out == NULL) {
694 return NGX_OK;
695 }
696
697 return ngx_http_next_body_filter(r, out);
698 }
699
700
701 static ngx_int_t
702 ngx_http_range_multipart_body(ngx_http_request_t *r,
703 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
704 {
705 ngx_buf_t *b, *buf;
706 ngx_uint_t i;
707 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll;
708 ngx_http_range_t *range;
709
710 ll = &out;
711 buf = in->buf;
712 range = ctx->ranges.elts;
559 713
560 for (i = 0; i < ctx->ranges.nelts; i++) { 714 for (i = 0; i < ctx->ranges.nelts; i++) {
561 715
562 /* 716 /*
563 * The boundary header of the range: 717 * The boundary header of the range:
669 hcl->next = NULL; 823 hcl->next = NULL;
670 824
671 *ll = hcl; 825 *ll = hcl;
672 826
673 return ngx_http_next_body_filter(r, out); 827 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 } 828 }
682 829
683 830
684 static ngx_int_t 831 static ngx_int_t
685 ngx_http_range_header_filter_init(ngx_conf_t *cf) 832 ngx_http_range_header_filter_init(ngx_conf_t *cf)