← Commit list

88332049ea

Stefan Eissing
Stefan Eissing
2023-05-22
FAILED Duration: 474s

Subject

http/2: unstick uploads

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

$ git checkout -f 88332049ea2493c517e07d755378c855bd2f5112
Previous HEAD position was e37e92252d KNOWN_BUGS: hyper memory-leaks
HEAD is now at 88332049ea http/2: unstick uploads

$ git clean -fdx
Removing Makefile.in
Removing aclocal.m4
Removing autom4te.cache/
Removing compile
Removing confdefs.h
Removing config.guess
Removing config.log
Removing config.sub
Removing configure
Removing conftest.c
Removing depcomp
Removing docs/Makefile.in
Removing docs/cmdline-opts/Makefile.in
Removing docs/examples/Makefile.in
Removing docs/libcurl/Makefile.in
Removing docs/libcurl/opts/Makefile.in
Removing include/Makefile.in
Removing include/curl/Makefile.in
Removing install-sh
Removing lib/Makefile.in
Removing lib/curl_config.h.in
Removing ltmain.sh
Removing m4/libtool.m4
Removing m4/ltoptions.m4
Removing m4/ltsugar.m4
Removing m4/ltversion.m4
Removing m4/lt~obsolete.m4
Removing missing
Removing packages/Makefile.in
Removing packages/vms/Makefile.in
Removing run-compiler
Removing scripts/Makefile.in
Removing src/Makefile.in
Removing test-driver
Removing tests/Makefile.in
Removing tests/certs/Makefile.in
Removing tests/certs/scripts/Makefile.in
Removing tests/data/Makefile.in
Removing tests/http/Makefile.in
Removing tests/http/clients/Makefile.in
Removing tests/libtest/Makefile.in
Removing tests/server/Makefile.in
Removing tests/unit/Makefile.in

$ autoreconf -fi
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
libtoolize: Remember to add 'LT_INIT' to configure.ac.
configure.ac:123: installing './compile'
configure.ac:439: installing './config.guess'
configure.ac:439: installing './config.sub'
configure.ac:123: installing './install-sh'
configure.ac:129: installing './missing'
docs/examples/Makefile.am: installing './depcomp'
parallel-tests: installing './test-driver'

$ bash -c find . -name config.guess -exec cp /usr/share/misc/config.guess {} \;

$ bash -c find . -name config.sub -exec cp /usr/share/misc/config.sub {} \;

$ chmod +x configure

$ ./configure --disable-shared --without-ssl --disable-docs

[TIMEOUT]

Commit Diff GitHub →

lib/http2.c+35 -18
@@ -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);
@@ -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",
@@ -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;
@@ -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);
@@ -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;
@@ -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;
}
@@ -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;
tests/http/test_07_upload.py+2 -2
@@ -275,14 +275,14 @@ class TestUpload:
'--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):