changeset 4035:c2a91088b0c0

Now if total size of all ranges is greater than source response size, then nginx disables ranges and returns just the source response. This fix should not affect well-behaving applications but will defeat DoS attempts exploiting malicious byte ranges.
author Igor Sysoev <igor@sysoev.ru>
date Fri, 26 Aug 2011 09:42:50 +0000
parents e2c075e774b6
children 20c7c73d3efa
files src/http/modules/ngx_http_range_filter_module.c
diffstat 1 files changed, 23 insertions(+), 14 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
@@ -146,7 +146,6 @@ static ngx_int_t
 ngx_http_range_header_filter(ngx_http_request_t *r)
 {
     time_t                        if_range;
-    ngx_int_t                     rc;
     ngx_http_range_filter_ctx_t  *ctx;
 
     if (r->http_version < NGX_HTTP_VERSION_10
@@ -192,10 +191,9 @@ ngx_http_range_header_filter(ngx_http_re
         return NGX_ERROR;
     }
 
-    rc = ngx_http_range_parse(r, ctx);
+    switch (ngx_http_range_parse(r, ctx)) {
 
-    if (rc == NGX_OK) {
-
+    case NGX_OK:
         ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
 
         r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
@@ -206,16 +204,17 @@ ngx_http_range_header_filter(ngx_http_re
         }
 
         return ngx_http_range_multipart_header(r, ctx);
-    }
+
+    case NGX_HTTP_RANGE_NOT_SATISFIABLE:
+        return ngx_http_range_not_satisfiable(r);
 
-    if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) {
-        return ngx_http_range_not_satisfiable(r);
+    case NGX_ERROR:
+        return NGX_ERROR;
+
+    default: /* NGX_DECLINED */
+        break;
     }
 
-    /* rc == NGX_ERROR */
-
-    return rc;
-
 next_filter:
 
     r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers);
@@ -235,11 +234,12 @@ ngx_int_t
 ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx)
 {
     u_char            *p;
-    off_t              start, end;
+    off_t              start, end, size;
     ngx_uint_t         suffix;
     ngx_http_range_t  *range;
 
     p = r->headers_in.range->value.data + 6;
+    size = 0;
 
     for ( ;; ) {
         start = 0;
@@ -277,9 +277,10 @@ ngx_http_range_parse(ngx_http_request_t 
 
                 range->start = start;
                 range->end = r->headers_out.content_length_n;
+                size += range->end - start;
 
                 if (*p++ != ',') {
-                    return NGX_OK;
+                    break;
                 }
 
                 continue;
@@ -331,10 +332,18 @@ ngx_http_range_parse(ngx_http_request_t 
             range->end = end + 1;
         }
 
+        size += range->end - start;
+
         if (*p++ != ',') {
-            return NGX_OK;
+            break;
         }
     }
+
+    if (size > r->headers_out.content_length_n) {
+        return NGX_DECLINED;
+    }
+
+    return NGX_OK;
 }