[Libwebsockets] lws_client_connect_via_info() - protocol 0 handler

Andy Green andy at warmcat.com
Wed Feb 15 13:54:43 CET 2017

On 02/15/2017 08:38 PM, Denis Osvald wrote:
> On 2017-02-15 12:11, Andy Green wrote:
>> On 02/15/2017 06:55 PM, Denis Osvald wrote:
>>> On 2017-02-15 10:46, Andy Green wrote:
>>>> On 02/15/2017 05:31 PM, Denis Osvald wrote:
>>>>> On 2017-02-15 02:18, Andy Green wrote:
>>>>>> On 02/15/2017 01:50 AM, Joel Winarske wrote:
>>>>> [...]
>>>>>> That doesn't mean much though since it knows it will generate
>>>>>> callbacks
>>>>>> in the process of connecting, and when no better protocol is
>>>>>> capable of
>>>>>> being selected (because for ws it must be negotiated with the server),
>>>>>> lws uses protocols[0] for want of anything better in many places.
>>>>>> Client connections were until recently all ws/wss, for that this will
>>>>>> work fine since the protocol is negotiated and selected later.
>>>>>> For HTTP[S] client until now no code to allow forcing the protocol
>>>>>> selection... that works fine with all on protocols[0] in "by hand"
>>>>>> code
>>>>>> like the original test server.  But being able to target a specific
>>>>>> plugin / protocol handler by name makes a lot more sense inside lwsws.
>>>>>> Please try this
>>>>>> https://github.com/warmcat/libwebsockets/commit/d23cb338654c423e74c0b0160ba275e9a57c0070
>>>>>> pushed on master just now.
>>>>>> Set the info .vhost, the protocol name you want on that vhost in the
>>>>>> info .protocol and there should be an info.method set already
>>>>>> indicating
>>>>>> http GET or whatever.  Then it will attempt to select the protocol
>>>>>> from
>>>>>> the vhost early in the connection action.
>>>>> Hmm, I don't seem to get what this change does exactly. Would
>>>>> protocols[0] still be called for things like:
>>>>> - FD / extpoll stuff
>>>>> - extra SSL info callbacks
>>>>> - client connection error (CCE)
>>>>> - callbacks before we know we'll upgrade to ws(s)
>>>>> - callbacks after we've upgraded to ws(s)
>>>>> - callbacks after we know no upgrade to ws(s) will happen
>>>>> (Does the last type of client callback even exist?)
>>>>> In other words, what callback reasons are moved from protocols[0] to
>>>>> the
>>>>> selected-by-name protocol callback?
>>>> Absolutely none, unless in the client connect info:
>>>>    - you gave a method, like "GET"
>>>>    - you gave a vhost
>>>>    - you gave a protocol name
>>>> Normally, giving a protocol name along with a method has no meaning,
>>>> since until now the protocol name was only used by ws[s] processing and
>>>> giving the method means you are doing HTTP[S] processing.  So *no
>>>> existing code meets these criteria*.
>>>> If you do give those things in the connect info, the callback for most
>>>> http things is the one in the named protocol.  But you have had to go
>>>> out of your way to ask for that on your http client connection info.
>>>> And in client-on-lwsws, that is what you want since you have control
>>>> over the plugin and can handle his http client messages there.
>>>> For extpoll, the stuff that calls that explicitly uses protocols[0], so
>>>> it's unaffected.
>>>> This can't affect anything related to ws[s] client connections, because
>>>> the precondition of the method being set means we are not doing ws[s].
>>>> Make sense?
>>> Yes, that's good to hear.
>>> So just to confirm my understanding, we could have always done:
>>> - method=NULL, vhost=..., protocol="abc"
>>>     -> we want websocket protocol "abc" through "abc" protocol cb
>>> - method="GET", vhost=..., protocol=NULL
>>>     -> we want plain HTTP GET (no upgrade) through protocols[0] cb
>> Right
>>> With the new change we can also do:
>>> - method="GET", vhost=..., protocol="abc"
>>>     -> we want plain HTTP GET (no upgrade) through "abc" protocol cb
>> Yes with the addition it's specifically protocol "abc" on the given
>> vhost.  With per-vhost options, the same protocol / plugin may be
>> configured to do something different on another vhost (act on a
>> different local directory etc).
> Good.
>>> Did I get this right?
>>> A tangentially related question - is it possible somehow to say "I want
>>> to use xyz protocol cb, and upgrade to WS if possible, otherwise stay
>>> with plain HTTP client connection" (i'm almost sure that the answer is
>>> no, and that this should be done in a separate connect attempt when I
>>> know that WS won't work for whatever reason)?
>> Theoretically, both sides stay in http if the upgrade didn't succeed.
>> But practically, lws treats that as fatal.
>> At the moment although it knows how to do it, and does do it for server,
>> there are no arrangements for pipelining client transactions in lws.
>> Each client transaction is a new connection.
> Do you think that's a reasonably valid use case?

If lws supported client pipelining it would be legal afaik.  You would 
get something like 4xx http response to the upgrade if no ws possible, 
but then nobody upgraded so it's still HTTP.  If lws allowed the same 
"transaction_completed" -> idle behaviour it does for server, the 
connection would remain sane and live and able to take another transaction.

lws client code would have to stop hanging up after controlled failure 
HTTP responses and instead do the "transaction completed" processing 
like server does.  That mainly resets the ah if something was pipelined 
or detaches the ah if a new request hasn't come (it should queue for a 
new one when one is free and something came that needs it... this stuff 
already exists for server).

> I have a websocket-enabled application as a backend where previously
> HTTP POST was used. Now I'm exploring the possibilities of having a
> legacy-compatible client, or server. For server, lws supports everything
> AFAIK except HTTP is always in protocols[0]. I imagine it would be
> reasonable if the same protocol callback could be used for both, with
> just the opcode in lws_write different, and of course with different
> connection lifetimes.
> Any thoughts?

Eventually it should be added that you can pass an existing, 
transaction-completed wsi in to the next client connect info (not in 
*pwsi though because existing users don't take care to initialize the 
thing they point it at to NULL; it'd have to be a new member).

When you did that, instead of doing the connect it will bypass all that 
and arrive straight at the part that generates the request headers as 
the "next transaction" on the existing wsi.

However I don't have time to look at it for a while... the ESP32 port 
and the gzip stuff will use up all my free time.


>> -Andy
>>>> -Andy
>>>>> Regards,
>>>>> Denis Osvald
>>>>>> -Andy
>>>>>>> Thanks,
>>>>>>> Joel
>>>>>>> _______________________________________________
>>>>>>> Libwebsockets mailing list
>>>>>>> Libwebsockets at ml.libwebsockets.org
>>>>>>> https://libwebsockets.org/mailman/listinfo/libwebsockets
>>>>>> _______________________________________________
>>>>>> Libwebsockets mailing list
>>>>>> Libwebsockets at ml.libwebsockets.org
>>>>>> https://libwebsockets.org/mailman/listinfo/libwebsockets
>>>>> _______________________________________________
>>>>> Libwebsockets mailing list
>>>>> Libwebsockets at ml.libwebsockets.org
>>>>> https://libwebsockets.org/mailman/listinfo/libwebsockets

More information about the Libwebsockets mailing list