WebSocket: with CURLWS_NOAUTOPONG, incoming zero-payload PING is neither delivered to WRITEFUNCTION nor auto-responded (8.14.1)
I did this
Mode: multi + write-callback (not CONNECT_ONLY), CURLOPT_WS_OPTIONS = CURLWS_NOAUTOPONG Server: wss://zello.io/ws (servers sends PING with payload=0)
Observed: When the server sends a WebSocket PING with payload length 0, libcurl does not invoke the CURLOPT_WRITEFUNCTION at all (so curl_ws_meta() can’t be used). Since CURLWS_NOAUTOPONG is set, libcurl does not auto-reply either. The application has no way to learn about the PING in the write-callback model and cannot send PONG; the server disconnects.
I expected the following
If CURLWS_NOAUTOPONG is set, libcurl should always deliver PING to the application — even with len==0 — e.g. by calling the write callback with size*nmemb==0 and curl_ws_meta()->flags & CURLWS_PING, or provide an officially supported non-blocking way to retrieve such control frames in the write-callback model.
curl/libcurl version
curl 8.14.1 (x86_64-pc-linux-gnu) libcurl/8.14.1 OpenSSL/3.5.1 zlib/1.3.1 brotli/1.1.0 zstd/1.5.7 libidn2/2.3.8 libpsl/0.21.2 libssh2/1.11.1 nghttp2/1.64.0 nghttp3/1.8.0 librtmp/2.3 OpenLDAP/2.6.10 Release-Date: 2025-06-04, security patched: 8.14.1-2 Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp ws wss Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTP3 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP UnixSockets zstd
operating system
Linux a 6.12.38+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.38-1 (2025-07-16) x86_64 GNU/Linux
It also seems like CURLOPT_WRITEFUNCTION doesn’t handle empty CURLWS_PONG
@cyanide-burnout we improved curl's websocket in fa3baabbd81ab9f0aa50bc6335a3e315be0e3009, which has been released in curl 8.16.0. Could you check with a recent curl? Best would be 8.17 or the master branch.
As to sending PONG replies, this indeed cannot be done from the WRITEFUNCTION. You would need to add a READFUNCTION and use the new curl_ws_start_frame() from there. See https://curl.se/libcurl/c/curl_ws_start_frame.html