return NGX_ABORT;
}
- if (rev->active && !rev->ready) {
- ngx_add_timer(rev, p->read_timeout);
+ if (!rev->delayed) {
+ if (rev->active && !rev->ready) {
+ ngx_add_timer(rev, p->read_timeout);
- } else if (rev->timer_set) {
- ngx_del_timer(rev);
+ } else if (rev->timer_set) {
+ ngx_del_timer(rev);
+ }
}
}
static ngx_int_t
ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
{
+ off_t limit;
ssize_t n, size;
ngx_int_t rc;
ngx_buf_t *b;
+ ngx_msec_t delay;
ngx_chain_t *chain, *cl, *ln;
if (p->upstream_eof || p->upstream_error || p->upstream_done) {
}
#endif
+ if (p->limit_rate) {
+ if (p->upstream->read->delayed) {
+ break;
+ }
+
+ limit = (off_t) p->limit_rate * (ngx_time() - p->start_sec + 1)
+ - p->read_length;
+
+ if (limit <= 0) {
+ p->upstream->read->delayed = 1;
+ delay = (ngx_msec_t) (- limit * 1000 / p->limit_rate + 1);
+ ngx_add_timer(p->upstream->read, delay);
+ break;
+ }
+
+ } else {
+ limit = 0;
+ }
+
if (p->free_raw_bufs) {
/* use the free bufs if they exist */
break;
}
- n = p->upstream->recv_chain(p->upstream, chain, 0);
+ n = p->upstream->recv_chain(p->upstream, chain, limit);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe recv chain: %z", n);
}
}
+ delay = p->limit_rate ? (ngx_msec_t) n * 1000 / p->limit_rate : 0;
+
p->read_length += n;
cl = chain;
p->free_raw_bufs = NULL;
ln->next = p->free_raw_bufs;
p->free_raw_bufs = cl;
}
+
+ if (delay > 0) {
+ p->upstream->read->delayed = 1;
+ ngx_add_timer(p->upstream->read, delay);
+ break;
+ }
}
#if (NGX_DEBUG)
size_t preread_size;
ngx_buf_t *buf_to_file;
+ size_t limit_rate;
+ time_t start_sec;
+
ngx_temp_file_t *temp_file;
/* STUB */ int num;
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.force_ranges),
NULL },
+ { ngx_string("fastcgi_limit_rate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("fastcgi_cache"),
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges),
NULL },
+ { ngx_string("proxy_limit_rate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("proxy_cache"),
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
offsetof(ngx_http_scgi_loc_conf_t, upstream.force_ranges),
NULL },
+ { ngx_string("scgi_limit_rate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("scgi_cache"),
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.force_ranges),
NULL },
+ { ngx_string("uwsgi_limit_rate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, upstream.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("uwsgi_cache"),
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
p->downstream = c;
p->pool = r->pool;
p->log = c->log;
+ p->limit_rate = u->conf->limit_rate;
+ p->start_sec = ngx_time();
p->cacheable = u->cacheable || u->store;
ngx_http_upstream_process_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
+ ngx_event_t *rev;
+ ngx_event_pipe_t *p;
ngx_connection_t *c;
c = u->peer.connection;
+ p = u->pipe;
+ rev = c->read;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process upstream");
c->log->action = "reading upstream";
- if (c->read->timedout) {
- u->pipe->upstream_error = 1;
- ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
+ if (rev->timedout) {
+
+ if (rev->delayed) {
+
+ rev->timedout = 0;
+ rev->delayed = 0;
+
+ if (!rev->ready) {
+ ngx_add_timer(rev, p->read_timeout);
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
+ }
+
+ return;
+ }
+
+ if (ngx_event_pipe(p, 0) == NGX_ABORT) {
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
+ return;
+ }
+
+ } else {
+ p->upstream_error = 1;
+ ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
+ }
} else {
- if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
+
+ if (rev->delayed) {
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http upstream delayed");
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
+ }
+
+ return;
+ }
+
+ if (ngx_event_pipe(p, 0) == NGX_ABORT) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
size_t send_lowat;
size_t buffer_size;
+ size_t limit_rate;
size_t busy_buffers_size;
size_t max_temp_file_size;