Description
I did this
I am trying to implement a websocket abstraction in C++ with CURL. The goal is to manage a lot of connection (>100), therefore I am using a multi-handle to manage many easy-handles. On my journey I found the following problems which are a mix of bugs / inconvenient behavior / missing features.
-
Because I am using Multi-Handles, I need to be able receive an asynchronous
onOpen
-event in order to know when the websocket connection is established. CURL does not provide such an event.
I am going for Model 1 using aWRITEFUNCTION
to keep things asynchronous. Model 1 does not describe how I send data, therefore i am defaulting tocurl_ws_send
. I also cannot useCURLOPT_CONNECT_ONLY
as this would be "Model 2". When connecting, I send my own header to let it connect and switch protocols; then parse the incoming protocol-switch response myself (using theHEADERFUNCTION
). When receiving the empty-line (end of header), i can generate anonOpen()
event myself. However, since my call-context is in theHEADERFUNCTION
, i cant directly invoke theonOpen
event handler from there, becauseonOpen
could want to send data. For some reasoncurl_ws_send()
does not work from within theHEADERFUNCTION
-context. According to the documentation of curl_ws_send it should be possible to usecurl_ws_send
from within a callback. The error code is however consistentlyCURLE_SEND_ERROR
. -
This leads to the next issue: there is no method to send a message to the main-loop /
curl_multi_info_read()
in order to trigger operations associated with a certain easy-handle that cant be directly executed from within a callback. This leads to state-management outside of the curl control flow which is always messy. It would be nice to be able to trigger a special message that is notCURLMSG_DONE
. (with custom data in themessage.data.whatever
field) -
Within the
WRITEFUNCTION
,curl_ws_meta()
never setsCURLWS_CONT
for partial messages. When I receive a large response (>100kb) theWRITEFUNCTION
trickles in the data in ~4kb chunks. According to the documentation of curl_ws_metaCURLWS_CONT
should be set for all but the last data chunk. This is not the case. -
I am not sure about this one - it may be a CURL-problem or a me-problem, due to lack of references. But while my websocket implementation generally works, it fails to connect to a certain host which always responds with
502 (Bad Gateway)
instead of101 (Protocol switch)
. This particular host is only reachable if I connect viahttps://....
instead ofwss://....
. When using https, the protocol switch is accepted successfully by the host. However under this URL,curl_ws_send()
fails consistently withCURLE_SEND_ERROR
. I think this may be caused by a violation of Setup where the websocket-part of CURL is not activated because I cant use thewss://
-prefix (??)
IF that is the case, I find that design decision highly disturbing, because I can, at any point, assemble my own header that asks for a protocol switch - I therefore need an option for the easy-handle to turn on websocket features at will, independently of the URL I connect to. This is a decision between me and the server, not CURLs background state management. I hope that makes sense.
Again, this could be my fault, so it would be nice if someone (who knows the internals) could confirm this behavior.
curl/libcurl version
curl 8.13.0
operating system
Linux 6.14.6-2-MANJARO