ПРОЕКТЫ 


  АРХИВ 


Apache-Talk @lexa.ru 

Inet-Admins @info.east.ru 

Filmscanners @halftone.co.uk 

Security-alerts @yandex-team.ru 

nginx-ru @sysoev.ru 


  СТАТЬИ 


  ПЕРСОНАЛЬНОЕ 


  ПРОГРАММЫ 



ПИШИТЕ
ПИСЬМА












     АРХИВ :: nginx-ru
Nginx-ru mailing list archive (nginx-ru@sysoev.ru)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

upload_limit_rate



Патч во вложении к upload module 2.0.8 добавляет директиву upload_limit_rate и 
позволяет ограничивать скорость загрузки.

Рекомендуется потестировать, прежде чем выкладывать в production.

-- 
Regards,
Valery Kholodkov
diff --git a/ngx_http_upload_module.c b/ngx_http_upload_module.c
index fbad80b..8304ad2 100644
--- a/ngx_http_upload_module.c
+++ b/ngx_http_upload_module.c
@@ -102,6 +102,7 @@ typedef struct {
     ngx_array_t       *field_filters;
     ngx_array_t       *cleanup_statuses;
     ngx_flag_t         forward_args;
+    size_t            limit_rate;
 
     unsigned int      md5:1;
     unsigned int      sha1:1;
@@ -153,6 +154,8 @@ typedef struct ngx_http_upload_ctx_s {
     ngx_chain_t         *last;
     ngx_chain_t         *checkpoint;
     size_t              output_body_len;
+    size_t              limit_rate;
+    ssize_t             received;
 
     ngx_pool_cleanup_t          *cln;
 
@@ -419,6 +422,17 @@ static ngx_command_t  ngx_http_upload_commands[] = { /* 
{{{ */
        offsetof(ngx_http_upload_loc_conf_t, forward_args),
        NULL },
 
+     /*
+      * Specifies request body reception rate limit
+      */
+    { ngx_string("upload_limit_rate"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_upload_loc_conf_t, limit_rate),
+      NULL },
+
       ngx_null_command
 }; /* }}} */
 
@@ -569,6 +583,8 @@ ngx_http_upload_handler(ngx_http_request_t *r)
     u->log = r->connection->log;
     u->chain = u->last = u->checkpoint = NULL;
     u->output_body_len = 0;
+    u->limit_rate = ulcf->limit_rate;
+    u->received = 0;
 
     upload_init_ctx(u);
 
@@ -1126,6 +1142,7 @@ ngx_http_upload_create_loc_conf(ngx_conf_t *cf)
     conf->max_header_len = NGX_CONF_UNSET_SIZE;
     conf->max_output_body_len = NGX_CONF_UNSET_SIZE;
     conf->max_file_size = NGX_CONF_UNSET;
+    conf->limit_rate = NGX_CONF_UNSET_SIZE;
 
     /*
      * conf->field_templates,
@@ -1169,6 +1186,8 @@ ngx_http_upload_merge_loc_conf(ngx_conf_t *cf, void 
*parent, void *child)
                              prev->max_file_size,
                              0);
 
+    ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
+
     if(conf->forward_args == NGX_CONF_UNSET) {
         conf->forward_args = (prev->forward_args != NGX_CONF_UNSET) ?
             prev->forward_args : 0;
@@ -1817,12 +1836,45 @@ 
ngx_http_read_upload_client_request_body_handler(ngx_http_request_t *r)
 {
     ngx_int_t  rc;
     ngx_http_upload_ctx_t     *u = ngx_http_get_module_ctx(r, 
ngx_http_upload_module);
+    ngx_event_t               *rev = r->connection->read;
+    ngx_http_core_loc_conf_t  *clcf;
 
-    if (r->connection->read->timedout) {
-        r->connection->timedout = 1;
-        upload_shutdown_ctx(u);
-        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
-        return;
+    if (rev->timedout) {
+        if(!rev->delayed) {
+            r->connection->timedout = 1;
+            upload_shutdown_ctx(u);
+            ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+            return;
+        }
+
+        rev->timedout = 0;
+        rev->delayed = 0;
+
+        if (!rev->ready) {
+            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+            ngx_add_timer(rev, clcf->client_body_timeout);
+
+            if (ngx_handle_read_event(rev, clcf->send_lowat) != NGX_OK) {
+                upload_shutdown_ctx(u);
+                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            }
+
+            return;
+        }
+    }
+    else{
+        if (r->connection->read->delayed) {
+            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
+                           "http read delayed");
+
+            if (ngx_handle_read_event(rev, clcf->send_lowat) != NGX_OK) {
+                upload_shutdown_ctx(u);
+                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            }
+
+            return;
+        }
     }
 
     rc = ngx_http_do_read_upload_client_request_body(r);
@@ -1836,13 +1888,13 @@ 
ngx_http_read_upload_client_request_body_handler(ngx_http_request_t *r)
 static ngx_int_t /* {{{ ngx_http_do_read_upload_client_request_body */
 ngx_http_do_read_upload_client_request_body(ngx_http_request_t *r)
 {
-    size_t                     size;
-    ssize_t                    n;
+    ssize_t                     size, n, limit;
     ngx_connection_t          *c;
     ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_upload_ctx_t     *u = ngx_http_get_module_ctx(r, 
ngx_http_upload_module);
     ngx_int_t                  rc;
+    ngx_msec_t                 delay;
 
     c = r->connection;
     rb = r->request_body;
@@ -1880,6 +1932,22 @@ 
ngx_http_do_read_upload_client_request_body(ngx_http_request_t *r)
                 size = (size_t)rb->rest;
             }
 
+            if (u->limit_rate) {
+                limit = u->limit_rate * (ngx_time() - r->start_sec + 1) - 
u->received;
+
+                if (limit < 0) {
+                    c->read->delayed = 1;
+                    ngx_add_timer(c->read,
+                                  (ngx_msec_t) (- limit * 1000 / u->limit_rate 
+ 1));
+
+                    return NGX_AGAIN;
+                }
+
+                if(limit > 0 && size > limit) {
+                    size = limit;
+                }
+            }
+
             n = c->recv(c, rb->buf->last, size);
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
@@ -1902,6 +1970,7 @@ 
ngx_http_do_read_upload_client_request_body(ngx_http_request_t *r)
             rb->buf->last += n;
             rb->rest -= n;
             r->request_length += n;
+            u->received += n;
 
             if (rb->rest == 0) {
                 break;
@@ -1910,6 +1979,16 @@ 
ngx_http_do_read_upload_client_request_body(ngx_http_request_t *r)
             if (rb->buf->last < rb->buf->end) {
                 break;
             }
+
+            if (u->limit_rate) {
+                delay = (ngx_msec_t) (n * 1000 / u->limit_rate + 1);
+
+                if (delay > 0) {
+                    c->read->delayed = 1;
+                    ngx_add_timer(c->read, delay);
+                    return NGX_AGAIN;
+                }
+            }
         }
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,


 




Copyright © Lexa Software, 1996-2009.