MINOR: h3: complete HTTP/3 request scheme encoding

Previously, scheme was always set to https when transcoding an HTX
start-line into a HTTP/3 request. Change this so this conversion is now
fully compliant.

If no scheme is specified by the client, which is what happens most of
the time with HTTP/1, https is set for the HTTP/3 request. Else, reuse
the scheme requested by the client.

If either https or http is set, qpack_encode_scheme will encode it using
entry from QPACK static table. Else, a full literal field line with name
ref is used instead as the scheme value is specified as-is.
This commit is contained in:
Amaury Denoyelle 2025-05-30 11:48:00 +02:00
parent a0912cf914
commit 235e818fa1
3 changed files with 58 additions and 12 deletions

View File

@ -9,7 +9,7 @@ struct buffer;
int qpack_encode_field_section_line(struct buffer *out);
int qpack_encode_int_status(struct buffer *out, unsigned int status);
int qpack_encode_method(struct buffer *out, enum http_meth_t meth, struct ist other);
int qpack_encode_scheme(struct buffer *out);
int qpack_encode_scheme(struct buffer *out, const struct ist scheme);
int qpack_encode_path(struct buffer *out, const struct ist path);
int qpack_encode_header(struct buffer *out, const struct ist n, const struct ist v);

View File

@ -1707,7 +1707,7 @@ static int h3_req_headers_send(struct qcs *qcs, struct htx *htx)
enum htx_blk_type type;
struct htx_blk *blk;
struct htx_sl *sl;
struct ist meth;
struct ist meth, uri, scheme = IST_NULL, auth = IST_NULL;
int frame_length_size; /* size in bytes of frame length varint field */
int ret, err, hdr;
@ -1726,6 +1726,7 @@ static int h3_req_headers_send(struct qcs *qcs, struct htx *htx)
BUG_ON_HOT(sl); /* Only one start-line expected */
sl = htx_get_blk_ptr(htx, blk);
meth = htx_sl_req_meth(sl);
uri = htx_sl_req_uri(sl);
break;
case HTX_BLK_HDR:
@ -1762,7 +1763,35 @@ static int h3_req_headers_send(struct qcs *qcs, struct htx *htx)
if (qpack_encode_method(&headers_buf, sl->info.req.meth, meth))
goto err;
if (qpack_encode_scheme(&headers_buf))
if (uri.ptr[0] != '/' && uri.ptr[0] != '*') {
int len = 1;
/* the URI seems to start with a scheme */
while (len < uri.len && uri.ptr[len] != ':')
len++;
if (len + 2 < uri.len && uri.ptr[len + 1] == '/' && uri.ptr[len + 2] == '/') {
/* make the uri start at the authority now */
scheme = ist2(uri.ptr, len);
uri = istadv(uri, len + 3);
/* find the auth part of the URI */
auth = ist2(uri.ptr, 0);
while (auth.len < uri.len && auth.ptr[auth.len] != '/')
auth.len++;
uri = istadv(uri, auth.len);
}
}
if (!istlen(scheme)) {
if ((sl->flags & (HTX_SL_F_HAS_SCHM|HTX_SL_F_SCHM_HTTP)) == (HTX_SL_F_HAS_SCHM|HTX_SL_F_SCHM_HTTP))
scheme = ist("http");
else
scheme = ist("https");
}
if (qpack_encode_scheme(&headers_buf, scheme))
goto err;
if (qpack_encode_path(&headers_buf, ist('/')))

View File

@ -172,17 +172,34 @@ int qpack_encode_method(struct buffer *out, enum http_meth_t meth, struct ist ot
return 0;
}
/* Encode pseudo-header scheme defined to https on <out> buffer.
*
* Returns 0 on success else non-zero.
*/
int qpack_encode_scheme(struct buffer *out)
/* Returns 0 on success else non-zero. */
int qpack_encode_scheme(struct buffer *out, const struct ist scheme)
{
if (b_room(out) < 2)
return 1;
int sz;
if (unlikely(!isteq(scheme, ist("https"))) && !isteq(scheme, ist("http"))) {
sz = 2 + qpack_get_prefix_int_size(istlen(scheme), 7) + istlen(scheme);
if (b_room(out) < sz)
return 1;
/* literal field line with name ref */
qpack_encode_prefix_integer(out, 23, 4, 0x50);
qpack_encode_prefix_integer(out, istlen(scheme), 7, 0);
for (size_t i = 0; i < istlen(scheme); ++i)
b_putchr(out, istptr(scheme)[i]);
}
else {
int idx = 23;
if (unlikely(!isteq(scheme, ist("http"))))
idx = 22;
if (b_room(out) < 2)
return 1;
/* :scheme: http[s] */
qpack_encode_prefix_integer(out, idx, 6, 0xc0);
}
/* :scheme: https */
qpack_encode_prefix_integer(out, 23, 6, 0xc0);
return 0;
}