BUG/MINOR: qpack: fix error code reported on QPACK decoding failure
qpack_decode_fs() is used to decode QPACK field section on HTTP/3 headers parsing. Its return value is incoherent as it returns either QPACK_DECOMPRESSION_FAILED defined in RFC 9204 or any other internal values defined in qpack-dec.h. On failure, such return code is reused by HTTP/3 layer to be reported via a CONNECTION_CLOSE frame. This is incorrect if an internal error values was reported as it is not defined by any specification. Fir return values of qpack_decode_fs() in two ways. Firstly, fix invalid usages of QPACK_DECOMPRESSION_FAILED when decoded content is too large for the correct internal error QPACK_ERR_TOO_LARGE. Secondly, adjust qpack_decode_fs() API to only returns internal code values. A new internal enum QPACK_ERR_DECOMP is defined to replace QPACK_DECOMPRESSION_FAILED. Caller is responsible to convert it to a suitable error value. For other internal values, H3_INTERNAL_ERROR is used. This is done through a set of convert functions. This should be backported up to 2.6. Note that trailers are not supported in 2.6 so chunk related to h3_trailers_to_htx() can be safely skipped.
This commit is contained in:
parent
4295dd21bd
commit
86aafd0236
@ -31,6 +31,7 @@ struct http_hdr;
|
||||
*/
|
||||
enum {
|
||||
QPACK_ERR_NONE = 0, /* no error */
|
||||
QPACK_ERR_DECOMP, /* corresponds to RFC 9204 decompression error */
|
||||
QPACK_ERR_RIC, /* cannot decode Required Insert Count prefix field */
|
||||
QPACK_ERR_DB, /* cannot decode Delta Base prefix field */
|
||||
QPACK_ERR_TRUNCATED, /* truncated stream */
|
||||
@ -50,4 +51,6 @@ int qpack_decode_fs(const unsigned char *buf, uint64_t len, struct buffer *tmp,
|
||||
int qpack_decode_enc(struct buffer *buf, int fin, void *ctx);
|
||||
int qpack_decode_dec(struct buffer *buf, int fin, void *ctx);
|
||||
|
||||
int qpack_err_decode(const int value);
|
||||
|
||||
#endif /* _HAPROXY_QPACK_DEC_H */
|
||||
|
12
src/h3.c
12
src/h3.c
@ -131,7 +131,7 @@ static uint64_t h3_settings_max_field_section_size = QUIC_VARINT_8_BYTE_MAX; /*
|
||||
struct h3c {
|
||||
struct qcc *qcc;
|
||||
struct qcs *ctrl_strm; /* Control stream */
|
||||
enum h3_err err;
|
||||
int err;
|
||||
uint32_t flags;
|
||||
|
||||
/* Settings */
|
||||
@ -504,6 +504,12 @@ static int h3_set_authority(struct qcs *qcs, struct ist *auth, const struct ist
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return <value> as is or H3_INTERNAL_ERROR if negative. Useful to prepare a standard error code. */
|
||||
static int h3_err(const int value)
|
||||
{
|
||||
return value >= 0 ? value : H3_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/* Parse from buffer <buf> a H3 HEADERS frame of length <len>. Data are copied
|
||||
* in a local HTX buffer and transfer to the stream connector layer. <fin> must be
|
||||
* set if this is the last data to transfer from this stream.
|
||||
@ -560,7 +566,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
list, sizeof(list) / sizeof(list[0]));
|
||||
if (ret < 0) {
|
||||
TRACE_ERROR("QPACK decoding error", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
h3c->err = -ret;
|
||||
h3c->err = h3_err(qpack_err_decode(ret));
|
||||
len = -1;
|
||||
goto out;
|
||||
}
|
||||
@ -939,7 +945,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
list, sizeof(list) / sizeof(list[0]));
|
||||
if (ret < 0) {
|
||||
TRACE_ERROR("QPACK decoding error", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
h3c->err = -ret;
|
||||
h3c->err = h3_err(qpack_err_decode(ret));
|
||||
len = -1;
|
||||
goto out;
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
* Count (Section 4.5.1), it MUST treat this as a connection error of
|
||||
* type QPACK_DECOMPRESSION_FAILED.
|
||||
*/
|
||||
return -QPACK_DECOMPRESSION_FAILED;
|
||||
return -QPACK_ERR_DECOMP;
|
||||
}
|
||||
else if (efl_type == QPACK_IFL_WPBI) {
|
||||
/* Indexed field line with post-base index
|
||||
@ -344,7 +344,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
* Count (Section 4.5.1), it MUST treat this as a connection error of
|
||||
* type QPACK_DECOMPRESSION_FAILED.
|
||||
*/
|
||||
return -QPACK_DECOMPRESSION_FAILED;
|
||||
return -QPACK_ERR_DECOMP;
|
||||
}
|
||||
else if (efl_type & QPACK_IFL_BIT) {
|
||||
/* Indexed field line */
|
||||
@ -375,7 +375,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
*
|
||||
* TODO adjust this when dynamic table support is implemented.
|
||||
*/
|
||||
return -QPACK_DECOMPRESSION_FAILED;
|
||||
return -QPACK_ERR_DECOMP;
|
||||
}
|
||||
|
||||
qpack_debug_printf(stderr, " t=%d index=%llu", !!static_tbl, (unsigned long long)index);
|
||||
@ -409,7 +409,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
*
|
||||
* TODO adjust this when dynamic table support is implemented.
|
||||
*/
|
||||
return -QPACK_DECOMPRESSION_FAILED;
|
||||
return -QPACK_ERR_DECOMP;
|
||||
}
|
||||
|
||||
qpack_debug_printf(stderr, " n=%d t=%d index=%llu", !!n, !!static_tbl, (unsigned long long)index);
|
||||
@ -429,7 +429,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
trash = chunk_newstr(tmp);
|
||||
if (!trash) {
|
||||
qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
|
||||
ret = -QPACK_DECOMPRESSION_FAILED;
|
||||
ret = -QPACK_ERR_TOO_LARGE;
|
||||
goto out;
|
||||
}
|
||||
nlen = huff_dec(raw, length, trash, tmp->size - tmp->data);
|
||||
@ -488,7 +488,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
trash = chunk_newstr(tmp);
|
||||
if (!trash) {
|
||||
qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
|
||||
ret = -QPACK_DECOMPRESSION_FAILED;
|
||||
ret = -QPACK_ERR_TOO_LARGE;
|
||||
goto out;
|
||||
}
|
||||
nlen = huff_dec(raw, name_len, trash, tmp->size - tmp->data);
|
||||
@ -533,7 +533,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
trash = chunk_newstr(tmp);
|
||||
if (!trash) {
|
||||
qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
|
||||
ret = -QPACK_DECOMPRESSION_FAILED;
|
||||
ret = -QPACK_ERR_TOO_LARGE;
|
||||
goto out;
|
||||
}
|
||||
nlen = huff_dec(raw, value_len, trash, tmp->size - tmp->data);
|
||||
@ -561,7 +561,7 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
*/
|
||||
if (!name.len) {
|
||||
qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
|
||||
ret = -QPACK_DECOMPRESSION_FAILED;
|
||||
ret = -QPACK_ERR_DECOMP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -586,3 +586,11 @@ int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
|
||||
qpack_debug_printf(stderr, "-- done: ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Convert return value from qpack_decode_fs() to a standard error code usable
|
||||
* in CONNECTION_CLOSE or -1 for an internal error.
|
||||
*/
|
||||
int qpack_err_decode(const int value)
|
||||
{
|
||||
return (value == -QPACK_ERR_DECOMP) ? QPACK_DECOMPRESSION_FAILED : -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user