Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#582 closed defect (invalid)

WebSocket disconnection not detected by Chrome

Reported by: Iñaki Baz Castillo Owned by:
Priority: minor Milestone:
Component: other Version: 1.4.x
Keywords: WebSocket Cc:
uname -a: Linux dev-nginx-1 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.4.7
built by gcc 4.7.2 (Debian 4.7.2-5)
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_spdy_module --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,--as-needed' --with-ipv6

Description

This issue is also reported in Chromium site (given that, at the end, I'm pretty sure it is a bug on Chrome):

https://code.google.com/p/chromium/issues/detail?id=388243&thanks=388243&ts=1403619302

Steps to reproduce the problem

  1. Open a wss:// connection to a NGINX server which dispatches the connection using plain WS to a server behind it.
  2. Close/kill the server.
  3. NGINX sends WS Close message followed by a TCP FIN.

What is the expected behavior?

Chrome should send a TCP FIN and fire "onclose" event for the WebSocket connection (as Firefox 30 does).

What went wrong?

Chrome does not send a TCP FIN and does not fire "onclose" event.

TCP connection remains in CLOSE_WAIT state and the WebSocket.readyState is still OPEN.

Of course, attempting to write on the WebSocket does not (immediately) fail and, of course, the message does not arrive to NGINX who already closed its pipe side.

This happens mostly in OSX (in Windows it seems to fail randomly).

  • Chrome version: 35.0.1916.153 Channel: stable
  • OS Version: OS X 10.9.3

tcpdump output

This is a tcpdump (running in OSX where Chrome runs) capturing the traffic between Chrome and NGINX in the exact moment in which the server behind NGINX is killed (note that the TCP connection, both sides, is correctly closed between NGINX and the server). The tcpdump between Chrome and NGINX:

14:08:25.738982 IP NGINX > CHROME: Flags [P.], seq 391:444, ack 1462, win 528, options [nop,nop,TS val 17630239 ecr 886915943], length 53
14:08:25.739062 IP CHROME > NGINX: Flags [.], ack 444, win 8244, options [nop,nop,TS val 886932539 ecr 17630239], length 0
14:08:25.739483 IP NGINX > CHROME: Flags [F.], seq 444, ack 1462, win 528, options [nop,nop,TS val 17630239 ecr 886915943], length 0
14:08:25.739519 IP CHROME > NGINX: Flags [.], ack 445, win 8244, options [nop,nop,TS val 886932539 ecr 17630239], length 0
[ nothing else ]

I'm pretty sure the first packet from NGINX is a WS Close message (see below). After this TCP exchange a lsof -i -n -P in OSX shows the TCP connection between Chrome and NGINX in CLOSE_WAIT state.

The following tcpdump (same environment) happens when the browser is Firefox 30:

16:12:05.194648 IP NGINX > FIREFOX: Flags [P.], seq 4290:4343, ack 943, win 542, options [nop,nop,TS val 19485142 ecr 894311035], length 53
16:12:05.194727 IP FIREFOX > NGINX: Flags [.], ack 4343, win 8188, options [nop,nop,TS val 894329403 ecr 19485142], length 0
16:12:05.194925 IP FIREFOX > NGINX: Flags [F.], seq 943, ack 4343, win 8192, options [nop,nop,TS val 894329403 ecr 19485142], length 0
16:12:05.194984 IP NGINX > FIREFOX: Flags [F.], seq 4343, ack 943, win 542, options [nop,nop,TS val 19485142 ecr 894311035], length 0
16:12:05.341083 IP NGINX > FIREFOX: Flags [.], ack 944, win 542, options [nop,nop,TS val 19485179 ecr 894329403], length 0
16:12:05.341152 IP FIREFOX > NGINX: Flags [.], ack 4343, win 8192, options [nop,nop,TS val 894329548 ecr 19485142], length 0
16:12:05.756566 IP NGINX > FIREFOX: Flags [F.], seq 4343, ack 944, win 542, options [nop,nop,TS val 19485275 ecr 894329548], length 0
16:12:05.756618 IP FIREFOX > NGINX: Flags [.], ack 4344, win 8192, options [nop,nop,TS val 894329962 ecr 19485275], length 0

Note that after the first packet from NGINX, Firefox sends a TCP FIN so I'm pretty sure that it is because it has received a WS Close message.

Change History (4)

comment:1 by Maxim Dounin, 6 years ago

Resolution: invalid
Status: newclosed

From the description it's clear that there is no problem in nginx.

comment:2 by Iñaki Baz Castillo, 6 years ago

Sure. May you please just confirm me that, in the above case (this is: the WS server behind Nginx closes a WS connection) then Nginx will first send a WS Close message and then a TCP FIN?

Thanks a lot.

comment:3 by Maxim Dounin, 6 years ago

As long as a backend will send Close frame, nginx will forward it before closing the connection. It just passes along whatever is send by the backend.

In this particular case, I suspect that the 53 bytes packet isn't Close frame, but rather an SSL close_notify alert. Anyway, instead of asking for confirmations, it's better to check what's on the wire using tcpdump / wireshark.

comment:4 by Iñaki Baz Castillo, 6 years ago

You are right, it is the SSL alert.
Thanks a lot.

Note: See TracTickets for help on using tickets.