If a request repeats the same header name multiple times, merge the
header values into a comma separated string. Previously, only the last
header specified would be used.
For header fields that are defined as a comma-separated list, a client
may choose to send it as multiple headers instead of one header with
comma-separated values. The specification says that these are
equivalent, so we can therefore join the headers into a comma-separated
string.
This is specified at https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.2
which says:
A sender MUST NOT generate multiple header fields with the same field
name in a message unless either the entire field value for that
header field is defined as a comma-separated list [i.e., #(values)]
or the header field is a well-known exception (as noted below).
A recipient MAY combine multiple header fields with the same field
name into one "field-name: field-value" pair, without changing the
semantics of the message, by appending each subsequent field value to
the combined field value in order, separated by a comma. The order
in which header fields with the same field name are received is
therefore significant to the interpretation of the combined field
value; a proxy MUST NOT change the order of these field values when
forwarding a message.
The API for connecting to WebSockets in browsers unfortunately doesn't
support setting any Authorization header. This means that before this
commit it was impossible to connect to the API relay from a web browser.
The only thing that can be set apart from the URL is the
Sec-WebSocket-Protocol header. Therefore this allows you to send the
auth token in this header.
This is a weird way to send auth, but it seems to be the best one that
makes it possible for browsers to connect. Kubernetes also does it this
way: https://github.com/kubernetes/kubernetes/pull/47740
Here is a post describing the different ways to make it possible for a
browser to authenticate against a websocket connection, and it also
recommends doing it this way:
https://stackoverflow.com/questions/4361173/http-headers-in-websockets-client-api/77060459#77060459
Note that when this header is used to pass auth, the client also needs
to specify the `api.weechat` sub protocol. This is because the client
and server have to agree on a sub protocol when this header is
specified, and in order to not send the fake protocol used for auth back
to the client, we require specifying the protocol `api.weechat`, which
the server then returns to the client. This is only necessary when the
Sec-WebSocket-Protocol header is used. If the Authorization header is
used for auth as before, nothing changes.
This fixes the following warning emitted by gcc:
…/relay-http.c:1207:32: warning: ‘%s’ directive output may be truncated writing up to 1023 bytes into a region of size 64 [-Wformat-truncation=]
1207 | "%s[%d bytes data]",
| ^~
1208 | str_header,
| ~~~~~~~~~~
…/relay-http.c:1207:31: note: directive argument in the range [1, 2147483647]
1207 | "%s[%d bytes data]",
| ^~~~~~~~~~~~~~~~~~~
…/relay-http.c:1206:21: note: ‘snprintf’ output between 15 and 1047 bytes into a destination of size 64
1206 | snprintf (raw_message, length_raw,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1207 | "%s[%d bytes data]",
| ~~~~~~~~~~~~~~~~~~~~
1208 | str_header,
| ~~~~~~~~~~~
1209 | *ptr_body_size);
| ~~~~~~~~~~~~~~~
Connection to remote:
- handshake: offer support for all supported hash algorithms
- network connect with a socket
- upgrade to websocket and authenticate with remote (password/TOTP)
- check websocket response
- get list of buffers (not used yet)
Note: connection to remote with TLS or a proxy is not yet supported.