Sat, 30 Mar 2024 12:35:09 +0100
change net_write to attempt to write all bytes, improve error handling
--- a/src/server/daemon/protocol.c Tue Sep 12 18:08:11 2023 +0200 +++ b/src/server/daemon/protocol.c Sat Mar 30 12:35:09 2024 +0100 @@ -354,8 +354,7 @@ } // set stream property - HttpStream *stream = (HttpStream*)sn->csd; // TODO: make this typesafe - stream->chunked_enc = 1; + httpstream_enable_chunked_write(sn->csd); rq->rq_attr.chunked = 1; }
--- a/src/server/test/io.c Tue Sep 12 18:08:11 2023 +0200 +++ b/src/server/test/io.c Sat Mar 30 12:35:09 2024 +0100 @@ -445,6 +445,7 @@ size_t msglen = strlen(msg); st->max_write = 1; // limit the test stream max write size + io_set_max_writes(1); // only 1 byte of the header is written, 0 bytes of msg ssize_t w = net_write(http, msg, msglen); @@ -493,6 +494,7 @@ // limit first write to 3 to only write the header st->max_write = 3; + io_set_max_writes(1); ssize_t w = net_write(http, msg, msglen); @@ -535,6 +537,7 @@ TestIOStream *st = testutil_iostream(2048, TRUE); IOStream *http = httpstream_new(sn->pool, (IOStream*)st); httpstream_enable_chunked_write(http); + io_set_max_writes(1); UCX_TEST_BEGIN; @@ -595,6 +598,7 @@ TestIOStream *st = testutil_iostream(2048, TRUE); IOStream *http = httpstream_new(sn->pool, (IOStream*)st); httpstream_enable_chunked_write(http); + io_set_max_writes(1); UCX_TEST_BEGIN; @@ -654,6 +658,7 @@ TestIOStream *st = testutil_iostream(2048, TRUE); IOStream *http = httpstream_new(sn->pool, (IOStream*)st); httpstream_enable_chunked_write(http); + io_set_max_writes(1); UCX_TEST_BEGIN; @@ -700,6 +705,7 @@ TestIOStream *st = testutil_iostream(2048, TRUE); IOStream *http = httpstream_new(sn->pool, (IOStream*)st); httpstream_enable_chunked_write(http); + io_set_max_writes(1); UCX_TEST_BEGIN;
--- a/src/server/test/testutils.c Tue Sep 12 18:08:11 2023 +0200 +++ b/src/server/test/testutils.c Sat Mar 30 12:35:09 2024 +0100 @@ -184,6 +184,7 @@ stream->io.st.writev = test_io_writev; stream->io.st.close = test_io_close; stream->io.st.finish = test_io_finish; + stream->io.st.type = IO_STREAM_TYPE_HTTP; return stream; }
--- a/src/server/util/io.c Tue Sep 12 18:08:11 2023 +0200 +++ b/src/server/util/io.c Sat Mar 30 12:35:09 2024 +0100 @@ -78,6 +78,7 @@ NULL, (io_setmode_f)net_sys_setmode, (io_poll_f)net_sys_poll, + 0, 0 }; @@ -90,7 +91,8 @@ (io_finish_f)net_http_finish, (io_setmode_f)net_http_setmode, (io_poll_f)net_http_poll, - 0 + 0, + IO_STREAM_TYPE_HTTP }; IOStream ssl_io_funcs = { @@ -102,9 +104,15 @@ (io_finish_f)net_ssl_finish, (io_setmode_f)net_ssl_setmode, (io_poll_f)net_ssl_poll, - 0 + 0, + IO_STREAM_TYPE_SSL }; +static int net_write_max_attempts = 16384; + +void io_set_max_writes(int n) { + net_write_max_attempts = 1; +} /* * Sysstream implementation @@ -300,7 +308,7 @@ } int httpstream_enable_chunked_write(IOStream *st) { - if(st->write != (io_write_f)net_http_write) { + if(st->type != IO_STREAM_TYPE_HTTP) { log_ereport(LOG_FAILURE, "%s", "httpstream_enable_chunked_write: IOStream is not an HttpStream"); return 1; } @@ -467,7 +475,7 @@ st->written += ret_w; if(ret_w == 0) { st->st.io_errno = EWOULDBLOCK; // not sure if this is really correct - ret_w = -1; + //ret_w = -1; } return ret_w; } @@ -876,11 +884,25 @@ } ssize_t net_write(SYS_NETFD fd, const void *buf, size_t nbytes) { - ssize_t r = ((IOStream*)fd)->write(fd, buf, nbytes); - if(r < 0) { + size_t w = 0; + size_t remaining = nbytes; + const char *cbuf = buf; + ssize_t r = 0; + int attempts = 0; + while(w < nbytes && attempts < net_write_max_attempts) { + r = ((IOStream*)fd)->write(fd, cbuf, remaining); + if(r <= 0) { + break; + } + w += r; + cbuf += r; + remaining -= r; + attempts++; + } + if(r < 0 && w == 0) { return IO_ERROR; } - return r; + return w; } ssize_t net_writev(SYS_NETFD fd, struct iovec *iovec, int iovcnt) {
--- a/src/server/util/io.h Tue Sep 12 18:08:11 2023 +0200 +++ b/src/server/util/io.h Sat Mar 30 12:35:09 2024 +0100 @@ -55,6 +55,9 @@ #define IO_POLL_IN 1 #define IO_POLL_OUT 2 +#define IO_STREAM_TYPE_HTTP 0x48545450 +#define IO_STREAM_TYPE_SSL 0x53534C + typedef struct IOStream IOStream; typedef struct Sysstream Sysstream; typedef struct HttpStream HttpStream; @@ -78,6 +81,7 @@ io_setmode_f setmode; io_poll_f poll; int io_errno; + unsigned int type; }; struct Sysstream { @@ -180,7 +184,7 @@ int error; } SSLStream; - +void io_set_max_writes(int n); /* system stream */ IOStream* Sysstream_new(pool_handle_t *pool, SYS_SOCKET fd);
--- a/src/server/webdav/multistatus.c Tue Sep 12 18:08:11 2023 +0200 +++ b/src/server/webdav/multistatus.c Sat Mar 30 12:35:09 2024 +0100 @@ -348,7 +348,9 @@ // start http response protocol_status(ms->sn, ms->rq, 207, NULL); - protocol_start_response(ms->sn, ms->rq); + if(protocol_start_response(ms->sn, ms->rq)) { + return 1; + } char buffer[MULTISTATUS_BUFFER_LENGTH]; // create a writer, that flushes the buffer when it is filled