Skip to content

Proposal: prefix-less websocket control via new frame type via http-over-websocket extensions #48289

@ethanniser

Description

@ethanniser

Currently to use websocket-over-http with GRIP, you must negotiate the grip websocket extension which needs a way to distinguish normal messages (which should be sent to clients) and "control" messages, which instruct the gateway to take certain actions associated with the connection.

Currently this is done by the proxy and server agreeing on a message prefix for each message type (by default m: and c:)

via websocket text frame

m:this is a normal message
c:{"type": "subscribe", "channel": "mychannel"}

via websocket-over-http

HTTP/1.1 200 OK
Content-Type: application/websocket-events

TEXT 2F\r\n
m:this is a normal message
TEXT 2F\r\n
c:{"type": "subscribe", "channel": "mychannel"}\r\n

While for most cases, if you know you are never sending anything but JSON (which will never start with c:) it is safe to negotiate the non-control prefix to an empty string.

However, this implementation still has a few downsides:

  • if you do use a prefix its generally just kind of confusing / adds complexity
  • If you negotiate an empty string, you can footgun yourself if you end up sending some text that happens to start with c:

Ideally, we could separate control messages by introducing a new frame type. While possible in the websocket spec (though the other possible frame values are technically "reserved"), most user facing websocket libraries do not support non-standard frame types. As such this is not particularly practical for websocket proxying.

However, since websocket-over-http is the vastly more common usecase for websockets + GRIP, and the spec is much smaller, and easier to extend, it is possible to do it here.

Proposal

WebSocket-Over-Http-Extensions header

During the initial connection handshake between a GRIP proxy and a origin, in addition to Sec-Websocket-Extensions, proxies can additionally send a WebSocket-Over-Http-Extensions header. Websocket-over-HTTP extensions can make changes to the WebSocket-over-HTTP protocol, such as adding a new frame type.

The grip-events WebSocket-over-HTTP extension

This extension should be negotiated alongside the grip websocket extension. If both are present, no message prefix is to be used an TEXT events should be consider all "non-control" messages.

A new event is introduced, CONTROL, which contains text which should be interpreted exactly as messages with the control prefix were interpreted.

POST /target HTTP/1.1
Connection-Id: b5ea0e11
Content-Type: application/websocket-events
Sec-WebSocket-Extensions: grip
WebSocket-Over-Http-Extensions: grip-events

OPEN\r\n
HTTP/1.1 200 OK
Content-Type: application/websocket-events
Sec-WebSocket-Extensions: grip
WebSocket-Over-Http-Extensions: grip-events

OPEN\r\n
CONTROL 2F\r\n
{"type": "subscribe", "channel": "mychannel"}\r\n
CONTROL 2F\r\n
{"type": "keep-alive", "content": "{}", "timeout": 30, "mode": "interval"}\r\n
TEXT 2F\r\n
hi client\r\n

Curious on people's thoughts!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions