|
|
|
|
@@ -197,7 +197,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
|
|
|
|
case H3_UNI_S_T_CTRL:
|
|
|
|
|
if (h3c->flags & H3_CF_UNI_CTRL_SET) {
|
|
|
|
|
TRACE_ERROR("duplicated control stream", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_ERR_STREAM_CREATION_ERROR, 1);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
h3c->flags |= H3_CF_UNI_CTRL_SET;
|
|
|
|
|
@@ -212,7 +212,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
|
|
|
|
case H3_UNI_S_T_QPACK_DEC:
|
|
|
|
|
if (h3c->flags & H3_CF_UNI_QPACK_DEC_SET) {
|
|
|
|
|
TRACE_ERROR("duplicated qpack decoder stream", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_ERR_STREAM_CREATION_ERROR, 1);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
h3c->flags |= H3_CF_UNI_QPACK_DEC_SET;
|
|
|
|
|
@@ -223,7 +223,7 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
|
|
|
|
case H3_UNI_S_T_QPACK_ENC:
|
|
|
|
|
if (h3c->flags & H3_CF_UNI_QPACK_ENC_SET) {
|
|
|
|
|
TRACE_ERROR("duplicated qpack encoder stream", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_ERR_STREAM_CREATION_ERROR, 1);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
h3c->flags |= H3_CF_UNI_QPACK_ENC_SET;
|
|
|
|
|
@@ -322,7 +322,7 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
|
|
|
|
/* cf H3_FT_HEADERS case. */
|
|
|
|
|
if (h3s->type == H3S_T_CTRL ||
|
|
|
|
|
(h3s->st_req != H3S_ST_REQ_HEADERS && h3s->st_req != H3S_ST_REQ_DATA)) {
|
|
|
|
|
ret = H3_FRAME_UNEXPECTED;
|
|
|
|
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
@@ -349,7 +349,7 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
|
|
|
|
* own rules; see Section 9.
|
|
|
|
|
*/
|
|
|
|
|
if (h3s->type == H3S_T_CTRL || h3s->st_req == H3S_ST_REQ_TRAILERS)
|
|
|
|
|
ret = H3_FRAME_UNEXPECTED;
|
|
|
|
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case H3_FT_CANCEL_PUSH:
|
|
|
|
|
@@ -376,9 +376,9 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (h3s->type != H3S_T_CTRL)
|
|
|
|
|
ret = H3_FRAME_UNEXPECTED;
|
|
|
|
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
|
|
|
|
else if (!(h3c->flags & H3_CF_SETTINGS_RECV))
|
|
|
|
|
ret = H3_MISSING_SETTINGS;
|
|
|
|
|
ret = H3_ERR_MISSING_SETTINGS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case H3_FT_SETTINGS:
|
|
|
|
|
@@ -396,7 +396,7 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
|
|
|
|
* H3_FRAME_UNEXPECTED.
|
|
|
|
|
*/
|
|
|
|
|
if (h3s->type != H3S_T_CTRL || h3c->flags & H3_CF_SETTINGS_RECV)
|
|
|
|
|
ret = H3_FRAME_UNEXPECTED;
|
|
|
|
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case H3_FT_PUSH_PROMISE:
|
|
|
|
|
@@ -408,7 +408,7 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* TODO server-side only. */
|
|
|
|
|
ret = H3_FRAME_UNEXPECTED;
|
|
|
|
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
@@ -422,7 +422,7 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
|
|
|
|
* not satisfy that requirement and SHOULD be treated as an error.
|
|
|
|
|
*/
|
|
|
|
|
if (h3s->type == H3S_T_CTRL && !(h3c->flags & H3_CF_SETTINGS_RECV))
|
|
|
|
|
ret = H3_MISSING_SETTINGS;
|
|
|
|
|
ret = H3_ERR_MISSING_SETTINGS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -463,7 +463,7 @@ static int h3_check_body_size(struct qcs *qcs, int fin)
|
|
|
|
|
if (h3s->data_len > h3s->body_len ||
|
|
|
|
|
(fin && h3s->data_len < h3s->body_len)) {
|
|
|
|
|
TRACE_ERROR("Content-length does not match DATA frame size", H3_EV_RX_FRAME|H3_EV_RX_DATA, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
ret = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -504,10 +504,10 @@ 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. */
|
|
|
|
|
/* Return <value> as is or H3_ERR_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;
|
|
|
|
|
return value >= 0 ? value : H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse from buffer <buf> a H3 HEADERS frame of length <len>. Data are copied
|
|
|
|
|
@@ -573,7 +573,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
if (!b_alloc(&htx_buf, DB_SE_RX)) {
|
|
|
|
|
TRACE_ERROR("HTX buffer alloc failure", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -612,7 +612,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
ctl = ist_find_ctl(list[hdr_idx].v);
|
|
|
|
|
if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
|
|
|
|
|
TRACE_ERROR("control character present in pseudo-header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -623,7 +623,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
if (isteq(list[hdr_idx].n, ist(":method"))) {
|
|
|
|
|
if (isttest(meth)) {
|
|
|
|
|
TRACE_ERROR("duplicated method pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -632,7 +632,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
else if (isteq(list[hdr_idx].n, ist(":path"))) {
|
|
|
|
|
if (isttest(path)) {
|
|
|
|
|
TRACE_ERROR("duplicated path pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -644,7 +644,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
ctl = ist_find_range(list[hdr_idx].v, 0, '#');
|
|
|
|
|
if (unlikely(ctl) && http_path_has_forbidden_char(list[hdr_idx].v, ctl)) {
|
|
|
|
|
TRACE_ERROR("forbidden character in ':path' pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -656,7 +656,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
if (isttest(scheme)) {
|
|
|
|
|
/* duplicated pseudo-header */
|
|
|
|
|
TRACE_ERROR("duplicated scheme pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -665,20 +665,20 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
else if (isteq(list[hdr_idx].n, ist(":authority"))) {
|
|
|
|
|
if (isttest(authority)) {
|
|
|
|
|
TRACE_ERROR("duplicated authority pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (h3_set_authority(qcs, &authority, list[hdr_idx].v)) {
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
TRACE_ERROR("unknown pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -695,7 +695,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
*/
|
|
|
|
|
if (!isttest(meth) || !isttest(scheme) || !isttest(path)) {
|
|
|
|
|
TRACE_ERROR("missing mandatory pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -706,7 +706,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, path, ist("HTTP/3.0"));
|
|
|
|
|
if (!sl) {
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -718,7 +718,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
if (isttest(authority)) {
|
|
|
|
|
if (!htx_add_header(htx, ist("host"), authority)) {
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -731,7 +731,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
if (istmatch(list[hdr_idx].n, ist(":"))) {
|
|
|
|
|
TRACE_ERROR("pseudo-header field after fields", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -740,7 +740,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
const char c = list[hdr_idx].n.ptr[i];
|
|
|
|
|
if ((uint8_t)(c - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(c)) {
|
|
|
|
|
TRACE_ERROR("invalid characters in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -761,14 +761,14 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
ctl = ist_find_ctl(list[hdr_idx].v);
|
|
|
|
|
if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
|
|
|
|
|
TRACE_ERROR("control character present in header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isteq(list[hdr_idx].n, ist("host"))) {
|
|
|
|
|
if (h3_set_authority(qcs, &authority, list[hdr_idx].v)) {
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -784,7 +784,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
h3s->flags & H3_SF_HAVE_CLEN);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
TRACE_ERROR("invalid content-length", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -818,7 +818,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
* connection-specific fields MUST be treated as malformed.
|
|
|
|
|
*/
|
|
|
|
|
TRACE_ERROR("invalid connection header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -831,13 +831,13 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
* NOT contain any value other than "trailers".
|
|
|
|
|
*/
|
|
|
|
|
TRACE_ERROR("invalid te header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v)) {
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -853,21 +853,21 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
*/
|
|
|
|
|
if (!isttest(authority)) {
|
|
|
|
|
TRACE_ERROR("missing mandatory pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cookie >= 0) {
|
|
|
|
|
if (http_cookie_merge(htx, list, cookie)) {
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!htx_add_endof(htx, HTX_BLK_EOH)) {
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -879,7 +879,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
htx = NULL;
|
|
|
|
|
|
|
|
|
|
if (!qcs_attach_sc(qcs, &htx_buf, fin)) {
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -952,7 +952,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
if (!(appbuf = qcc_get_stream_rxbuf(qcs))) {
|
|
|
|
|
TRACE_ERROR("HTX buffer alloc failure", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -986,7 +986,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
*/
|
|
|
|
|
if (istmatch(list[hdr_idx].n, ist(":"))) {
|
|
|
|
|
TRACE_ERROR("pseudo-header field in trailers", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -995,7 +995,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
const char c = list[hdr_idx].n.ptr[i];
|
|
|
|
|
if ((uint8_t)(c - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(c)) {
|
|
|
|
|
TRACE_ERROR("invalid characters in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -1010,7 +1010,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
isteq(list[hdr_idx].n, ist("te")) ||
|
|
|
|
|
isteq(list[hdr_idx].n, ist("transfer-encoding"))) {
|
|
|
|
|
TRACE_ERROR("forbidden HTTP/3 headers", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -1029,14 +1029,14 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
ctl = ist_find_ctl(list[hdr_idx].v);
|
|
|
|
|
if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
|
|
|
|
|
TRACE_ERROR("control character present in trailer value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3s->err = H3_MESSAGE_ERROR;
|
|
|
|
|
h3s->err = H3_ERR_MESSAGE_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!htx_add_trailer(htx, list[hdr_idx].n, list[hdr_idx].v)) {
|
|
|
|
|
TRACE_ERROR("cannot add trailer", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -1046,7 +1046,7 @@ static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
if (!htx_add_endof(htx, HTX_BLK_EOT)) {
|
|
|
|
|
TRACE_ERROR("cannot add trailer", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -1084,7 +1084,7 @@ static ssize_t h3_data_to_htx(struct qcs *qcs, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
if (!(appbuf = qcc_get_stream_rxbuf(qcs))) {
|
|
|
|
|
TRACE_ERROR("data buffer alloc failure", H3_EV_RX_FRAME|H3_EV_RX_DATA, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
len = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
@@ -1158,7 +1158,7 @@ static ssize_t h3_parse_settings_frm(struct h3c *h3c, const struct buffer *buf,
|
|
|
|
|
|
|
|
|
|
while (b_data(&b)) {
|
|
|
|
|
if (!b_quic_dec_int(&id, &b, &ret) || !b_quic_dec_int(&value, &b, &ret)) {
|
|
|
|
|
h3c->err = H3_FRAME_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_FRAME_ERROR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1175,7 +1175,7 @@ static ssize_t h3_parse_settings_frm(struct h3c *h3c, const struct buffer *buf,
|
|
|
|
|
/* Ignore duplicate check for ID too big used for GREASE. */
|
|
|
|
|
if (id < sizeof(mask)) {
|
|
|
|
|
if (ha_bit_test(id, &mask)) {
|
|
|
|
|
h3c->err = H3_SETTINGS_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_SETTINGS_ERROR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ha_bit_set(id, &mask);
|
|
|
|
|
@@ -1205,7 +1205,7 @@ static ssize_t h3_parse_settings_frm(struct h3c *h3c, const struct buffer *buf,
|
|
|
|
|
* their receipt MUST be treated as a connection error of type
|
|
|
|
|
* H3_SETTINGS_ERROR.
|
|
|
|
|
*/
|
|
|
|
|
h3c->err = H3_SETTINGS_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_SETTINGS_ERROR;
|
|
|
|
|
return -1;
|
|
|
|
|
default:
|
|
|
|
|
/* MUST be ignored */
|
|
|
|
|
@@ -1264,7 +1264,7 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
|
|
|
|
*/
|
|
|
|
|
if (h3s->type == H3S_T_CTRL && fin) {
|
|
|
|
|
TRACE_ERROR("control stream closed by remote peer", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_ERR_CLOSED_CRITICAL_STREAM, 1);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1275,14 +1275,14 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
|
|
|
|
TRACE_PROTO("received FIN without data", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
|
|
|
|
if (!(appbuf = qcc_get_stream_rxbuf(qcs))) {
|
|
|
|
|
TRACE_ERROR("data buffer alloc failure", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
htx = htx_from_buf(appbuf);
|
|
|
|
|
if (!htx_set_eom(htx)) {
|
|
|
|
|
TRACE_ERROR("cannot set EOM", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
}
|
|
|
|
|
htx_to_buf(htx, appbuf);
|
|
|
|
|
goto done;
|
|
|
|
|
@@ -1337,7 +1337,7 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
|
|
|
|
*/
|
|
|
|
|
if (flen > QC_S_RX_BUF_SZ) {
|
|
|
|
|
TRACE_ERROR("received a too big frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_EXCESSIVE_LOAD, 1);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_ERR_EXCESSIVE_LOAD, 1);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
@@ -1542,7 +1542,7 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
|
|
|
|
|
else if (type == HTX_BLK_HDR) {
|
|
|
|
|
if (unlikely(hdr >= sizeof(list) / sizeof(list[0]) - 1)) {
|
|
|
|
|
TRACE_ERROR("too many headers", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
list[hdr].n = htx_get_blk_name(htx, blk);
|
|
|
|
|
@@ -1562,7 +1562,7 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
|
|
|
|
|
if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
|
|
|
|
|
if (err) {
|
|
|
|
|
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1585,7 +1585,7 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
|
|
|
|
|
ABORT_NOW();
|
|
|
|
|
if (qpack_encode_int_status(&headers_buf, status)) {
|
|
|
|
|
TRACE_ERROR("invalid status code", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1689,7 +1689,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
|
|
|
|
|
if (type == HTX_BLK_TLR) {
|
|
|
|
|
if (unlikely(hdr >= sizeof(list) / sizeof(list[0]) - 1)) {
|
|
|
|
|
TRACE_ERROR("too many headers", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
list[hdr].n = htx_get_blk_name(htx, blk);
|
|
|
|
|
@@ -1698,7 +1698,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
TRACE_ERROR("unexpected HTX block", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1727,7 +1727,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
|
|
|
|
|
if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
|
|
|
|
|
if (err) {
|
|
|
|
|
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1865,7 +1865,7 @@ static int h3_resp_data_send(struct qcs *qcs, struct htx *htx,
|
|
|
|
|
if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
|
|
|
|
|
if (err) {
|
|
|
|
|
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_DATA, qcs->qcc->conn, qcs);
|
|
|
|
|
h3c->err = H3_INTERNAL_ERROR;
|
|
|
|
|
h3c->err = H3_ERR_INTERNAL_ERROR;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2061,7 +2061,7 @@ static size_t h3_snd_buf(struct qcs *qcs, struct buffer *buf, size_t count)
|
|
|
|
|
/* Generate a STOP_SENDING if full response transferred before
|
|
|
|
|
* receiving the full request.
|
|
|
|
|
*/
|
|
|
|
|
qcs->err = H3_NO_ERROR;
|
|
|
|
|
qcs->err = H3_ERR_NO_ERROR;
|
|
|
|
|
qcc_abort_stream_read(qcs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2181,7 +2181,7 @@ static int h3_close(struct qcs *qcs, enum qcc_app_ops_close_side side)
|
|
|
|
|
*/
|
|
|
|
|
if (qcs == h3c->ctrl_strm || h3s->type == H3S_T_CTRL) {
|
|
|
|
|
TRACE_ERROR("closure detected on control stream", H3_EV_H3S_END, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
|
|
|
|
|
qcc_set_error(qcs->qcc, H3_ERR_CLOSED_CRITICAL_STREAM, 1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2212,7 +2212,7 @@ static int h3_attach(struct qcs *qcs, void *conn_ctx)
|
|
|
|
|
*/
|
|
|
|
|
TRACE_STATE("reject stream higher than goaway", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
|
|
|
|
|
qcc_abort_stream_read(qcs);
|
|
|
|
|
qcc_reset_stream(qcs, H3_REQUEST_REJECTED);
|
|
|
|
|
qcc_reset_stream(qcs, H3_ERR_REQUEST_REJECTED);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2345,7 +2345,7 @@ static int h3_init(struct qcc *qcc)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
fail_no_h3:
|
|
|
|
|
qcc_set_error(qcc, H3_INTERNAL_ERROR, 1);
|
|
|
|
|
qcc_set_error(qcc, H3_ERR_INTERNAL_ERROR, 1);
|
|
|
|
|
TRACE_DEVEL("leaving on error", H3_EV_H3C_NEW, qcc->conn);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -2377,7 +2377,7 @@ static int h3_finalize(void *ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
qcc_set_error(qcc, H3_INTERNAL_ERROR, 1);
|
|
|
|
|
qcc_set_error(qcc, H3_ERR_INTERNAL_ERROR, 1);
|
|
|
|
|
TRACE_DEVEL("leaving on error", H3_EV_H3C_NEW, qcc->conn);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
@@ -2404,7 +2404,7 @@ static void h3_shutdown(void *ctx)
|
|
|
|
|
* graceful shutdown SHOULD use the H3_NO_ERROR error code when closing
|
|
|
|
|
* the connection.
|
|
|
|
|
*/
|
|
|
|
|
h3c->qcc->err = quic_err_app(H3_NO_ERROR);
|
|
|
|
|
h3c->qcc->err = quic_err_app(H3_ERR_NO_ERROR);
|
|
|
|
|
|
|
|
|
|
TRACE_LEAVE(H3_EV_H3C_END, h3c->qcc->conn);
|
|
|
|
|
}
|
|
|
|
|
|