comparison src/http/modules/ngx_http_range_filter_module.c @ 390:a5f67d82aea3

Range filter: support for multiple buffers (single range only). This partially allows range support for replies that aren't sent in single buffer. More work still required to support multipart/byteranges replies (when client asks for multiple ranges in one request).
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 21 Jul 2008 05:31:34 +0400
parents 984bb0b1399b
children 1d9bef53cd8e
comparison
equal deleted inserted replaced
389:930e48a26dde 390:a5f67d82aea3
487 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 487 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
488 { 488 {
489 off_t start, last; 489 off_t start, last;
490 ngx_buf_t *b, *buf; 490 ngx_buf_t *b, *buf;
491 ngx_uint_t i; 491 ngx_uint_t i;
492 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; 492 ngx_chain_t *out, *cl, *hcl, *rcl, *dcl, **ll;
493 ngx_http_range_t *range; 493 ngx_http_range_t *range;
494 ngx_http_range_filter_ctx_t *ctx; 494 ngx_http_range_filter_ctx_t *ctx;
495 495
496 if (in == NULL) { 496 if (in == NULL) {
497 return ngx_http_next_body_filter(r, in); 497 return ngx_http_next_body_filter(r, in);
507 507
508 if (ngx_buf_special(in->buf)) { 508 if (ngx_buf_special(in->buf)) {
509 return ngx_http_next_body_filter(r, in); 509 return ngx_http_next_body_filter(r, in);
510 } 510 }
511 511
512 if (ctx->offset) {
513 goto overlapped;
514 }
515
516 range = ctx->ranges.elts; 512 range = ctx->ranges.elts;
517 513
518 if (!buf->last_buf) { 514 if (ctx->ranges.nelts > 1) {
519 515 goto multipart;
520 if (buf->in_file) {
521 start = buf->file_pos + ctx->offset;
522 last = buf->file_last + ctx->offset;
523
524 } else {
525 start = buf->pos - buf->start + ctx->offset;
526 last = buf->last - buf->start + ctx->offset;
527 }
528
529 for (i = 0; i < ctx->ranges.nelts; i++) {
530 if (start > range[i].start || last < range[i].end) {
531 goto overlapped;
532 }
533 }
534 } 516 }
535 517
536 /* 518 /*
537 * the optimized version for the responses 519 * the optimized version for the responses
538 * that are passed in the single buffer 520 * that are passed in the single buffer
539 */ 521 */
540 522
523 out = NULL;
524 ll = &out;
525
526 for (cl = in; cl; cl = cl->next) {
527
528 buf = cl->buf;
529
530 start = ctx->offset;
531 last = ctx->offset + ngx_buf_size(buf);
532
533 ctx->offset = last;
534
535 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
536 "range body filter: %O-%O", start, last);
537
538 if (ngx_buf_special(buf)) {
539 /* pass anyway */
540 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
541 "range body filter: pass special");
542 *ll = cl;
543 ll = &cl->next;
544 continue;
545 }
546
547 if (range->end <= start || range->start >= last) {
548 /* skip buffer */
549 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
550 "range body filter: skip");
551 buf->pos = buf->last;
552 continue;
553 }
554
555 if (range->start > start) {
556 if (buf->in_file) {
557 buf->file_pos += range->start - start;
558 }
559 if (ngx_buf_in_memory(buf)) {
560 buf->pos += (size_t) (range->start - start);
561 }
562 }
563
564 if (range->end <= last) {
565 if (buf->in_file) {
566 buf->file_last -= last - range->end;
567 }
568 if (ngx_buf_in_memory(buf)) {
569 buf->last -= (size_t) (last - range->end);
570 }
571
572 /* we are done */
573
574 buf->last_buf = 1;
575 *ll = cl;
576 cl->next = NULL;
577
578 break;
579 }
580
581 *ll = cl;
582 ll = &cl->next;
583 }
584
585 if (out == NULL) {
586 return NGX_OK;
587 }
588
589 return ngx_http_next_body_filter(r, out);
590
591 multipart:
592
593 if (ctx->offset) {
594 goto overlapped;
595 }
596
597 if (!buf->last_buf) {
598
599 if (buf->in_file) {
600 start = buf->file_pos + ctx->offset;
601 last = buf->file_last + ctx->offset;
602
603 } else {
604 start = buf->pos - buf->start + ctx->offset;
605 last = buf->last - buf->start + ctx->offset;
606 }
607
608 for (i = 0; i < ctx->ranges.nelts; i++) {
609 if (start > range[i].start || last < range[i].end) {
610 goto overlapped;
611 }
612 }
613 }
614
541 ctx->offset = ngx_buf_size(buf); 615 ctx->offset = ngx_buf_size(buf);
542
543 if (ctx->ranges.nelts == 1) {
544
545 if (buf->in_file) {
546 buf->file_pos = range->start;
547 buf->file_last = range->end;
548 }
549
550 if (ngx_buf_in_memory(buf)) {
551 buf->pos = buf->start + (size_t) range->start;
552 buf->last = buf->start + (size_t) range->end;
553 }
554
555 return ngx_http_next_body_filter(r, in);
556 }
557 616
558 ll = &out; 617 ll = &out;
559 618
560 for (i = 0; i < ctx->ranges.nelts; i++) { 619 for (i = 0; i < ctx->ranges.nelts; i++) {
561 620