diff options
Diffstat (limited to 'lib/http2.c')
-rw-r--r-- | lib/http2.c | 121 |
1 files changed, 51 insertions, 70 deletions
diff --git a/lib/http2.c b/lib/http2.c index 4940918f8..9da3cae17 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -154,34 +154,6 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) } } -/* - * This specific transfer on this connection has been "drained". - */ -static void drained_transfer(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - if(data->state.drain) { - struct cf_h2_ctx *ctx = cf->ctx; - DEBUGASSERT(ctx->drain_total > 0); - ctx->drain_total--; - data->state.drain = 0; - } -} - -/* - * Mark this transfer to get "drained". - */ -static void drain_this(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - if(!data->state.drain) { - struct cf_h2_ctx *ctx = cf->ctx; - data->state.drain = 1; - ctx->drain_total++; - DEBUGASSERT(ctx->drain_total > 0); - } -} - /** * All about the H3 internals of a stream */ @@ -213,6 +185,25 @@ struct stream_ctx { #define H2_STREAM_ID(d) (H2_STREAM_CTX(d)? \ H2_STREAM_CTX(d)->id : -2) +/* + * Mark this transfer to get "drained". + */ +static void drain_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct stream_ctx *stream) +{ + int bits; + + (void)cf; + bits = CURL_CSELECT_IN; + if(stream->upload_left) + bits |= CURL_CSELECT_OUT; + if(data->state.dselect_bits != bits) { + data->state.dselect_bits = bits; + Curl_expire(data, 0, EXPIRE_RUN_NOW); + } +} + static CURLcode http2_data_setup(struct Curl_cfilter *cf, struct Curl_easy *data, struct stream_ctx **pstream) @@ -276,8 +267,6 @@ static void http2_data_done(struct Curl_cfilter *cf, (void)nghttp2_session_send(ctx->h2); } - drained_transfer(cf, data); - /* -1 means unassigned and 0 means cleared */ if(nghttp2_session_get_stream_user_data(ctx->h2, stream->id)) { int rv = nghttp2_session_set_stream_user_data(ctx->h2, @@ -515,8 +504,6 @@ static int h2_process_pending_input(struct Curl_cfilter *cf, while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); - DEBUGF(LOG_CF(data, cf, - "fed %zu bytes from nw to nghttp2 -> %zd", blen, rv)); if(rv < 0) { failf(data, "process_pending_input: nghttp2_session_mem_recv() returned " @@ -526,7 +513,6 @@ static int h2_process_pending_input(struct Curl_cfilter *cf, } Curl_bufq_skip(&ctx->inbufq, (size_t)rv); if(Curl_bufq_is_empty(&ctx->inbufq)) { - DEBUGF(LOG_CF(data, cf, "all data in connection buffer processed")); break; } else { @@ -975,8 +961,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, } } if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - drain_this(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); + drain_stream(cf, data, stream); } break; case NGHTTP2_HEADERS: @@ -1005,10 +990,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, DEBUGF(LOG_CF(data, cf, "[h2sid=%d] %zu header bytes", stream_id, Curl_bufq_len(&stream->recvbuf))); - if(CF_DATA_CURRENT(cf) != data) { - drain_this(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } + drain_stream(cf, data, stream); break; case NGHTTP2_PUSH_PROMISE: DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv PUSH_PROMISE", stream_id)); @@ -1031,16 +1013,14 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv RST", stream_id)); stream->closed = TRUE; stream->reset = TRUE; - drain_this(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); + drain_stream(cf, data, stream); break; case NGHTTP2_WINDOW_UPDATE: DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv WINDOW_UPDATE", stream_id)); if((data->req.keepon & KEEP_SEND_HOLD) && (data->req.keepon & KEEP_SEND)) { data->req.keepon &= ~KEEP_SEND_HOLD; - drain_this(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); + drain_stream(cf, data, stream); DEBUGF(LOG_CF(data, cf, "[h2sid=%d] un-holding after win update", stream_id)); } @@ -1156,10 +1136,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, } /* if we receive data for another handle, wake that up */ - if(CF_DATA_CURRENT(cf) != data_s) { - drain_this(cf, data_s); - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - } + drain_stream(cf, data_s, stream); DEBUGASSERT((size_t)nwritten == len); DEBUGF(LOG_CF(data_s, cf, "[h2sid=%d] %zd/%zu DATA recvd, " @@ -1196,10 +1173,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, if(stream->error) stream->reset = TRUE; - if(CF_DATA_CURRENT(cf) != data_s) { - drain_this(cf, data_s); - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - } + drain_stream(cf, data_s, stream); /* remove `data_s` from the nghttp2 stream */ rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); @@ -1529,7 +1503,7 @@ static CURLcode http2_data_done_send(struct Curl_cfilter *cf, /* resume sending here to trigger the callback to get called again so that it can signal EOF to nghttp2 */ (void)nghttp2_session_resume_data(ctx->h2, stream->id); - drain_this(cf, data); + drain_stream(cf, data, stream); } out: @@ -1543,14 +1517,17 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, struct stream_ctx *stream = H2_STREAM_CTX(data); ssize_t rv = 0; - drained_transfer(cf, data); - if(stream->error == NGHTTP2_REFUSED_STREAM) { DEBUGF(LOG_CF(data, cf, "[h2sid=%d] REFUSED_STREAM, try again on a new " "connection", stream->id)); connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */ data->state.refused_stream = TRUE; - *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ + *err = CURLE_SEND_ERROR; /* trigger Curl_retry_request() later */ + return -1; + } + else if(stream->reset) { + failf(data, "HTTP/2 stream %u was reset", stream->id); + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; return -1; } else if(stream->error != NGHTTP2_NO_ERROR) { @@ -1560,11 +1537,6 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, *err = CURLE_HTTP2_STREAM; return -1; } - else if(stream->reset) { - failf(data, "HTTP/2 stream %u was reset", stream->id); - *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; - return -1; - } if(!stream->bodystarted) { failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " @@ -1691,7 +1663,6 @@ static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data, ssize_t nread = -1; *err = CURLE_AGAIN; - drained_transfer(cf, data); if(!Curl_bufq_is_empty(&stream->recvbuf)) { nread = Curl_bufq_read(&stream->recvbuf, (unsigned char *)buf, len, err); @@ -1755,8 +1726,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, } nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); - DEBUGF(LOG_CF(data, cf, "read %zd bytes nw data -> %zd, %d", - Curl_bufq_len(&ctx->inbufq), nread, result)); + /* DEBUGF(LOG_CF(data, cf, "read %zd bytes nw data -> %zd, %d", + Curl_bufq_len(&ctx->inbufq), nread, result)); */ if(nread < 0) { if(result != CURLE_AGAIN) { failf(data, "Failed receiving HTTP2 data"); @@ -1832,7 +1803,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, if(stream->closed) { DEBUGF(LOG_CF(data, cf, "[h2sid=%d] closed stream, set drain", stream->id)); - drain_this(cf, data); + drain_stream(cf, data, stream); } } @@ -2040,9 +2011,14 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, } if(should_close_session(ctx)) { - DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); - *err = CURLE_HTTP2; - nwritten = -1; + if(stream->closed) { + nwritten = http2_handle_stream_close(cf, data, err); + } + else { + DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); + *err = CURLE_HTTP2; + nwritten = -1; + } goto out; } @@ -2085,9 +2061,14 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, } if(should_close_session(ctx)) { - DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); - *err = CURLE_HTTP2; - nwritten = -1; + if(stream->closed) { + nwritten = http2_handle_stream_close(cf, data, err); + } + else { + DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); + *err = CURLE_HTTP2; + nwritten = -1; + } goto out; } } |