From 0f15fe172acfdc39b972396a0262a15ecb4e063f Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Sun, 11 Dec 2016 12:38:17 +0100 Subject: [PATCH] Moved mg_vprintf to own file --- Makefile | 1 + src/httplib_vprintf.c | 122 ++++++++++++++++++++++++++++++++++++++++++ src/libhttp.c | 96 +-------------------------------- 3 files changed, 125 insertions(+), 94 deletions(-) create mode 100644 src/httplib_vprintf.c diff --git a/Makefile b/Makefile index 77f3ce12..5abf3a33 100644 --- a/Makefile +++ b/Makefile @@ -167,6 +167,7 @@ LIB_SOURCES = src/libhttp.c \ src/httplib_url_decode.c \ src/httplib_url_encode.c \ src/httplib_version.c \ + src/httplib_vprintf.c \ src/httplib_websocket_client_thread.c \ src/httplib_websocket_client_write.c \ src/httplib_websocket_write.c \ diff --git a/src/httplib_vprintf.c b/src/httplib_vprintf.c new file mode 100644 index 00000000..6446319f --- /dev/null +++ b/src/httplib_vprintf.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* Alternative alloc_vprintf() for non-compliant C runtimes */ +static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) { + + va_list ap_copy; + size_t size = MG_BUF_LEN / 4; + int len = -1; + + *buf = NULL; + while (len < 0) { + if (*buf) XX_httplib_free(*buf); + + size *= 4; + *buf = (char *)XX_httplib_malloc(size); + if (!*buf) break; + + va_copy(ap_copy, ap); + len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy); + va_end(ap_copy); + (*buf)[size - 1] = 0; + } + + return len; +} + + +/* Print message to buffer. If buffer is large enough to hold the message, + * return buffer. If buffer is to small, allocate large enough buffer on heap, + * and return allocated buffer. */ +static int alloc_vprintf( char **out_buf, char *prealloc_buf, size_t prealloc_size, const char *fmt, va_list ap ) { + + va_list ap_copy; + int len; + + /* Windows is not standard-compliant, and vsnprintf() returns -1 if + * buffer is too small. Also, older versions of msvcrt.dll do not have + * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly. + * Therefore, we make two passes: on first pass, get required message + * length. + * On second pass, actually print the message. */ + va_copy(ap_copy, ap); + len = vsnprintf_impl(NULL, 0, fmt, ap_copy); + va_end(ap_copy); + + if (len < 0) { + /* C runtime is not standard compliant, vsnprintf() returned -1. + * Switch to alternative code path that uses incremental allocations. + */ + va_copy(ap_copy, ap); + len = alloc_vprintf2(out_buf, fmt, ap); + va_end(ap_copy); + + } else if ((size_t)(len) >= prealloc_size) { + /* The pre-allocated buffer not large enough. */ + /* Allocate a new buffer. */ + *out_buf = (char *)XX_httplib_malloc((size_t)(len) + 1); + if (!*out_buf) { + /* Allocation failed. Return -1 as "out of memory" error. */ + return -1; + } + /* Buffer allocation successful. Store the string there. */ + va_copy(ap_copy, ap); + IGNORE_UNUSED_RESULT( + vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy)); + va_end(ap_copy); + + } else { + /* The pre-allocated buffer is large enough. + * Use it to store the string and return the address. */ + va_copy(ap_copy, ap); + IGNORE_UNUSED_RESULT( + vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy)); + va_end(ap_copy); + *out_buf = prealloc_buf; + } + + return len; + +} /* alloc_vprintf */ + + +int XX_httplib_vprintf( struct mg_connection *conn, const char *fmt, va_list ap ) { + + char mem[MG_BUF_LEN]; + char *buf = NULL; + int len; + + if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) len = mg_write(conn, buf, (size_t)len); + if (buf != mem && buf != NULL) XX_httplib_free(buf); + + return len; + +} /* XX_httplib_vprintf */ diff --git a/src/libhttp.c b/src/libhttp.c index 82322b2f..a112b48f 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -3025,7 +3025,7 @@ int mg_read(struct mg_connection *conn, void *buf, size_t len) { } -int mg_write(struct mg_connection *conn, const void *buf, size_t len) { +int mg_write( struct mg_connection *conn, const void *buf, size_t len ) { time_t now; int64_t n; @@ -3073,97 +3073,5 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len) { else total = XX_httplib_push_all(conn->ctx, NULL, conn->client.sock, conn->ssl, (const char *)buf, (int64_t)len); return (int)total; -} - -/* Alternative alloc_vprintf() for non-compliant C runtimes */ -static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) { - - va_list ap_copy; - size_t size = MG_BUF_LEN / 4; - int len = -1; - - *buf = NULL; - while (len < 0) { - if (*buf) XX_httplib_free(*buf); - - size *= 4; - *buf = (char *)XX_httplib_malloc(size); - if (!*buf) break; - - va_copy(ap_copy, ap); - len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy); - va_end(ap_copy); - (*buf)[size - 1] = 0; - } - - return len; -} - - -/* Print message to buffer. If buffer is large enough to hold the message, - * return buffer. If buffer is to small, allocate large enough buffer on heap, - * and return allocated buffer. */ -static int alloc_vprintf(char **out_buf, char *prealloc_buf, size_t prealloc_size, const char *fmt, va_list ap) { - - va_list ap_copy; - int len; - - /* Windows is not standard-compliant, and vsnprintf() returns -1 if - * buffer is too small. Also, older versions of msvcrt.dll do not have - * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly. - * Therefore, we make two passes: on first pass, get required message - * length. - * On second pass, actually print the message. */ - va_copy(ap_copy, ap); - len = vsnprintf_impl(NULL, 0, fmt, ap_copy); - va_end(ap_copy); - - if (len < 0) { - /* C runtime is not standard compliant, vsnprintf() returned -1. - * Switch to alternative code path that uses incremental allocations. - */ - va_copy(ap_copy, ap); - len = alloc_vprintf2(out_buf, fmt, ap); - va_end(ap_copy); - - } else if ((size_t)(len) >= prealloc_size) { - /* The pre-allocated buffer not large enough. */ - /* Allocate a new buffer. */ - *out_buf = (char *)XX_httplib_malloc((size_t)(len) + 1); - if (!*out_buf) { - /* Allocation failed. Return -1 as "out of memory" error. */ - return -1; - } - /* Buffer allocation successful. Store the string there. */ - va_copy(ap_copy, ap); - IGNORE_UNUSED_RESULT( - vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy)); - va_end(ap_copy); - - } else { - /* The pre-allocated buffer is large enough. - * Use it to store the string and return the address. */ - va_copy(ap_copy, ap); - IGNORE_UNUSED_RESULT( - vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy)); - va_end(ap_copy); - *out_buf = prealloc_buf; - } - - return len; -} - - -int XX_httplib_vprintf( struct mg_connection *conn, const char *fmt, va_list ap ) { - - char mem[MG_BUF_LEN]; - char *buf = NULL; - int len; - - if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) len = mg_write(conn, buf, (size_t)len); - if (buf != mem && buf != NULL) XX_httplib_free(buf); - - return len; - -} /* XX_httplib_vprintf */ +} /* mg_write */