Websocket's better support

Dridi Boukelmoune dridi at varni.sh
Thu Apr 20 17:17:34 CEST 2017


On Thu, Apr 20, 2017 at 9:57 AM,  <jonathan.huot at thomsonreuters.com> wrote:
> Hi Varnish dev & users,
>
> Websocket is (still) not dying, and for us, it seems we have to handle more and more this kind of traffic.
> It's why I would like to open a discussion and see how we can enhance the websocket support in Varnish.
>
> Currently, the implementation is done thru pipe like this :
>
> cli (Upgrade) -> recv -> pipe <--> backend
>
> So basically, we're putting the ball into backend's hands and nothing else.
> It has several disadvantages; one of them is that we cannot interact with the handshake's response which is still in HTTP/1.1.
> E.g. adding a set-cookie for stickiness is not possible.
> E.g. testing if status code is 101 is not possible
>
> So, first problem, first question: do you think it is possible to allow opening the pipe after vcl_backend_response ?
> The flow will be:
>
> cli (Upgrade) -> recv -> pass -> b_fetch -> b_response -> pipe <---> backend

It's not, but it's not the first time we discussed it:

https://github.com/varnishcache/varnish-cache/wiki/VIP8%3A-No-pipe-in-builtin.vcl-in-V5#discussion

See around 13:41.

You can emulate an "Expect: 100-continue" dance with the backend to at
least make sure an upgrade would be allowed before actually piping:

    varnishtest "websocket example"

    # Varnish won't let you use 100-continue so we need an ad-hoc solution
    # to ask the backend whether websocket is acceptable beforehand.

    server s1 {
        rxreq
        expect req.http.Connection == upgrade
        expect req.http.Upgrade == websocket
        expect req.http.Expect == 200-ok
        txresp

        rxreq
        expect req.http.Connection == upgrade
        expect req.http.Upgrade == websocket
        expect req.http.Expect == <undef>
        txresp -status 101 \
            -hdr "Connection: upgrade" \
            -hdr "Upgrade: websocket"

        send "pretend we do websocket here"
    } -start

    varnish v1 -vcl+backend {
        sub vcl_recv {
            if (req.restarts == 0) {
                unset req.http.Pipe;
                unset req.http.X-Upgrade;
            }
            if (req.http.Pipe) {
                set req.http.Upgrade = req.http.X-Upgrade;
                return (pipe);
            }
            elsif (req.http.Connection == "upgrade") {
                set req.http.X-Upgrade = req.http.Upgrade;
                return (pass);
            }
        }

        sub vcl_backend_fetch {
            if (bereq.http.X-Upgrade) {
                set bereq.http.Connection = "upgrade";
                set bereq.http.Upgrade = bereq.http.X-Upgrade;
                set bereq.http.Expect = "200-ok";
                unset bereq.http.X-Upgrade;
            }
        }

        sub vcl_backend_response {
            if (bereq.http.Upgrade && beresp.status == 200) {
                set beresp.http.Pipe = bereq.http.Upgrade;
                return (deliver);
            }
        }

        sub vcl_deliver {
            if (resp.http.Pipe) {
                set req.http.Pipe = resp.http.Pipe;
                return (restart);
            }
        }
    } -start

    client c1 {
        txreq -hdr "Connection: upgrade" -hdr "Upgrade: websocket"
        rxresp
        expect resp.status == 101

        # receive the fake websocket traffic
        recv 28

        # this will fail because there isn't anything left to read
        # recv 1
    } -run

This example is over-simplified, it only shows that you can act upon
websocket requests. That doesn't solve the fact that you don't have
access to the beresp once you return pipe.

> Only this extra step would be a huge improvement of what we can do on websockets connections and will be very beneficial.
>
>
> Then, a bonus question, cuz it requires probably much more time:
> I was wondering if later, websocket protocol can be integrated to the core (e.g. similarly to HTTP2?), to have benefits of metrics, params and logs.
> Because, No, websocket messages are not just "bytes thru a pipe" :-)

Well, websocket is not HTTP, unlilke... HTTP/2? I don't think it would
fit nicely in VCL, applications do what they want on top of the
session. Unlike HTTP that specifies what happens on the session, we
couldn't make more assumption than bytes passing through.

Dridi



More information about the varnish-misc mailing list