MINOR: h3: abort request if not completed before full response

A HTTP server may provide a complete response even prior receiving the
full request. In this case, RFC 9114 allows the server to abort read
with a STOP_SENDING with error code H3_NO_ERROR.

This scenario was notably reproduced with haproxy and an inactive
server. If the client send a POST request, haproxy may provide a full
HTTP 503 response before the end of the full request.
This commit is contained in:
Amaury Denoyelle 2023-08-04 16:10:18 +02:00
parent f40a72a7ff
commit 559482c11e
3 changed files with 29 additions and 2 deletions

View File

@ -15,6 +15,8 @@
void qcc_set_error(struct qcc *qcc, int err, int app);
struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi);
struct stconn *qcs_attach_sc(struct qcs *qcs, struct buffer *buf, char fin);
int qcs_is_close_local(struct qcs *qcs);
int qcs_is_close_remote(struct qcs *qcs);
struct buffer *qcs_get_buf(struct qcs *qcs, struct buffer *bptr);
int qcs_subscribe(struct qcs *qcs, int event_type, struct wait_event *es);

View File

@ -1673,6 +1673,31 @@ static size_t h3_snd_buf(struct qcs *qcs, struct htx *htx, size_t count)
}
}
/* RFC 9114 4.1. HTTP Message Framing
*
* A server can send a complete response prior to the client sending an
* entire request if the response does not depend on any portion of the
* request that has not been sent and received. When the server does not
* need to receive the remainder of the request, it MAY abort reading
* the request stream, send a complete response, and cleanly close the
* sending part of the stream. The error code H3_NO_ERROR SHOULD be used
* when requesting that the client stop sending on the request stream.
* Clients MUST NOT discard complete responses as a result of having
* their request terminated abruptly, though clients can always discard
* responses at their discretion for other reasons. If the server sends
* a partial or complete response but does not abort reading the
* request, clients SHOULD continue sending the content of the request
* and close the stream normally.
*/
if (unlikely((htx->flags & HTX_FL_EOM) && htx_is_empty(htx)) &&
!qcs_is_close_remote(qcs)) {
/* Generate a STOP_SENDING if full response transferred before
* receiving the full request.
*/
qcs->err = H3_NO_ERROR;
qcc_abort_stream_read(qcs);
}
out:
return total;
}

View File

@ -403,12 +403,12 @@ static void qcs_close_remote(struct qcs *qcs)
}
}
static int qcs_is_close_local(struct qcs *qcs)
int qcs_is_close_local(struct qcs *qcs)
{
return qcs->st == QC_SS_HLOC || qcs->st == QC_SS_CLO;
}
static int qcs_is_close_remote(struct qcs *qcs)
int qcs_is_close_remote(struct qcs *qcs)
{
return qcs->st == QC_SS_HREM || qcs->st == QC_SS_CLO;
}