summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2014-11-21 22:51:49 +0300
committerValentin Bartenev <vbart@nginx.com>2014-11-21 22:51:49 +0300
commit4dafec8d514a685f1da0d097f53313b53e0c759a (patch)
treeceb7ebc9fac4d27582e8d35c44aba2863fdf50dd
parent1f9564223bc8073e08537526dfdfbb8b5087a5a3 (diff)
downloadnginx-4dafec8d514a685f1da0d097f53313b53e0c759a.tar.gz
nginx-4dafec8d514a685f1da0d097f53313b53e0c759a.tar.bz2
SPDY: push pending data while closing a stream as with keepalive.
This helps to avoid delays in sending the last chunk of data because of bad interaction between Nagle's algorithm on nginx side and delayed ACK on the client side. Delays could also be caused by TCP_CORK/TCP_NOPUSH if SPDY was working without SSL and sendfile() was used.
-rw-r--r--src/http/ngx_http_spdy.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index 9bd624c82..bd6d73d82 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -3156,8 +3156,10 @@ 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 *fc;
+ ngx_connection_t *c, *fc;
+ ngx_http_core_loc_conf_t *clcf;
ngx_http_spdy_stream_t **index, *s;
ngx_http_spdy_srv_conf_t *sscf;
ngx_http_spdy_connection_t *sc;
@@ -3183,6 +3185,54 @@ 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) {