changeset 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 930e48a26dde
children 1d9bef53cd8e
files src/http/modules/ngx_http_range_filter_module.c
diffstat 1 files changed, 82 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -489,7 +489,7 @@ ngx_http_range_body_filter(ngx_http_requ
     off_t                         start, last;
     ngx_buf_t                    *b, *buf;
     ngx_uint_t                    i;
-    ngx_chain_t                  *out, *hcl, *rcl, *dcl, **ll;
+    ngx_chain_t                  *out, *cl, *hcl, *rcl, *dcl, **ll;
     ngx_http_range_t             *range;
     ngx_http_range_filter_ctx_t  *ctx;
 
@@ -509,12 +509,91 @@ ngx_http_range_body_filter(ngx_http_requ
         return ngx_http_next_body_filter(r, in);
     }
 
+    range = ctx->ranges.elts;
+
+    if (ctx->ranges.nelts > 1) {
+        goto multipart;
+    }
+
+    /*
+     * the optimized version for the responses
+     * that are passed in the single buffer
+     */
+
+    out = NULL;
+    ll = &out;
+
+    for (cl = in; cl; cl = cl->next) {
+
+        buf = cl->buf;
+
+        start = ctx->offset;
+        last = ctx->offset + ngx_buf_size(buf);
+
+        ctx->offset = last;
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "range body filter: %O-%O", start, last);
+
+        if (ngx_buf_special(buf)) {
+            /* pass anyway */
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "range body filter: pass special");
+            *ll = cl;
+            ll = &cl->next;
+            continue;
+        }
+
+        if (range->end <= start || range->start >= last) {
+            /* skip buffer */
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "range body filter: skip");
+            buf->pos = buf->last;
+            continue;
+        }
+
+        if (range->start > start) {
+            if (buf->in_file) {
+                buf->file_pos += range->start - start;
+            }
+            if (ngx_buf_in_memory(buf)) {
+                buf->pos += (size_t) (range->start - start);
+            }
+        }
+
+        if (range->end <= last) {
+            if (buf->in_file) {
+                buf->file_last -= last - range->end;
+            }
+            if (ngx_buf_in_memory(buf)) {
+                buf->last -= (size_t) (last - range->end);
+            }
+
+            /* we are done */
+
+            buf->last_buf = 1;
+            *ll = cl;
+            cl->next = NULL;
+
+            break;
+        }
+
+        *ll = cl;
+        ll = &cl->next;
+    }
+
+    if (out == NULL) {
+        return NGX_OK;
+    }
+
+    return ngx_http_next_body_filter(r, out);
+
+multipart:
+
     if (ctx->offset) {
         goto overlapped;
     }
 
-    range = ctx->ranges.elts;
-
     if (!buf->last_buf) {
 
         if (buf->in_file) {
@@ -533,28 +612,8 @@ ngx_http_range_body_filter(ngx_http_requ
         }
     }
 
-    /*
-     * the optimized version for the responses
-     * that are passed in the single buffer
-     */
-
     ctx->offset = ngx_buf_size(buf);
 
-    if (ctx->ranges.nelts == 1) {
-
-        if (buf->in_file) {
-            buf->file_pos = range->start;
-            buf->file_last = range->end;
-        }
-
-        if (ngx_buf_in_memory(buf)) {
-            buf->pos = buf->start + (size_t) range->start;
-            buf->last = buf->start + (size_t) range->end;
-        }
-
-        return ngx_http_next_body_filter(r, in);
-    }
-
     ll = &out;
 
     for (i = 0; i < ctx->ranges.nelts; i++) {