Skip to content

Commit bb33cec

Browse files
authored
Update curl_ngtcp2.c
1 parent 0def7f0 commit bb33cec

1 file changed

Lines changed: 238 additions & 42 deletions

File tree

lib/vquic/curl_ngtcp2.c

Lines changed: 238 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,48 +1248,244 @@
12481248
}
12491249

12501250
rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id,
1251-
qpack_dec_stream_id);
1252-
if(rc) {
1253-
failf(data, "error binding HTTP/3 qpack streams: %s",
1254-
ngtcp2_strerror(rc));
1255-
return CURLE_QUIC_CONNECT_ERROR;
1256-
}
1257-
1258-
return CURLE_OK;
1259-
}
1260-
1261-
static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
1262-
struct Curl_easy *data,
1263-
struct h3_stream_ctx *stream,
1264-
CURLcode *err)
1265-
{
1266-
ssize_t nread = -1;
1267-
1268-
(void)cf;
1269-
if(stream->reset) {
1270-
failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
1271-
*err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
1272-
goto out;
1273-
}
1274-
else if(!stream->resp_hds_complete) {
1275-
failf(data,
1276-
"HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
1277-
"getting all response header fields, treated as error",
1278-
stream->id);
1279-
*err = CURLE_HTTP3;
1280-
goto out;
1281-
}
1282-
*err = CURLE_OK;
1283-
nread = 0;
1284-
1285-
out:
1286-
return nread;
1287-
}
1288-
1289-
/* incoming data frames on the h3 stream */
1290-
static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1291-
char *buf, size_t blen, size_t *pnread)
1292-
{
1251+
qpack_dec_stream_id);
1252+
if(rc) {
1253+
failf(data, "error binding HTTP/3 qpack streams: %s",
1254+
ngtcp2_strerror(rc));
1255+
return CURLE_QUIC_CONNECT_ERROR;
1256+
}
1257+
1258+
return CURLE_OK;
1259+
}
1260+
1261+
static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
1262+
struct Curl_easy *data,
1263+
struct h3_stream_ctx *stream,
1264+
CURLcode *err)
1265+
{
1266+
ssize_t nread = -1;
1267+
1268+
(void)cf;
1269+
if(stream->reset) {
1270+
failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
1271+
*err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
1272+
goto out;
1273+
}
1274+
else if(!stream->resp_hds_complete) {
1275+
failf(data,
1276+
"HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
1277+
"getting all response header fields, treated as error",
1278+
stream->id);
1279+
*err = CURLE_HTTP3;
1280+
goto out;
1281+
}
1282+
*err = CURLE_OK;
1283+
nread = 0;
1284+
1285+
out:
1286+
return nread;
1287+
}
1288+
1289+
/* incoming data frames on the h3 stream */
1290+
static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1291+
char *buf, size_t blen, size_t *pnread)
1292+
{
1293+
struct cf_ngtcp2_ctx *ctx = cf->ctx;
1294+
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1295+
struct cf_call_data save;
1296+
struct pkt_io_ctx pktx;
1297+
CURLcode result = CURLE_OK;
1298+
1299+
(void)ctx;
1300+
(void)buf;
1301+
1302+
CF_DATA_SAVE(save, cf, data);
1303+
DEBUGASSERT(cf->connected);
1304+
DEBUGASSERT(ctx);
1305+
DEBUGASSERT(ctx->qconn);
1306+
DEBUGASSERT(ctx->h3conn);
1307+
*pnread = 0;
1308+
1309+
/* handshake verification failed in callback, do not recv anything */
1310+
if(ctx->tls_vrfy_result)
1311+
return ctx->tls_vrfy_result;
1312+
1313+
pktx_init(&pktx, cf, data);
1314+
1315+
if(!stream || ctx->shutdown_started) {
1316+
result = CURLE_RECV_ERROR;
1317+
goto out;
1318+
}
1319+
1320+
if(cf_progress_ingress(cf, data, &pktx)) {
1321+
result = CURLE_RECV_ERROR;
1322+
goto out;
1323+
}
1324+
1325+
if(stream->xfer_result) {
1326+
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
1327+
cf_ngtcp2_stream_close(cf, data, stream);
1328+
result = stream->xfer_result;
1329+
goto out;
1330+
}
1331+
else if(stream->closed) {
1332+
ssize_t nread = recv_closed_stream(cf, data, stream, &result);
1333+
if(nread > 0)
1334+
*pnread = (size_t)nread;
1335+
goto out;
1336+
}
1337+
result = CURLE_AGAIN;
1338+
1339+
out:
1340+
result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx));
1341+
result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx));
1342+
1343+
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu",
1344+
stream ? stream->id : -1, blen, result, *pnread);
1345+
CF_DATA_RESTORE(cf, save);
1346+
return result;
1347+
}
1348+
1349+
static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
1350+
uint64_t datalen, void *user_data,
1351+
void *stream_user_data)
1352+
{
1353+
struct Curl_cfilter *cf = user_data;
1354+
struct cf_ngtcp2_ctx *ctx = cf->ctx;
1355+
struct Curl_easy *data = stream_user_data;
1356+
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1357+
size_t skiplen;
1358+
1359+
(void)cf;
1360+
if(!stream)
1361+
return 0;
1362+
/* The server acknowledged `datalen` of bytes from our request body.
1363+
* This is a delta. We have kept this data in `sendbuf` for
1364+
* re-transmissions and can free it now. */
1365+
if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
1366+
skiplen = stream->sendbuf_len_in_flight;
1367+
else
1368+
skiplen = (size_t)datalen;
1369+
Curl_bufq_skip(&stream->sendbuf, skiplen);
1370+
stream->sendbuf_len_in_flight -= skiplen;
1371+
1372+
/* Resume upload processing if we have more data to send */
1373+
if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1374+
int rv = nghttp3_conn_resume_stream(conn, stream_id);
1375+
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1376+
return NGHTTP3_ERR_CALLBACK_FAILURE;
1377+
}
1378+
}
1379+
return 0;
1380+
}
1381+
1382+
static nghttp3_ssize
1383+
cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
1384+
nghttp3_vec *vec, size_t veccnt,
1385+
uint32_t *pflags, void *user_data,
1386+
void *stream_user_data)
1387+
{
1388+
struct Curl_cfilter *cf = user_data;
1389+
struct cf_ngtcp2_ctx *ctx = cf->ctx;
1390+
struct Curl_easy *data = stream_user_data;
1391+
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1392+
ssize_t nwritten = 0;
1393+
size_t nvecs = 0;
1394+
(void)cf;
1395+
(void)conn;
1396+
(void)stream_id;
1397+
(void)user_data;
1398+
(void)veccnt;
1399+
1400+
if(!stream)
1401+
return NGHTTP3_ERR_CALLBACK_FAILURE;
1402+
/* nghttp3 keeps references to the sendbuf data until it is ACKed
1403+
* by the server (see `cb_h3_acked_req_body()` for updates).
1404+
* `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
1405+
* that we have already passed to nghttp3, but which have not been
1406+
* ACKed yet.
1407+
* Any amount beyond `sendbuf_len_in_flight` we need still to pass
1408+
* to nghttp3. Do that now, if we can. */
1409+
if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1410+
nvecs = 0;
1411+
while(nvecs < veccnt &&
1412+
Curl_bufq_peek_at(&stream->sendbuf,
1413+
stream->sendbuf_len_in_flight,
1414+
CURL_UNCONST(&vec[nvecs].base),
1415+
&vec[nvecs].len)) {
1416+
stream->sendbuf_len_in_flight += vec[nvecs].len;
1417+
nwritten += vec[nvecs].len;
1418+
++nvecs;
1419+
}
1420+
DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
1421+
}
1422+
1423+
if(nwritten > 0 && stream->upload_left != -1)
1424+
stream->upload_left -= nwritten;
1425+
1426+
/* When we stopped sending and everything in `sendbuf` is "in flight",
1427+
* we are at the end of the request body. */
1428+
if(stream->upload_left == 0) {
1429+
*pflags = NGHTTP3_DATA_FLAG_EOF;
1430+
stream->send_closed = TRUE;
1431+
}
1432+
else if(!nwritten) {
1433+
/* Not EOF, and nothing to give, we signal WOULDBLOCK. */
1434+
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
1435+
stream->id);
1436+
return NGHTTP3_ERR_WOULDBLOCK;
1437+
}
1438+
1439+
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
1440+
"%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
1441+
stream->id, (int)nvecs,
1442+
*pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "",
1443+
nwritten, Curl_bufq_len(&stream->sendbuf),
1444+
stream->upload_left);
1445+
return (nghttp3_ssize)nvecs;
1446+
}
1447+
1448+
/* Index where :authority header field will appear in request header
1449+
field list. */
1450+
#define AUTHORITY_DST_IDX 3
1451+
1452+
static CURLcode h3_stream_open(struct Curl_cfilter *cf,
1453+
struct Curl_easy *data,
1454+
const void *buf, size_t len,
1455+
size_t *pnwritten)
1456+
{
1457+
struct cf_ngtcp2_ctx *ctx = cf->ctx;
1458+
struct h3_stream_ctx *stream = NULL;
1459+
int64_t sid;
1460+
struct dynhds h2_headers;
1461+
size_t nheader;
1462+
nghttp3_nv *nva = NULL;
1463+
int rc = 0;
1464+
unsigned int i;
1465+
ssize_t nwritten = -1;
1466+
nghttp3_data_reader reader;
1467+
nghttp3_data_reader *preader = NULL;
1468+
CURLcode result;
1469+
1470+
*pnwritten = 0;
1471+
Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
1472+
1473+
result = h3_data_setup(cf, data);
1474+
if(result)
1475+
goto out;
1476+
stream = H3_STREAM_CTX(ctx, data);
1477+
DEBUGASSERT(stream);
1478+
if(!stream) {
1479+
result = CURLE_FAILED_INIT;
1480+
goto out;
1481+
}
1482+
1483+
nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
1484+
if(nwritten < 0)
1485+
goto out;
1486+
*pnwritten = (size_t)nwritten;
1487+
1488+
/* ... */
12931489
struct cf_ngtcp2_ctx *ctx = cf->ctx;
12941490
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
12951491
struct cf_call_data save;

0 commit comments

Comments
 (0)