quiche: after leaving h3_recving state, poll again

This could otherwise easily leave libcurl "hanging" after the entire
transfer is done but without noticing the end-of-transfer signal.

Assisted-by: Lucas Pardue
Closes #8436
This commit is contained in:
Daniel Stenberg 2022-02-11 09:26:07 +01:00
parent 6883180fa5
commit 96f85a0fef
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -596,66 +596,67 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
if(rcode <= 0) { if(rcode <= 0) {
recvd = -1; recvd = -1;
qs->h3_recving = FALSE; qs->h3_recving = FALSE;
/* fall through into the while loop below */
} }
else else
recvd = rcode; recvd = rcode;
} }
else {
while(recvd < 0) {
int64_t s = quiche_h3_conn_poll(qs->h3c, qs->conn, &ev);
if(s < 0)
/* nothing more to do */
break;
if(s != stream->stream3_id) { while(recvd < 0) {
/* another transfer, ignore for now */ int64_t s = quiche_h3_conn_poll(qs->h3c, qs->conn, &ev);
infof(data, "Got h3 for stream %u, expects %u", infof(data, "quiche_h3_conn_poll: %ld", s);
s, stream->stream3_id); if(s < 0)
continue; /* nothing more to do */
} break;
switch(quiche_h3_event_type(ev)) { if(s != stream->stream3_id) {
case QUICHE_H3_EVENT_HEADERS: /* another transfer, ignore for now */
rc = quiche_h3_event_for_each_header(ev, cb_each_header, &headers); infof(data, "Got h3 for stream %u, expects %u",
if(rc) { s, stream->stream3_id);
*curlcode = rc; continue;
failf(data, "Error in HTTP/3 response header");
break;
}
recvd = headers.nlen;
break;
case QUICHE_H3_EVENT_DATA:
if(!stream->firstbody) {
/* add a header-body separator CRLF */
buf[0] = '\r';
buf[1] = '\n';
buf += 2;
buffersize -= 2;
stream->firstbody = TRUE;
recvd = 2; /* two bytes already */
}
else
recvd = 0;
rcode = quiche_h3_recv_body(qs->h3c, qs->conn, s, (unsigned char *)buf,
buffersize);
if(rcode <= 0) {
recvd = -1;
break;
}
qs->h3_recving = TRUE;
recvd += rcode;
break;
case QUICHE_H3_EVENT_FINISHED:
streamclose(conn, "End of stream");
recvd = 0; /* end of stream */
break;
default:
break;
}
quiche_h3_event_free(ev);
} }
switch(quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS:
rc = quiche_h3_event_for_each_header(ev, cb_each_header, &headers);
if(rc) {
*curlcode = rc;
failf(data, "Error in HTTP/3 response header");
break;
}
recvd = headers.nlen;
break;
case QUICHE_H3_EVENT_DATA:
if(!stream->firstbody) {
/* add a header-body separator CRLF */
buf[0] = '\r';
buf[1] = '\n';
buf += 2;
buffersize -= 2;
stream->firstbody = TRUE;
recvd = 2; /* two bytes already */
}
else
recvd = 0;
rcode = quiche_h3_recv_body(qs->h3c, qs->conn, s, (unsigned char *)buf,
buffersize);
if(rcode <= 0) {
recvd = -1;
break;
}
qs->h3_recving = TRUE;
recvd += rcode;
break;
case QUICHE_H3_EVENT_FINISHED:
streamclose(conn, "End of stream");
recvd = 0; /* end of stream */
break;
default:
break;
}
quiche_h3_event_free(ev);
} }
if(flush_egress(data, sockfd, qs)) { if(flush_egress(data, sockfd, qs)) {
*curlcode = CURLE_SEND_ERROR; *curlcode = CURLE_SEND_ERROR;