Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http/2, unstuck uploads #11176

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions lib/http2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream->error = error_code;
if(stream->error)
stream->reset = TRUE;
data_s->req.keepon &= ~KEEP_SEND_HOLD;

drain_stream(cf, data_s, stream);

Expand Down Expand Up @@ -1676,7 +1677,9 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
goto out;
}

rv = nghttp2_session_send(ctx->h2);
while(!rv && nghttp2_session_want_write(ctx->h2))
rv = nghttp2_session_send(ctx->h2);

out:
if(nghttp2_is_fatal(rv)) {
DEBUGF(LOG_CF(data, cf, "nghttp2_session_send error (%s)%d",
Expand Down Expand Up @@ -1996,13 +1999,6 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CF_DATA_SAVE(save, cf, data);

if(stream && stream->id != -1) {
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send: win %u/%u",
stream->id,
nghttp2_session_get_remote_window_size(ctx->h2),
nghttp2_session_get_stream_remote_window_size(
ctx->h2, stream->id)
));

if(stream->close_handled) {
infof(data, "stream %u closed", stream->id);
*err = CURLE_HTTP2_STREAM;
Expand All @@ -2021,6 +2017,8 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
nwritten = 0;
}
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] bufq_write(len=%zu) -> %zd, %d",
stream->id, len, nwritten, *err));

if(!Curl_bufq_is_empty(&stream->sendbuf)) {
rv = nghttp2_session_resume_data(ctx->h2, stream->id);
Expand Down Expand Up @@ -2063,14 +2061,16 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send: win %u/%zu",
stream->id,
nghttp2_session_get_remote_window_size(ctx->h2), rwin));
if(rwin == 0) {
/* We cannot upload more as the stream's remote window size
* is 0. We need to receive WIN_UPDATEs before we can continue.
*/
data->req.keepon |= KEEP_SEND_HOLD;
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] holding send as remote flow "
"window is exhausted", stream->id));
}
if(rwin == 0) {
/* We cannot upload more as the stream's remote window size
* is 0. We need to receive WIN_UPDATEs before we can continue.
*/
data->req.keepon |= KEEP_SEND_HOLD;
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] holding send as remote flow "
"window is exhausted", stream->id));
}
nwritten = -1;
*err = CURLE_AGAIN;
}
/* handled writing BODY for open stream. */
goto out;
Expand Down Expand Up @@ -2109,8 +2109,24 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}

out:
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send -> %zd, %d",
stream? stream->id : -1, nwritten, *err));
if(stream) {
DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) -> %zd, %d, "
"buffered=%zu, upload_left=%zu, stream-window=%d, "
"connection-window=%d",
stream->id, len, nwritten, *err,
Curl_bufq_len(&stream->sendbuf),
(ssize_t)stream->upload_left,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, stream->id),
nghttp2_session_get_remote_window_size(ctx->h2)));
drain_stream(cf, data, stream);
}
else {
DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, "
"connection-window=%d",
len, nwritten, *err,
nghttp2_session_get_remote_window_size(ctx->h2)));
}
CF_DATA_RESTORE(cf, save);
return nwritten;
}
Expand Down Expand Up @@ -2313,6 +2329,7 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf,
struct stream_ctx *stream = H2_STREAM_CTX(data);

if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq)
|| (stream && !Curl_bufq_is_empty(&stream->sendbuf))
|| (stream && !Curl_bufq_is_empty(&stream->recvbuf))))
return TRUE;
return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
Expand Down
4 changes: 2 additions & 2 deletions tests/http/test_07_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,14 @@ def test_07_33_issue_11157b(self, env: Env, httpd, nghttpx, repeat):
'--resolve', f'{env.authority_for(env.domain1, proto)}:127.0.0.1',
'--cacert', env.ca.cert_file,
'--request', 'PUT',
'--max-time', '5', '-v',
'--max-time', '10', '-v',
'--url', url,
'--form', 'idList=12345678',
'--form', 'pos=top',
'--form', 'name=mr_test',
'--form', f'fileSource=@{fdata};type=application/pdf',
])
assert r.exit_code == 0, f'{r}'
assert r.exit_code == 0, r.dump_logs()
r.check_stats(1, 200)

def check_download(self, count, srcfile, curl):
Expand Down