diff src/http/modules/ngx_http_range_filter_module.c @ 272:29a6403156b0 NGINX_0_5_6

nginx 0.5.6 *) Change: now the ngx_http_index_module ignores all methods except the GET, HEAD, and POST methods. *) Feature: the ngx_http_limit_zone_module. *) Feature: the $binary_remote_addr variable. *) Feature: the "ssl_session_cache" directives of the ngx_http_ssl_module and ngx_imap_ssl_module. *) Feature: the DELETE method supports recursive removal. *) Bugfix: the byte-ranges were transferred incorrectly if the $r->sendfile() was used.
author Igor Sysoev <http://sysoev.ru>
date Tue, 09 Jan 2007 00:00:00 +0300
parents 38e7b94d63ac
children 675a39fd14cd
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
@@ -45,7 +45,16 @@
 
 
 typedef struct {
-    ngx_str_t  boundary_header;
+    off_t        start;
+    off_t        end;
+    ngx_str_t    content_range;
+} ngx_http_range_t;
+
+
+typedef struct {
+    off_t        offset;
+    ngx_str_t    boundary_header;
+    ngx_array_t  ranges;
 } ngx_http_range_filter_ctx_t;
 
 
@@ -159,8 +168,13 @@ ngx_http_range_header_filter(ngx_http_re
         return ngx_http_next_header_filter(r);
     }
 
-    if (ngx_array_init(&r->headers_out.ranges, r->pool, 2,
-                                        sizeof(ngx_http_range_t)) == NGX_ERROR)
+    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t));
+    if (ctx == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t))
+        == NGX_ERROR)
     {
         return NGX_ERROR;
     }
