Lines Matching defs:stream

71 /* this is how much we want "in flight" for a stream */
73 /* on receiving from TLS, we prep for holding a full stream window */
77 /* stream recv/send chunks are a result of window / chunk sizes */
79 /* keep smaller stream upload buffer (default h2 window size) to have
130 struct bufc_pool stream_bufcp; /* spares for stream buffers */
132 size_t drain_total; /* sum of all stream's UrlState drain */
172 * All about the H3 internals of a stream
175 /*********** for HTTP/2 we store stream-local data here *************/
176 int32_t id; /* HTTP/2 protocol identifier for stream */
190 uint32_t error; /* stream error code */
193 bool closed; /* TRUE on stream close */
194 bool reset; /* TRUE on stream reset */
195 bool close_handled; /* TRUE if stream closure is handled by libcurl */
198 buffered data in stream->sendbuf to upload. */
213 struct stream_ctx *stream)
219 if(!stream->send_closed &&
220 (stream->upload_left || stream->upload_blocked_len))
224 stream->id, bits);
235 struct stream_ctx *stream;
243 stream = H2_STREAM_CTX(data);
244 if(stream) {
245 *pstream = stream;
249 stream = calloc(1, sizeof(*stream));
250 if(!stream)
253 stream->id = -1;
254 Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
256 Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
258 Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
259 Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
260 stream->resp_hds_len = 0;
261 stream->bodystarted = FALSE;
262 stream->status_code = -1;
263 stream->closed = FALSE;
264 stream->close_handled = FALSE;
265 stream->error = NGHTTP2_NO_ERROR;
266 stream->local_window_size = H2_STREAM_WINDOW_SIZE;
267 stream->upload_left = 0;
269 H2_STREAM_LCTX(data) = stream;
270 *pstream = stream;
274 static void free_push_headers(struct stream_ctx *stream)
277 for(i = 0; i<stream->push_headers_used; i++)
278 free(stream->push_headers[i]);
279 Curl_safefree(stream->push_headers);
280 stream->push_headers_used = 0;
287 struct stream_ctx *stream = H2_STREAM_CTX(data);
291 if(!stream)
296 /* returns error if stream not known, which is fine here */
297 (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL);
299 if(!stream->closed && stream->id > 0) {
301 CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream",
302 stream->id);
303 stream->closed = TRUE;
304 stream->reset = TRUE;
305 stream->send_closed = TRUE;
307 stream->id, NGHTTP2_STREAM_CLOSED);
310 if(!Curl_bufq_is_empty(&stream->recvbuf)) {
312 * in stream and connection window flow control. Need
315 nghttp2_session_consume(ctx->h2, stream->id,
316 Curl_bufq_len(&stream->recvbuf));
325 Curl_bufq_free(&stream->sendbuf);
326 Curl_bufq_free(&stream->recvbuf);
327 Curl_h1_req_parse_free(&stream->h1);
328 Curl_dynhds_free(&stream->resp_trailers);
329 free_push_headers(stream);
330 free(stream);
415 struct stream_ctx *stream;
455 * in the H1 request and we upgrade from there. This stream
467 result = http2_data_setup(cf, data, &stream);
470 DEBUGASSERT(stream);
471 stream->id = 1;
483 rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
486 infof(data, "http/2: failed to set user_data for stream %u",
487 stream->id);
573 GOAWAY frame has been received or when the limit of stream
735 struct stream_ctx *stream = H2_STREAM_CTX(h->data);
736 if(stream && num < stream->push_headers_used)
737 return stream->push_headers[num];
747 struct stream_ctx *stream;
760 stream = H2_STREAM_CTX(h->data);
761 if(!stream)
765 for(i = 0; i<stream->push_headers_used; i++) {
766 if(!strncmp(header, stream->push_headers[i], len)) {
768 if(stream->push_headers[i][len] != ':')
770 return &stream->push_headers[i][len + 1];
871 struct stream_ctx *stream;
889 stream = H2_STREAM_CTX(data);
890 if(!stream) {
891 failf(data, "Internal NULL stream");
906 failf(data, "error setting up stream: %d", result);
911 DEBUGASSERT(stream);
915 stream->push_headers_used, &heads,
920 free_push_headers(stream);
947 infof(data, "failed to set user_data for stream %u",
966 struct stream_ctx *stream = H2_STREAM_CTX(data);
971 nwritten = Curl_bufq_write(&stream->recvbuf,
975 stream->resp_hds_len += (size_t)nwritten;
985 struct stream_ctx *stream = H2_STREAM_CTX(data);
991 if(!stream) {
998 rbuflen = Curl_bufq_len(&stream->recvbuf);
1002 ctx->h2, stream->id),
1004 ctx->h2, stream->id));
1005 /* If !body started on this stream, then receiving DATA is illegal. */
1006 if(!stream->bodystarted) {
1015 drain_stream(cf, data, stream);
1017 else if(rbuflen > stream->local_window_size) {
1019 ctx->h2, stream->id);
1020 if(wsize > 0 && (uint32_t)wsize != stream->local_window_size) {
1027 stream->id,
1028 stream->local_window_size);
1033 if(stream->bodystarted) {
1040 stream->status_code. Fuzzing has proven this can still be reached
1042 if(stream->status_code == -1)
1046 if(stream->status_code / 100 != 1) {
1047 stream->bodystarted = TRUE;
1048 stream->status_code = -1;
1055 if(stream->status_code / 100 != 1) {
1056 stream->resp_hds_complete = TRUE;
1058 drain_stream(cf, data, stream);
1077 stream->closed = TRUE;
1079 stream->reset = TRUE;
1081 stream->send_closed = TRUE;
1082 drain_stream(cf, data, stream);
1086 drain_stream(cf, data, stream);
1206 /* stream ID zero is for connection-oriented stuff */
1226 /* Since the initial stream window is 64K, a request might be on HOLD,
1230 * To be safe, we UNHOLD a stream in order not to stall. */
1232 struct stream_ctx *stream = H2_STREAM_CTX(data);
1233 if(stream)
1234 drain_stream(cf, data, stream);
1269 struct stream_ctx *stream;
1275 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
1278 /* get the stream from the hash based on Stream ID */
1291 stream = H2_STREAM_CTX(data_s);
1292 if(!stream)
1295 nwritten = Curl_bufq_write(&stream->recvbuf, mem, len, &result);
1304 drain_stream(cf, data_s, stream);
1315 struct stream_ctx *stream;
1320 /* get the stream from the hash based on Stream ID, stream ID zero is for
1326 "[%d] on_stream_close, no easy set on stream", stream_id);
1330 /* nghttp2 still has an easy registered for the stream which has
1334 "[%d] on_stream_close, not a GOOD easy on stream", stream_id);
1338 stream = H2_STREAM_CTX(data_s);
1339 if(!stream) {
1341 "[%d] on_stream_close, GOOD easy but no stream", stream_id);
1345 stream->closed = TRUE;
1346 stream->error = error_code;
1347 if(stream->error) {
1348 stream->reset = TRUE;
1349 stream->send_closed = TRUE;
1352 if(stream->error)
1357 drain_stream(cf, data_s, stream);
1359 /* remove `data_s` from the nghttp2 stream */
1362 infof(data_s, "http/2: failed to clear user_data for stream %u",
1373 struct stream_ctx *stream;
1386 stream = H2_STREAM_CTX(data_s);
1387 if(!stream || !stream->bodystarted) {
1402 struct stream_ctx *stream;
1408 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
1410 /* get the stream from the hash based on Stream ID */
1417 stream = H2_STREAM_CTX(data_s);
1418 if(!stream) {
1419 failf(data_s, "Internal NULL stream");
1441 * PUSH_PROMISE for which the server is not authoritative as a stream
1453 if(!stream->push_headers) {
1454 stream->push_headers_alloc = 10;
1455 stream->push_headers = malloc(stream->push_headers_alloc *
1457 if(!stream->push_headers)
1459 stream->push_headers_used = 0;
1461 else if(stream->push_headers_used ==
1462 stream->push_headers_alloc) {
1464 if(stream->push_headers_alloc > 1000) {
1467 free_push_headers(stream);
1470 stream->push_headers_alloc *= 2;
1471 headp = realloc(stream->push_headers,
1472 stream->push_headers_alloc * sizeof(char *));
1474 free_push_headers(stream);
1477 stream->push_headers = headp;
1481 stream->push_headers[stream->push_headers_used++] = h;
1485 if(stream->bodystarted) {
1488 stream->id, (int)namelen, name, (int)valuelen, value);
1489 result = Curl_dynhds_add(&stream->resp_trailers,
1502 result = Curl_http_decode_status(&stream->status_code,
1507 stream->status_code);
1526 stream->id, stream->status_code);
1550 stream->id, (int)namelen, name, (int)valuelen, value);
1564 struct stream_ctx *stream = NULL;
1571 /* get the stream from the hash based on Stream ID, stream ID zero is for
1579 stream = H2_STREAM_CTX(data_s);
1580 if(!stream)
1586 nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result);
1593 if(nread > 0 && stream->upload_left != -1)
1594 stream->upload_left -= nread;
1598 stream_id, length, stream->upload_left, nread, result);
1600 if(stream->upload_left == 0)
1666 struct stream_ctx *stream = H2_STREAM_CTX(data);
1668 if(!ctx || !ctx->h2 || !stream)
1671 CURL_TRC_CF(data, cf, "[%d] data done send", stream->id);
1672 if(!stream->send_closed) {
1673 stream->send_closed = TRUE;
1674 if(stream->upload_left) {
1676 stream->upload_left = Curl_bufq_len(&stream->sendbuf);
1679 (void)nghttp2_session_resume_data(ctx->h2, stream->id);
1680 drain_stream(cf, data, stream);
1690 struct stream_ctx *stream,
1695 if(stream->error == NGHTTP2_REFUSED_STREAM) {
1697 "connection", stream->id);
1703 else if(stream->error != NGHTTP2_NO_ERROR) {
1704 failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
1705 stream->id, nghttp2_http2_strerror(stream->error),
1706 stream->error);
1710 else if(stream->reset) {
1711 failf(data, "HTTP/2 stream %u was reset", stream->id);
1712 *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
1716 if(!stream->bodystarted) {
1717 failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
1719 stream->id);
1724 if(Curl_dynhds_count(&stream->resp_trailers)) {
1731 for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) {
1732 e = Curl_dynhds_getn(&stream->resp_trailers, i);
1753 stream->close_handled = TRUE;
1804 struct stream_ctx *stream = H2_STREAM_CTX(data);
1807 if(stream && stream->id > 0 &&
1815 CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id);
1816 DEBUGASSERT(stream->id != -1);
1818 stream->id, &pri_spec);
1837 struct stream_ctx *stream,
1844 if(!Curl_bufq_is_empty(&stream->recvbuf)) {
1845 nread = Curl_bufq_read(&stream->recvbuf,
1853 if(stream->closed) {
1854 CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
1855 nread = http2_handle_stream_close(cf, data, stream, err);
1857 else if(stream->reset ||
1859 (ctx->goaway && ctx->last_stream_id < stream->id)) {
1860 CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
1861 *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
1873 stream->id, len, nread, *err);
1881 struct stream_ctx *stream;
1897 stream = H2_STREAM_CTX(data);
1898 if(stream && (stream->closed || Curl_bufq_is_full(&stream->recvbuf))) {
1941 struct stream_ctx *stream = H2_STREAM_CTX(data);
1946 if(!stream) {
1947 /* Abnormal call sequence: either this transfer has never opened a stream
1960 nread = stream_recv(cf, data, stream, buf, len, err);
1969 nread = stream_recv(cf, data, stream, buf, len, err);
1976 * that it adjusts stream flow control */
1977 if(stream->resp_hds_len >= data_consumed) {
1978 stream->resp_hds_len -= data_consumed; /* no DATA */
1981 if(stream->resp_hds_len) {
1982 data_consumed -= stream->resp_hds_len;
1983 stream->resp_hds_len = 0;
1986 nghttp2_session_consume(ctx->h2, stream->id, data_consumed);
1990 if(stream->closed) {
1991 CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id);
1992 drain_stream(cf, data, stream);
2003 drain_stream(cf, data, stream);
2011 stream->id, len, nread, *err,
2012 Curl_bufq_len(&stream->recvbuf),
2014 ctx->h2, stream->id),
2016 ctx->h2, stream->id),
2029 struct stream_ctx *stream = NULL;
2041 *err = http2_data_setup(cf, data, &stream);
2047 nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
2050 if(!stream->h1.done) {
2054 DEBUGASSERT(stream->h1.req);
2056 *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
2062 Curl_h1_req_parse_free(&stream->h1);
2081 stream->upload_left = data->state.infilesize;
2084 stream->upload_left = -1; /* unknown */
2092 stream->upload_left = 0; /* no request body */
2109 infof(data, "[HTTP/2] [%d] OPENED stream for %s",
2122 "stream to be rejected.", MAX_ACC);
2126 stream->id = stream_id;
2127 stream->local_window_size = H2_STREAM_WINDOW_SIZE;
2130 * Let's limit our stream window size around that, otherwise the server
2137 stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE;
2146 ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err);
2157 stream? stream->id : -1, nwritten, *err);
2159 *pstream = stream;
2168 struct stream_ctx *stream = H2_STREAM_CTX(data);
2177 if(stream && stream->id != -1) {
2178 if(stream->upload_blocked_len) {
2183 DEBUGASSERT(len >= stream->upload_blocked_len);
2184 if(len < stream->upload_blocked_len) {
2188 len, stream->upload_blocked_len);
2193 nwritten = (ssize_t)stream->upload_blocked_len;
2194 stream->upload_blocked_len = 0;
2197 else if(stream->closed) {
2198 if(stream->resp_hds_complete) {
2199 /* Server decided to close the stream after having sent us a findl
2205 "on closed stream with response", stream->id);
2210 infof(data, "stream %u closed", stream->id);
2219 nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
2224 if(!Curl_bufq_is_empty(&stream->sendbuf)) {
2225 /* req body data is buffered, resume the potentially suspended stream */
2226 rv = nghttp2_session_resume_data(ctx->h2, stream->id);
2235 nwritten = h2_submit(&stream, cf, data, buf, len, err);
2239 DEBUGASSERT(stream);
2245 /* if the stream has been closed in egress handling (nghttp2 does that
2247 if(stream && stream->closed && !was_blocked) {
2248 infof(data, "stream %u closed", stream->id);
2261 else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
2263 * there is data left in our stream send buffer unwritten. This may
2264 * be due to the stream's HTTP/2 flow window being exhausted. */
2268 if(stream && blocked && nwritten > 0) {
2270 * exhaustion. Data is left in our stream buffer, or nghttp2's internal
2273 stream->id);
2277 stream->upload_blocked_len = nwritten;
2280 stream->id, len,
2288 /* nghttp2 thinks this session is done. If the stream has not been
2290 if(stream->closed) {
2291 nwritten = http2_handle_stream_close(cf, data, stream, err);
2301 if(stream) {
2304 "h2 windows %d-%d (stream-conn), "
2305 "buffers %zu-%zu (stream-conn)",
2306 stream->id, len, nwritten, *err,
2307 stream->upload_left,
2309 ctx->h2, stream->id),
2311 Curl_bufq_len(&stream->sendbuf),
2339 struct stream_ctx *stream = H2_STREAM_CTX(data);
2345 s_exhaust = want_send && stream && stream->id >= 0 &&
2347 stream->id);
2440 struct stream_ctx *stream = H2_STREAM_CTX(data);
2443 if(ctx && ctx->h2 && stream) {
2444 uint32_t window = pause? 0 : stream->local_window_size;
2448 stream->id,
2457 drain_stream(cf, data, stream);
2468 drain_stream(cf, data, stream);
2471 DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
2472 window, stream->id));
2476 /* read out the stream local window again */
2479 stream->id);
2480 DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
2481 window2, stream->id));
2525 struct stream_ctx *stream = H2_STREAM_CTX(data);
2528 || (stream && !Curl_bufq_is_empty(&stream->sendbuf))
2529 || (stream && !Curl_bufq_is_empty(&stream->recvbuf))))
2802 infof(data, "Copied HTTP/2 data in stream buffer to connection buffer"
2822 struct stream_ctx *stream = H2_STREAM_CTX(data);
2823 return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED);