Opened 7 years ago

Closed 7 years ago

#325 closed defect (fixed)

websocket doesn't work when using unix socket for proxy_pass

Reported by: Avétis Kazarian Owned by: Maxim Dounin
Priority: minor Milestone: 1.3
Component: nginx-core Version: 1.3.x
Keywords: Cc:
uname -a: Darwin mahaprabhu.local 12.3.0 Darwin Kernel Version 12.3.0: Sun Jan 6 22:37:10 PST 2013; root:xnu-2050.22.13~1/RELEASE_X86_64 x86_64 i386 MacBookPro10,1 Darwin
nginx -V: nginx version: nginx/1.3.14
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/nginx/1.3.14 --with-http_ssl_module --with-pcre --with-ipv6 --with-cc-opt=-I/usr/local/include --with-ld-opt=-L/usr/local/lib --conf-path=/usr/local/etc/nginx/nginx.conf --pid-path=/usr/local/var/run/nginx.pid --lock-path=/usr/local/var/run/nginx.lock --http-client-body-temp-path=/usr/local/var/run/nginx/client_body_temp --http-proxy-temp-path=/usr/local/var/run/nginx/proxy_temp --http-fastcgi-temp-path=/usr/local/var/run/nginx/fastcgi_temp --http-uwsgi-temp-path=/usr/local/var/run/nginx/uwsgi_temp --http-scgi-temp-path=/usr/local/var/run/nginx/scgi_temp

Description

I don't know if it's something to be excepted or if it's really a bug.

My conf (in a server {}):

location ~ /socket {
  proxy_pass http://unix:/tmp/app.socket;
  proxy_http_version 1.1;
  proxy_set_header Upgrade "websocket";
  proxy_set_header Connection "upgrade";
}

error.log:

2013/03/26 15:25:11 [alert] 21581#0: *3457 
setsockopt(TCP_NODELAY) failed 
(102: Operation not supported on socket) while proxying upgraded connection, 
client: 127.0.0.1, 
server: localhost, 
request: "GET /socket/230/5o96b2yn/websocket HTTP/1.1",
upstream: "http://unix:/tmp/app.socket:/socket/230/5o96b2yn/websocket", 
host: "localhost"

It works perfectly fine if I replace proxy_pass http://unix:/tmp/app.socket; with proxy_pass http://127.0.0.1:9000; (and make accordingly the change on my socket server to listen on port 9000).

Change History (3)

comment:1 by Maxim Dounin, 7 years ago

Owner: set to Maxim Dounin
Status: newassigned

The following patch should fix this:

# HG changeset patch
# User Maxim Dounin <mdounin@mdounin.ru>
# Date 1364312044 -14400
# Node ID 51a7e8aaeb1d9792971c6d0d2d7062829ea15356
# Parent  8202d09ccee90004ce748a34f972c7a3e15ab49c
Upstream: fixed tcp_nodelay use (ticket #325).

diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2413,32 +2413,39 @@ ngx_http_upstream_upgrade(ngx_http_reque
     r->read_event_handler = ngx_http_upstream_upgraded_read_downstream;
     r->write_event_handler = ngx_http_upstream_upgraded_write_downstream;
 
-    if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
-
+    if (clcf->tcp_nodelay) {
         tcp_nodelay = 1;
 
-        if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
-                       (const void *) &tcp_nodelay, sizeof(int)) == -1)
-        {
-            ngx_connection_error(c, ngx_socket_errno,
-                                 "setsockopt(TCP_NODELAY) failed");
-            ngx_http_upstream_finalize_request(r, u, 0);
-            return;
+        if (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)
+            {
+                ngx_connection_error(c, ngx_socket_errno,
+                                     "setsockopt(TCP_NODELAY) failed");
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+            c->tcp_nodelay = NGX_TCP_NODELAY_SET;
         }
 
-        c->tcp_nodelay = NGX_TCP_NODELAY_SET;
-
-        if (setsockopt(u->peer.connection->fd, IPPROTO_TCP, TCP_NODELAY,
-                       (const void *) &tcp_nodelay, sizeof(int)) == -1)
-        {
-            ngx_connection_error(u->peer.connection, ngx_socket_errno,
-                                 "setsockopt(TCP_NODELAY) failed");
-            ngx_http_upstream_finalize_request(r, u, 0);
-            return;
+        if (u->peer.connection->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->peer.connection->log, 0,
+                           "tcp_nodelay");
+
+            if (setsockopt(u->peer.connection->fd, IPPROTO_TCP, TCP_NODELAY,
+                           (const void *) &tcp_nodelay, sizeof(int)) == -1)
+            {
+                ngx_connection_error(u->peer.connection, ngx_socket_errno,
+                                     "setsockopt(TCP_NODELAY) failed");
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+            u->peer.connection->tcp_nodelay = NGX_TCP_NODELAY_SET;
         }
-
-        u->peer.connection->tcp_nodelay = NGX_TCP_NODELAY_SET;
     }
 
     if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {

(Just in case if it's not clear, an obvious workaround would be switch off tcp_nodelay directive.)

comment:2 by Maxim Dounin, 7 years ago

In 5143/nginx:

(The changeset message doesn't reference this ticket)

comment:3 by Maxim Dounin, 7 years ago

Resolution: fixed
Status: assignedclosed

Fix committed, thanks for your report.

Note: See TracTickets for help on using tickets.