@@ -201,7 +215,7 @@ ngx_http_range_header_filter(ngx_http_re
             while (*p == ' ') { p++; }
 
             if (*p == ',' || *p == '\0') {
-                range = ngx_array_push(&r->headers_out.ranges);
+                range = ngx_array_push(&ctx->ranges);
                 if (range == NULL) {
                     return NGX_ERROR;
                 }
@@ -247,7 +261,7 @@ ngx_http_range_header_filter(ngx_http_re
             break;
         }
 
-        range = ngx_array_push(&r->headers_out.ranges);
+        range = ngx_array_push(&ctx->ranges);
         if (range == NULL) {
             return NGX_ERROR;
         }
@@ -275,7 +289,6 @@ ngx_http_range_header_filter(ngx_http_re
         /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */
 
         r->headers_out.status = rc;
-        r->headers_out.ranges.nelts = 0;
 
         content_range = ngx_list_push(&r->headers_out.headers);
         if (content_range == NULL) {
@@ -304,9 +317,11 @@ ngx_http_range_header_filter(ngx_http_re
         return rc;
     }
 
+    ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
+
     r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
 
-    if (r->headers_out.ranges.nelts == 1) {
+    if (ctx->ranges.nelts == 1) {
 
         content_range = ngx_list_push(&r->headers_out.headers);
         if (content_range == NULL) {
@@ -335,20 +350,17 @@ ngx_http_range_header_filter(ngx_http_re
 
         r->headers_out.content_length_n = range->end - range->start;
 
+        if (r->headers_out.content_length) {
+            r->headers_out.content_length->hash = 0;
+            r->headers_out.content_length = NULL;
+        }
+
         return ngx_http_next_header_filter(r);
     }
 
 
     /* TODO: what if no content_type ?? */
 
-    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t));
-    if (ctx == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
-
-
     len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
           + sizeof(CRLF "Content-Type: ") - 1
           + r->headers_out.content_type.len
@@ -417,8 +429,8 @@ ngx_http_range_header_filter(ngx_http_re
 
     len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1;
 
-    range = r->headers_out.ranges.elts;
-    for (i = 0; i < r->headers_out.ranges.nelts; i++) {
+    range = ctx->ranges.elts;
+    for (i = 0; i < ctx->ranges.nelts; i++) {
 
         /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */
 
@@ -440,7 +452,11 @@ ngx_http_range_header_filter(ngx_http_re
     }
 
     r->headers_out.content_length_n = len;
-    r->headers_out.content_length = NULL;
+
+    if (r->headers_out.content_length) {
+        r->headers_out.content_length->hash = 0;
+        r->headers_out.content_length = NULL;
+    }
 
     return ngx_http_next_header_filter(r);
 }
@@ -449,106 +465,105 @@ ngx_http_range_header_filter(ngx_http_re
 static ngx_int_t
 ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
+    off_t                         start, last;
+    ngx_buf_t                    *b, *buf;
     ngx_uint_t                    i;
-    ngx_buf_t                    *b;
     ngx_chain_t                  *out, *hcl, *rcl, *dcl, **ll;
     ngx_http_range_t             *range;
     ngx_http_range_filter_ctx_t  *ctx;
 
-    if (r->headers_out.ranges.nelts == 0) {
+    if (in == NULL) {
+        return ngx_http_next_body_filter(r, in);
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module);
+
+    if (ctx == NULL) {
+        return ngx_http_next_body_filter(r, in);
+    }
+
+    buf = in->buf;
+
+    if (ngx_buf_special(in->buf)) {
         return ngx_http_next_body_filter(r, in);
     }
 
+    if (ctx->offset) {
+        goto overlapped;
+    }
+
+    range = ctx->ranges.elts;
+
+    if (!buf->last_buf) {
+
+        if (buf->in_file) {
+            start = buf->file_pos + ctx->offset;
+            last = buf->file_last + ctx->offset;
+
+        } else {
+            start = buf->pos - buf->start + ctx->offset;
+            last = buf->last - buf->start + ctx->offset;
+        }
+
+        for (i = 0; i < ctx->ranges.nelts; i++) {
+            if (start > range[i].start || last < range[i].end) {
+                 goto overlapped;
+            }
+        }
+    }
+
     /*
-     * the optimized version for the static files only
-     * that are passed in the single file buf
+     * the optimized version for the responses
+     * that are passed in the single buffer
      */
 
-    if (in && in->buf->in_file && in->buf->last_buf) {
-        range = r->headers_out.ranges.elts;
+    ctx->offset = ngx_buf_size(buf);
+
+    if (ctx->ranges.nelts == 1) {
 
-        if (r->headers_out.ranges.nelts == 1) {
-            in->buf->file_pos = range->start;
-            in->buf->file_last = range->end;
+        if (buf->in_file) {
+            buf->file_pos = range->start;
+            buf->file_last = range->end;
+        }
 
-            return ngx_http_next_body_filter(r, in);
+        if (ngx_buf_in_memory(buf)) {
+            buf->pos = buf->start + (size_t) range->start;
+            buf->last = buf->start + (size_t) range->end;
         }
 
-        ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module);
-        ll = &out;
+        return ngx_http_next_body_filter(r, in);
+    }
 
-        for (i = 0; i < r->headers_out.ranges.nelts; i++) {
+    ll = &out;
+
+    for (i = 0; i < ctx->ranges.nelts; i++) {
 
-            /*
-             * The boundary header of the range:
-             * CRLF
-             * "--0123456789" CRLF
-             * "Content-Type: image/jpeg" CRLF
-             * "Content-Range: bytes "
-             */
+        /*
+         * The boundary header of the range:
+         * CRLF
+         * "--0123456789" CRLF
+         * "Content-Type: image/jpeg" CRLF
+         * "Content-Range: bytes "
+         */
 
-            b = ngx_calloc_buf(r->pool);
-            if (b == NULL) {
-                return NGX_ERROR;
-            }
+        b = ngx_calloc_buf(r->pool);
+        if (b == NULL) {
+            return NGX_ERROR;
+        }
 
-            b->memory = 1;
-            b->pos = ctx->boundary_header.data;
-            b->last = ctx->boundary_header.data + ctx->boundary_header.len;
+        b->memory = 1;
+        b->pos = ctx->boundary_header.data;
+        b->last = ctx->boundary_header.data + ctx->boundary_header.len;
 
-            hcl = ngx_alloc_chain_link(r->pool);
-            if (hcl == NULL) {
-                return NGX_ERROR;
-            }
+        hcl = ngx_alloc_chain_link(r->pool);
+        if (hcl == NULL) {
+            return NGX_ERROR;
+        }
 
-            hcl->buf = b;
+        hcl->buf = b;
 
 
-            /* "SSSS-EEEE/TTTT" CRLF CRLF */
-
-            b = ngx_calloc_buf(r->pool);
-            if (b == NULL) {
-                return NGX_ERROR;
-            }
-
-            b->temporary = 1;
-            b->pos = range[i].content_range.data;
-            b->last = range[i].content_range.data + range[i].content_range.len;
-
-            rcl = ngx_alloc_chain_link(r->pool);
-            if (rcl == NULL) {
-                return NGX_ERROR;
-            }
-
-            rcl->buf = b;
-
-
-            /* the range data */
-
-            b = ngx_calloc_buf(r->pool);
-            if (b == NULL) {
-                return NGX_ERROR;
-            }
-
-            b->in_file = 1;
-            b->file_pos = range[i].start;
-            b->file_last = range[i].end;
-            b->file = in->buf->file;
-
-            dcl = ngx_alloc_chain_link(r->pool);
-            if (dcl == NULL) {
-                return NGX_ERROR;
-            }
-
-            dcl->buf = b;
-
-            *ll = hcl;
-            hcl->next = rcl;
-            rcl->next = dcl;
-            ll = &dcl->next;
-        }
-
-        /* the last boundary CRLF "--0123456789--" CRLF  */
+        /* "SSSS-EEEE/TTTT" CRLF CRLF */
 
         b = ngx_calloc_buf(r->pool);
         if (b == NULL) {
@@ -556,34 +571,91 @@ ngx_http_range_body_filter(ngx_http_requ
         }
 
         b->temporary = 1;
-        b->last_buf = 1;
+        b->pos = range[i].content_range.data;
+        b->last = range[i].content_range.data + range[i].content_range.len;
+
+        rcl = ngx_alloc_chain_link(r->pool);
+        if (rcl == NULL) {
+            return NGX_ERROR;
+        }
+
+        rcl->buf = b;
+
+
+        /* the range data */
+
+        b = ngx_calloc_buf(r->pool);
+        if (b == NULL) {
+            return NGX_ERROR;
+        }
 
-        b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
-                                     + sizeof("--" CRLF) - 1);
-        if (b->pos == NULL) {
+        b->in_file = buf->in_file;
+        b->temporary = buf->temporary;
+        b->memory = buf->memory;
+        b->mmap = buf->mmap;
+        b->file = buf->file;
+
+        if (buf->in_file) {
+            buf->file_pos = range[i].start;
+            buf->file_last = range[i].end;
+        }
+
+        if (ngx_buf_in_memory(buf)) {
+            buf->pos = buf->start + (size_t) range[i].start;
+            buf->last = buf->start + (size_t) range[i].end;
+        }
+
+        dcl = ngx_alloc_chain_link(r->pool);
+        if (dcl == NULL) {
             return NGX_ERROR;
         }
 
-        b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10);
-        *b->last++ = '-'; *b->last++ = '-';
-        *b->last++ = CR; *b->last++ = LF;
-
-        hcl = ngx_alloc_chain_link(r->pool);
-        if (hcl == NULL) {
-            return NGX_ERROR;
-        }
-
-        hcl->buf = b;
-        hcl->next = NULL;
+        dcl->buf = b;
 
         *ll = hcl;
+        hcl->next = rcl;
+        rcl->next = dcl;
+        ll = &dcl->next;
+    }
 
-        return ngx_http_next_body_filter(r, out);
+    /* the last boundary CRLF "--0123456789--" CRLF  */
+
+    b = ngx_calloc_buf(r->pool);
+    if (b == NULL) {
+        return NGX_ERROR;
+    }
+
+    b->temporary = 1;
+    b->last_buf = 1;
+
+    b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
+                                 + sizeof("--" CRLF) - 1);
+    if (b->pos == NULL) {
+        return NGX_ERROR;
     }
 
-    /* TODO: alert */
+    b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10);
+    *b->last++ = '-'; *b->last++ = '-';
+    *b->last++ = CR; *b->last++ = LF;
+
+    hcl = ngx_alloc_chain_link(r->pool);
+    if (hcl == NULL) {
+        return NGX_ERROR;
+    }
 
-    return ngx_http_next_body_filter(r, in);
+    hcl->buf = b;
+    hcl->next = NULL;
+
+    *ll = hcl;
+
+    return ngx_http_next_body_filter(r, out);
+
+overlapped:
+
+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                  "range in overlapped buffers");
+
+    return NGX_ERROR;
 }