summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2015-03-23 21:04:13 +0300
committerValentin Bartenev <vbart@nginx.com>2015-03-23 21:04:13 +0300
commit0e853129ac857bef8d8553a0f90156bb7bd22fb3 (patch)
tree3be8c738bad3636044aaf3e7ea73bf645534a66f
parent44586bf5ee34a56f877ab04dc79fed279e1d52cb (diff)
downloadnginx-0e853129ac857bef8d8553a0f90156bb7bd22fb3.tar.gz
SPDY: always push pending data.
This helps to avoid suboptimal behavior when a client waits for a control frame or more data to increase window size, but the frames have been delayed in the socket buffer. The delays can be caused by bad interaction between Nagle's algorithm on nginx side and delayed ACK on the client side or by TCP_CORK/TCP_NOPUSH if SPDY was working without SSL and sendfile() was used. The pushing code is now very similar to ngx_http_set_keepalive().
-rw-r--r--src/http/ngx_http_spdy.c91
1 files changed, 40 insertions, 51 deletions
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index c35c31a18..6bb79b88b 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -662,6 +662,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
ngx_int_t
ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
{
+ int tcp_nodelay;
ngx_chain_t *cl;
ngx_event_t *wev;
ngx_connection_t *c;
@@ -710,6 +711,44 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
goto error;
}
+ if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
+ if (ngx_tcp_push(c->fd) == -1) {
+ ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");
+ goto error;
+ }
+
+ c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
+ tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
+
+ } else {
+ tcp_nodelay = 1;
+ }
+
+ if (tcp_nodelay
+ && clcf->tcp_nodelay
+ && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
+ {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
+
+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+ (const void *) &tcp_nodelay, sizeof(int))
+ == -1)
+ {
+#if (NGX_SOLARIS)
+ /* Solaris returns EINVAL if a socket has been shut down */
+ c->log_error = NGX_ERROR_IGNORE_EINVAL;
+#endif
+
+ ngx_connection_error(c, ngx_socket_errno,
+ "setsockopt(TCP_NODELAY) failed");
+
+ c->log_error = NGX_ERROR_INFO;
+ goto error;
+ }
+
+ c->tcp_nodelay = NGX_TCP_NODELAY_SET;
+ }
+
if (cl) {
ngx_add_timer(wev, clcf->send_timeout);
@@ -3321,10 +3360,8 @@ ngx_http_spdy_close_stream_handler(ngx_event_t *ev)
void
ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
{
- int tcp_nodelay;
ngx_event_t *ev;
- ngx_connection_t *c, *fc;
- ngx_http_core_loc_conf_t *clcf;
+ ngx_connection_t *fc;
ngx_http_spdy_stream_t **index, *s;
ngx_http_spdy_srv_conf_t *sscf;
ngx_http_spdy_connection_t *sc;
@@ -3350,54 +3387,6 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
{
sc->connection->error = 1;
}
-
- } else {
- c = sc->connection;
-
- if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
- if (ngx_tcp_push(c->fd) == -1) {
- ngx_connection_error(c, ngx_socket_errno,
- ngx_tcp_push_n " failed");
- c->error = 1;
- tcp_nodelay = 0;
-
- } else {
- c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
- tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
- }
-
- } else {
- tcp_nodelay = 1;
- }
-
- clcf = ngx_http_get_module_loc_conf(stream->request,
- ngx_http_core_module);
-
- if (tcp_nodelay
- && clcf->tcp_nodelay
- && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
- {
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
-
- if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
- (const void *) &tcp_nodelay, sizeof(int))
- == -1)
- {
-#if (NGX_SOLARIS)
- /* Solaris returns EINVAL if a socket has been shut down */
- c->log_error = NGX_ERROR_IGNORE_EINVAL;
-#endif
-
- ngx_connection_error(c, ngx_socket_errno,
- "setsockopt(TCP_NODELAY) failed");
-
- c->log_error = NGX_ERROR_INFO;
- c->error = 1;
-
- } else {
- c->tcp_nodelay = NGX_TCP_NODELAY_SET;
- }
- }
}
if (sc->stream == stream) {