cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: better handling of websocket protocol upgrades

From: Daniel Stenberg <daniel_at_haxx.se>
Date: Sat, 25 Jul 2015 01:03:27 +0200 (CEST)

On Thu, 23 Jul 2015, Frank Meier wrote:

> After some reading, the approach to use websockets with libcurl seems to be
> to let libcurl only establish the connection with CURLOPT_CONNECT_ONLY and
> then use curl_easy_send() and curl_easy_recv() on the easy_handle. This
> means to send and receive the HTTP headers also with this functions.

If you insist on using libcurl for this, then I think that is at least a way
you _can_ do it.

> My understanding is that there is no way to let libcurl handle the HTTP
> Upgrade itself, and then takeover the connection. At least not with the
> multi-interface.

Correct.

> I tried to let the HTTP request and response be handled "normally" by
> setting up the request parameters (url, headers, ...) on the easy_handle and
> use curl_multi_perform() to work it's magic. And when the response-headers
> were received (and the upgrade conditions were met) pause (CURLPAUSE_ALL)
> and set CURLOPT_CONNECT_ONLY on the easy_handle and then use
> curl_easy_send() and _recv(). But this fails with "Unsupported protocol"
> Error. The reason is, that Curl_getconnectinfo() will not retrieve the
> current socket, since "data->state.lastconnect" is not set yet.
>
> Am I right with this analysis, or did I just do something wrong?

I haven't fully looked through the code path for this approach but it seems
reasonable. And even if you made it work, it's not really a documented way to
do it and we don't test for it so it would be a rather fragile method that
could break in a future release.

> If Curl_getconnectinfo() would not not just care about "lastconnect" socket,
> but also would retrieve the connection that is actually being used, my
> approach would work. This was suggested in
> https://github.com/bagder/curl/pull/86, but was never merged.

That change alone would not make this a reliable method. You need to write
documentation and test cases too. And I think I would be fine with it, it
seems like an easy change that shouldn't break anything existing.

> So I came up with the Idea to handle the upgrade of the connection inside
> libcurl, and then use the READ and WRITEFUNCTION callbacks to handle the
> websocket communication. I came up with quite a small "prove of concept"
> (patch attached) to show were I'm heading. If you think this is the right
> way to go, I would be able to write a more conclusive patch.

It'd need to be more than that (like for example we always need to wait for
the socket to be BOTH readable and writable since we don't know the protocol
and that seems like a hard nut to crack or you need to signal that somehow)
and I'm also interested in how you imagine the API for enabling/controlling
this. I'm slightly scared that allowing this is the first step on a slippery
slope and that we will soon find out that it isn't enough to do good
websockets anyway unless we also do something else that is more intrusive.

And I'll again mention that we need test cases if we are to consider doing
this.

-- 
  / daniel.haxx.se
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2015-07-25