mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 07:07:04 +02:00
MINOR: h3: support basic HTX start-line conversion into HTTP/3 request
This commit is the first one of a serie which aim is to implement transcoding of a HTX request into HTTP/3, which is necessary for QUIC backend support. Transcoding is implementing via a new function h3_req_headers_send() when a HTX start-line is parsed. For now, most of the request fields are hardcoded, using a GET method. This will be adjusted in the next following patches.
This commit is contained in:
parent
fc1a17f169
commit
7157adb154
@ -1,12 +1,16 @@
|
||||
#ifndef QPACK_ENC_H_
|
||||
#define QPACK_ENC_H_
|
||||
|
||||
#include <haproxy/http-t.h>
|
||||
#include <haproxy/istbuf.h>
|
||||
|
||||
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);
|
||||
int qpack_encode_scheme(struct buffer *out);
|
||||
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);
|
||||
|
||||
#endif /* QPACK_ENC_H_ */
|
||||
|
78
src/h3.c
78
src/h3.c
@ -1691,6 +1691,74 @@ static int h3_encode_header(struct buffer *buf,
|
||||
return qpack_encode_header(buf, n, v_strip);
|
||||
}
|
||||
|
||||
/* Convert a HTX start-line and associated headers stored in <htx> into a
|
||||
* HTTP/3 HEADERS request frame. HTX blocks are removed up to end-of-trailer
|
||||
* included.
|
||||
*
|
||||
* Returns the amount of consumed bytes from <htx> buffer or a negative error
|
||||
* code.
|
||||
*/
|
||||
static int h3_req_headers_send(struct qcs *qcs, struct htx *htx)
|
||||
{
|
||||
struct buffer outbuf;
|
||||
struct buffer headers_buf = BUF_NULL;
|
||||
struct buffer *res;
|
||||
struct htx_blk *blk;
|
||||
enum htx_blk_type type;
|
||||
int frame_length_size; /* size in bytes of frame length varint field */
|
||||
int ret, err;
|
||||
|
||||
res = qcc_get_stream_txbuf(qcs, &err, 0);
|
||||
BUG_ON(!res);
|
||||
|
||||
b_reset(&outbuf);
|
||||
outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
|
||||
/* Start the headers after frame type + length */
|
||||
headers_buf = b_make(b_head(res) + 5, b_size(res) - 5, 0, 0);
|
||||
|
||||
if (qpack_encode_field_section_line(&headers_buf))
|
||||
goto err;
|
||||
|
||||
/* :method */
|
||||
if (qpack_encode_method(&headers_buf, HTTP_METH_GET))
|
||||
goto err;
|
||||
/* :scheme */
|
||||
|
||||
if (qpack_encode_scheme(&headers_buf))
|
||||
goto err;
|
||||
|
||||
if (qpack_encode_path(&headers_buf, ist('/')))
|
||||
goto err;
|
||||
|
||||
/* :authority */
|
||||
if (h3_encode_header(&headers_buf, ist(":authority"), ist("127.0.0.1:20443")))
|
||||
goto err;
|
||||
|
||||
/* Now that all headers are encoded, we are certain that res buffer is
|
||||
* big enough
|
||||
*/
|
||||
frame_length_size = quic_int_getsize(b_data(&headers_buf));
|
||||
res->head += 4 - frame_length_size;
|
||||
b_putchr(res, 0x01); /* h3 HEADERS frame type */
|
||||
b_quic_enc_int(res, b_data(&headers_buf), 0);
|
||||
b_add(res, b_data(&headers_buf));
|
||||
|
||||
ret = 0;
|
||||
blk = htx_get_head_blk(htx);
|
||||
while (blk) {
|
||||
type = htx_get_blk_type(blk);
|
||||
ret += htx_get_blksz(blk);
|
||||
blk = htx_remove_blk(htx, blk);
|
||||
if (type == HTX_BLK_EOH)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a HTX status-line and associated headers stored into <htx> into a
|
||||
* HTTP/3 HEADERS response frame. HTX blocks are removed up to end-of-trailer
|
||||
* included.
|
||||
@ -2191,6 +2259,16 @@ static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count)
|
||||
BUG_ON(btype == HTX_BLK_REQ_SL);
|
||||
|
||||
switch (btype) {
|
||||
case HTX_BLK_REQ_SL:
|
||||
ret = h3_req_headers_send(qcs, htx);
|
||||
if (ret > 0) {
|
||||
total += ret;
|
||||
count -= ret;
|
||||
if (ret < bsize)
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case HTX_BLK_RES_SL:
|
||||
/* start-line -> HEADERS h3 frame */
|
||||
ret = h3_resp_headers_send(qcs, htx);
|
||||
|
@ -132,6 +132,63 @@ int qpack_encode_int_status(struct buffer *out, unsigned int status)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 on success else non-zero. */
|
||||
int qpack_encode_method(struct buffer *out, enum http_meth_t meth)
|
||||
{
|
||||
int size, idx = 0;
|
||||
|
||||
switch (meth) {
|
||||
case HTTP_METH_GET: idx = 17; break;
|
||||
default: ABORT_NOW();
|
||||
}
|
||||
|
||||
if (idx) {
|
||||
/* method present in QPACK static table
|
||||
* -> indexed field line
|
||||
*/
|
||||
size = qpack_get_prefix_int_size(idx, 6);
|
||||
if (b_room(out) < size)
|
||||
return 1;
|
||||
|
||||
qpack_encode_prefix_integer(out, idx, 6, 0xc0);
|
||||
}
|
||||
else {
|
||||
ABORT_NOW();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (b_room(out) < 2)
|
||||
return 1;
|
||||
|
||||
/* :scheme: https */
|
||||
qpack_encode_prefix_integer(out, 23, 6, 0xc0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 on success else non-zero. */
|
||||
int qpack_encode_path(struct buffer *out, const struct ist path)
|
||||
{
|
||||
if (unlikely(isteq(path, ist("/")))) {
|
||||
if (!b_room(out))
|
||||
return 1;
|
||||
|
||||
qpack_encode_prefix_integer(out, 1, 6, 0xc0);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* TODO */
|
||||
ABORT_NOW();
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns 0 on success else non-zero. */
|
||||
int qpack_encode_field_section_line(struct buffer *out)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user