Tue, 17 Mar 2026 20:49:37 +0100
add test_io_httpstream_chunked_write_partial_writev
--- a/src/server/test/io.c Mon Mar 16 19:44:18 2026 +0100 +++ b/src/server/test/io.c Tue Mar 17 20:49:37 2026 +0100 @@ -675,6 +675,41 @@ } } +CX_TEST(test_io_httpstream_chunked_write_partial_writev) { + Session *sn = testutil_session(); + + TestIOStream *st = testutil_iostream(2048, TRUE); + IOStream *http = httpstream_new(sn->pool, (IOStream*)st); + httpstream_enable_chunked_write(http); + io_set_max_writes(1); + + CX_TEST_DO { + + memset(st->buf->space, 0, st->buf->capacity); + + char *msg = "hello world!"; + size_t msglen = strlen(msg); + + // Test: write complete chunk header, zero data + + st->max_write = 3; + ssize_t w = net_write(http, msg, msglen); + + CX_TEST_ASSERT(w == 0); + + st->max_write = 1000; + w = net_write(http, msg, msglen); + + CX_TEST_ASSERT(w == msglen); + + CX_TEST_ASSERT(!memcmp(st->buf->space, "c\r\nhello world!\r\n", st->buf->size)); + + testutil_destroy_session(sn); + testutil_iostream_destroy(st); + + } +} + CX_TEST(test_io_httpstream_chunked_write_data_2x) { Session *sn = testutil_session();
--- a/src/server/test/io.h Mon Mar 16 19:44:18 2026 +0100 +++ b/src/server/test/io.h Tue Mar 17 20:49:37 2026 +0100 @@ -57,6 +57,7 @@ CX_TEST(test_io_httpstream_chunked_write_partial_data); CX_TEST(test_io_httpstream_chunked_write_partial_trailer); CX_TEST(test_io_httpstream_chunked_write_partial_trailer_partial_header); +CX_TEST(test_io_httpstream_chunked_write_partial_writev); CX_TEST(test_io_httpstream_chunked_write_data_2x); CX_TEST(test_io_httpstream_chunked_write_xx_limit);
--- a/src/server/test/main.c Mon Mar 16 19:44:18 2026 +0100 +++ b/src/server/test/main.c Tue Mar 17 20:49:37 2026 +0100 @@ -147,6 +147,7 @@ cx_test_register(suite, test_io_httpstream_chunked_write_partial_data); cx_test_register(suite, test_io_httpstream_chunked_write_partial_trailer); cx_test_register(suite, test_io_httpstream_chunked_write_partial_trailer_partial_header); + cx_test_register(suite, test_io_httpstream_chunked_write_partial_writev); cx_test_register(suite, test_io_httpstream_chunked_write_data_2x); cx_test_register(suite, test_io_httpstream_chunked_write_xx_limit); @@ -209,6 +210,7 @@ // http tests + /* http_client_add_tests(suite); cx_test_register(suite, test_http_client_simple_get1); cx_test_register(suite, test_http_client_simple_get_line_io); @@ -219,6 +221,7 @@ cx_test_register(suite, test_http_client_post_ctlen_large); cx_test_register(suite, test_http_client_get_incorrect_ctlen); cx_test_register(suite, test_http_client_broken_response); + * */ // plugin tests #ifdef ENABLE_POSTGRESQL
--- a/src/server/util/io.c Mon Mar 16 19:44:18 2026 +0100 +++ b/src/server/util/io.c Tue Mar 17 20:49:37 2026 +0100 @@ -68,6 +68,8 @@ #include "../daemon/event.h" #include <cx/printf.h> +#include <openssl/err.h> + IOStream native_io_funcs = { (io_write_f)net_sys_write, (io_writev_f)net_sys_writev, @@ -490,6 +492,7 @@ ssize_t wv = fd->writev(fd, io, iovec_len); if(wv <= 0) { + log_ereport(LOG_INFORM, "net_http_write chunk writev ret %d", (int)wv); st->st.io_errno = net_errno(st->fd); return wv; } @@ -864,11 +867,17 @@ ssize_t net_ssl_write(SSLStream *st, const void *buf, size_t nbytes) { int ret = SSL_write(st->ssl, buf, nbytes); + log_ereport(LOG_INFORM, "SSL_write(%p, %d) -> %d", buf, (int)nbytes, ret); if(ret <= 0) { st->error = SSL_get_error(st->ssl, ret); if(st->error == SSL_ERROR_WANT_WRITE || st->error == SSL_ERROR_WANT_READ) { st->st.io_errno = EWOULDBLOCK; } else { + log_ereport(LOG_FAILURE, "net_ssl_write SSL error: %d , nbytes: %d, ret: %d", st->error, (int)nbytes, ret); + unsigned long e; + while ((e = ERR_get_error())) { + fprintf(stderr, "%s\n", ERR_error_string(e, NULL)); + } st->st.io_errno = -1; } ret = -1; @@ -879,10 +888,13 @@ ssize_t net_ssl_writev(SSLStream *st, struct iovec *iovec, int iovcnt) { ssize_t r = 0; for(int i=0;i<iovcnt;i++) { + int ml = iovec[i].iov_len > 10 ? 10 : iovec[i].iov_len; int ret = SSL_write(st->ssl, iovec[i].iov_base, iovec[i].iov_len); + log_ereport(LOG_INFORM, "SSL_write(%p {%.*s}, %d) -> %d", iovec[i].iov_base, ml, iovec[i].iov_base, (int)iovec[i].iov_len, ret); if(ret <= 0) { if(r == 0) { st->error = SSL_get_error(st->ssl, ret); + log_ereport(LOG_FAILURE, "net_ssl_write SSL error: %d , iov_len: %d, ret: %d", st->error, (int)iovec[i].iov_len, ret); if(st->error == SSL_ERROR_WANT_WRITE || st->error == SSL_ERROR_WANT_READ) { st->st.io_errno = EWOULDBLOCK; } else {