# HG changeset patch # User Valentin Bartenev # Date 1389702285 -14400 # Node ID 311803b21504290dd9f60579b09a95f31731322a # Parent 9fffc0c46e5c275428d04798cc6a531951e79630 SPDY: body filter was replaced by c->send_chain() function. It allows to use ngx_http_write_filter() and all its rate limiting logic. diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -112,6 +112,7 @@ typedef enum { #define NGX_LOWLEVEL_BUFFERED 0x0f #define NGX_SSL_BUFFERED 0x01 +#define NGX_SPDY_BUFFERED 0x02 struct ngx_connection_s { @@ -171,6 +172,8 @@ struct ngx_connection_s { unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */ unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ + unsigned need_last_buf:1; + #if (NGX_HAVE_IOCP) unsigned accept_context_updated:1; #endif diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c --- a/src/http/ngx_http_spdy_filter_module.c +++ b/src/http/ngx_http_spdy_filter_module.c @@ -14,8 +14,6 @@ #include -#define NGX_SPDY_WRITE_BUFFERED NGX_HTTP_WRITE_BUFFERED - #define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1) #define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1) @@ -29,6 +27,10 @@ #define ngx_http_spdy_nv_write_val(p, h) \ ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1) + +static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc, + ngx_chain_t *in, off_t limit); + static ngx_inline ngx_int_t ngx_http_spdy_filter_send( ngx_connection_t *fc, ngx_http_spdy_stream_t *stream); @@ -82,7 +84,6 @@ ngx_module_t ngx_http_spdy_filter_modul static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t @@ -607,41 +608,35 @@ ngx_http_spdy_header_filter(ngx_http_req stream->queued = 1; + c->send_chain = ngx_http_spdy_send_chain; + c->need_last_buf = 1; + return ngx_http_spdy_filter_send(c, stream); } -static ngx_int_t -ngx_http_spdy_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +static ngx_chain_t * +ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) { off_t size; ngx_buf_t *b; ngx_chain_t *cl, *out, **ln; - ngx_connection_t *fc; + ngx_http_request_t *r; ngx_http_spdy_stream_t *stream; ngx_http_spdy_out_frame_t *frame; + r = fc->data; stream = r->spdy_stream; - if (stream == NULL) { - return ngx_http_next_body_filter(r, in); - } - - fc = r->connection; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "spdy body filter \"%V?%V\"", &r->uri, &r->args); - - if (in == NULL || r->header_only) { + if (in == NULL) { if (stream->queued) { fc->write->delayed = 1; - return NGX_AGAIN; + } else { + fc->buffered &= ~NGX_SPDY_BUFFERED; } - fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED; - - return NGX_OK; + return NULL; } size = 0; @@ -649,28 +644,10 @@ ngx_http_spdy_body_filter(ngx_http_reque do { b = in->buf; -#if 1 - if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) { - ngx_log_error(NGX_LOG_ALERT, fc->log, 0, - "zero size buf in spdy body filter " - "t:%d r:%d f:%d %p %p-%p %p %O-%O", - b->temporary, - b->recycled, - b->in_file, - b->start, - b->pos, - b->last, - b->file, - b->file_pos, - b->file_last); - ngx_debug_point(); - return NGX_ERROR; - } -#endif cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { - return NGX_ERROR; + return NGX_CHAIN_ERROR; } size += ngx_buf_size(b); @@ -686,20 +663,24 @@ ngx_http_spdy_body_filter(ngx_http_reque if (size > NGX_SPDY_MAX_FRAME_SIZE) { ngx_log_error(NGX_LOG_ALERT, fc->log, 0, "FIXME: chain too big in spdy filter: %O", size); - return NGX_ERROR; + return NGX_CHAIN_ERROR; } frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size, out, cl); if (frame == NULL) { - return NGX_ERROR; + return NGX_CHAIN_ERROR; } ngx_http_spdy_queue_frame(stream->connection, frame); stream->queued++; - return ngx_http_spdy_filter_send(fc, stream); + if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + return NULL; } @@ -801,12 +782,12 @@ ngx_http_spdy_filter_send(ngx_connection stream->blocked = 0; if (stream->queued) { - fc->buffered |= NGX_SPDY_WRITE_BUFFERED; + fc->buffered |= NGX_SPDY_BUFFERED; fc->write->delayed = 1; return NGX_AGAIN; } - fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED; + fc->buffered &= ~NGX_SPDY_BUFFERED; return NGX_OK; } @@ -939,20 +920,22 @@ static ngx_inline void ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream) { - ngx_connection_t *fc; - - fc = stream->request->connection; - - fc->write->delayed = 0; + ngx_event_t *wev; if (stream->handled || stream->blocked) { return; } - stream->handled = 1; + wev = stream->request->connection->write; + + if (!wev->timer_set) { + wev->delayed = 0; - stream->next = sc->last_stream; - sc->last_stream = stream; + stream->handled = 1; + + stream->next = sc->last_stream; + sc->last_stream = stream; + } } @@ -994,8 +977,5 @@ ngx_http_spdy_filter_init(ngx_conf_t *cf ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_spdy_header_filter; - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_spdy_body_filter; - return NGX_OK; } diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -184,7 +184,10 @@ ngx_http_write_filter(ngx_http_request_t return NGX_AGAIN; } - if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) { + if (size == 0 + && !(c->buffered & NGX_LOWLEVEL_BUFFERED) + && !(last && c->need_last_buf)) + { if (last || flush) { for (cl = r->out; cl; /* void */) { ln = cl;