Просмотр исходного кода

Rewrite string handling (Step 1/?)

Replace all uses of (v)snprintf by mg_(v)snprintf
See issue #175
(Step 1 is a commit of a partial work and will not build)
bel 10 лет назад
Родитель
Сommit
8ea5607c54
2 измененных файлов с 164 добавлено и 142 удалено
  1. 158 140
      src/civetweb.c
  2. 6 2
      src/mod_lua.inl

+ 158 - 140
src/civetweb.c

@@ -272,8 +272,8 @@ typedef long off_t;
 #define SHUT_RD (0)
 #define SHUT_WR (1)
 #define SHUT_BOTH (2)
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
+#define vsnprintf_impl(buf, buflen, fmt, ap)                                   \
+	(void) _vsnprintf(buf, buflen, fmt, ap), buf[buflen - 1] = 0
 #define access _access
 #define mg_sleep(x) (Sleep(x))
 
@@ -392,6 +392,10 @@ typedef unsigned short int in_port_t;
 #include <unistd.h>
 #include <grp.h>
 #include <dirent.h>
+#define vsnprintf_impl                                                         \
+	(void) vsnprintf /* vsnprintf can be used directly if not on               \
+	                  * Windows/Visual studio */
+
 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
 #include <dlfcn.h>
 #endif
@@ -678,6 +682,20 @@ static __inline void mg_free(void *a) { free(a); }
 
 #endif
 
+
+static void mg_vsnprintf(const struct mg_connection *conn,
+                         char *buf,
+                         size_t buflen,
+                         const char *fmt,
+                         va_list ap);
+
+static void mg_snprintf(const struct mg_connection *conn,
+                        char *buf,
+                        size_t buflen,
+                        PRINTF_FORMAT_STRING(const char *fmt),
+                        ...) PRINTF_ARGS(4, 5);
+
+
 /* This following lines are just meant as a reminder to use the mg-functions
  * for memory management */
 #ifdef malloc
@@ -696,6 +714,8 @@ static __inline void mg_free(void *a) { free(a); }
 #define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
 #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
 #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
+#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
+#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
 
 #define MD5_STATIC static
 #include "md5.inl"
@@ -1154,15 +1174,9 @@ typedef struct tagTHREADNAME_INFO {
 
 static void mg_set_thread_name(const char *name)
 {
-	char threadName[16]; /* Max. thread length in Linux/OSX/.. */
-
-	/* TODO (low): use strcpy and strcat instad of snprintf, use server name,
-	 * don't
-	 * return */
-	if (snprintf(threadName, sizeof(threadName), "civetweb-%s", name) < 0) {
-		return;
-	}
+	char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
 
+	mg_snprintf(NULL, threadName, sizeof(threadName), "civetweb-%s", name);
 	threadName[sizeof(threadName) - 1] = 0;
 
 #if defined(_WIN32)
@@ -1341,20 +1355,18 @@ static const char *mg_strcasestr(const char *big_str, const char *small_str)
 	return NULL;
 }
 
-/* Like snprintf(), but never returns negative value, or a value
- * that is larger than a supplied buffer.
- * Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
- * in his audit report. */
-static int mg_vsnprintf(struct mg_connection *conn,
-                        char *buf,
-                        size_t buflen,
-                        const char *fmt,
-                        va_list ap)
+/* Return null terminated string of given maximum length.
+ * Report errors if length is exceeded. */
+static void mg_vsnprintf(const struct mg_connection *conn,
+                         char *buf,
+                         size_t buflen,
+                         const char *fmt,
+                         va_list ap)
 {
 	int n;
 
 	if (buflen == 0) {
-		return 0;
+		return;
 	}
 
 #ifdef __clang__
@@ -1364,7 +1376,7 @@ static int mg_vsnprintf(struct mg_connection *conn,
  * indirectly by mg_snprintf */
 #endif
 
-	n = vsnprintf(buf, buflen, fmt, ap);
+	vsnprintf_impl(buf, buflen, fmt, ap);
 
 #ifdef __clang__
 #pragma clang diagnostic pop
@@ -1381,27 +1393,19 @@ static int mg_vsnprintf(struct mg_connection *conn,
 		n = (int)buflen - 1;
 	}
 	buf[n] = '\0';
-
-	return n;
 }
 
-static int mg_snprintf(struct mg_connection *conn,
-                       char *buf,
-                       size_t buflen,
-                       PRINTF_FORMAT_STRING(const char *fmt),
-                       ...) PRINTF_ARGS(4, 5);
-
-static int mg_snprintf(
-    struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, ...)
+static void mg_snprintf(const struct mg_connection *conn,
+                        char *buf,
+                        size_t buflen,
+                        const char *fmt,
+                        ...)
 {
 	va_list ap;
-	int n;
 
 	va_start(ap, fmt);
-	n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
+	mg_vsnprintf(conn, buf, buflen, fmt, ap);
 	va_end(ap);
-
-	return n;
 }
 
 static int get_option_index(const char *name)
@@ -1529,7 +1533,7 @@ void mg_cry(const struct mg_connection *conn, const char *fmt, ...)
 	time_t timestamp;
 
 	va_start(ap, fmt);
-	IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap));
+	IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
 	va_end(ap);
 
 	/* Do not lock when getting the callback value, here and below.
@@ -1981,7 +1985,7 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
 {
 	char buf[MG_BUF_LEN];
 	va_list ap;
-	int len = 0, i, page_handler_found, scope;
+	int len, i, page_handler_found, scope;
 	char date[64];
 	time_t curtime = time(NULL);
 	const char *error_handler = NULL;
@@ -2005,31 +2009,33 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
 			if (error_handler != NULL) {
 				for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
 					switch (scope) {
-					case 1:
-						len = mg_snprintf(conn,
-						                  buf,
-						                  sizeof(buf) - 32,
-						                  "%serror%03u.",
-						                  error_handler,
-						                  status);
+					case 1: /* Handler for specific error, e.g. 404 error */
+						mg_snprintf(conn,
+						            buf,
+						            sizeof(buf) - 32,
+						            "%serror%03u.",
+						            error_handler,
+						            status);
 						break;
-					case 2:
-						len = mg_snprintf(conn,
-						                  buf,
-						                  sizeof(buf) - 32,
-						                  "%serror%01uxx.",
-						                  error_handler,
-						                  status / 100);
+					case 2: /* Handler for error group, e.g., 5xx error handler
+					         * for all server errors (500-599) */
+						mg_snprintf(conn,
+						            buf,
+						            sizeof(buf) - 32,
+						            "%serror%01uxx.",
+						            error_handler,
+						            status / 100);
 						break;
-					default:
-						len = mg_snprintf(conn,
-						                  buf,
-						                  sizeof(buf) - 32,
-						                  "%serror.",
-						                  error_handler);
+					default: /* Handler for all errors */
+						mg_snprintf(conn,
+						            buf,
+						            sizeof(buf) - 32,
+						            "%serror.",
+						            error_handler);
 						break;
 					}
 					tstr = strchr(error_page_file_ext, '.');
+					len = (int)strlen(buf);
 					while (tstr) {
 						for (i = 1; i < 32 && tstr[i] != 0 && tstr[i] != ',';
 						     i++)
@@ -2052,40 +2058,34 @@ send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
 			}
 		}
 
-		buf[0] = '\0';
+		/* No custom error page. Send default error page. */
 		gmt_time_string(date, sizeof(date), &curtime);
 
+		conn->must_close = 1;
+		mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
+		mg_printf(conn,
+		          "Date: %s\r\n"
+		          "Connection: close\r\n\r\n",
+		          date);
+
 		/* Errors 1xx, 204 and 304 MUST NOT send a body */
 		if (status > 199 && status != 204 && status != 304) {
-			len = mg_snprintf(conn,
-			                  buf,
-			                  sizeof(buf) - 1,
-			                  "Error %d: %s",
-			                  status,
-			                  status_text);
-			buf[len] = '\n';
-			len++;
-			buf[len] = 0;
-
-			va_start(ap, fmt);
-			len += mg_vsnprintf(
-			    conn, buf + len, sizeof(buf) - (size_t)len, fmt, ap);
-			va_end(ap);
-		}
-		DEBUG_TRACE("[%s]", buf);
 
-		mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
-		if (len > 0) {
-			mg_printf(conn, "Content-Type: text/plain\r\n");
+			mg_printf(conn, "Error %d: %s\n", status, status_text);
+
+			if (fmt != NULL) {
+				va_start(ap, fmt);
+				mg_vsnprintf(
+				    conn, buf + len, sizeof(buf) - (size_t)len, fmt, ap);
+				va_end(ap);
+				mg_write(conn, buf, strlen(buf));
+				DEBUG_TRACE("Error %i - [%s]", status, buf);
+			}
+
+		} else {
+			/* No body allowed. Close the connection. */
+			DEBUG_TRACE("Error %i", status);
 		}
-		mg_printf(conn,
-		          "Content-Length: %d\r\n"
-		          "Date: %s\r\n"
-		          "Connection: %s\r\n\r\n",
-		          len,
-		          date,
-		          suggest_connection_header(conn));
-		conn->num_bytes_sent += mg_printf(conn, "%s", buf);
 	}
 }
 
@@ -2703,7 +2703,7 @@ static pid_t spawn_process(struct mg_connection *conn,
 		buf[0] = buf[1] = '\0';
 
 		/* Read the first line of the script into the buffer */
-		snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
+		mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
 		if (mg_fopen(conn, cmdline, "r", &file)) {
 			p = (char *)file.membuf;
 			mg_fgets(buf, sizeof(buf), &file, &p);
@@ -3853,7 +3853,7 @@ interpret_uri(struct mg_connection *conn,   /* in: request */
 		if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) !=
 		    NULL) {
 			if (strstr(accept_encoding, "gzip") != NULL) {
-				snprintf(gz_path, sizeof(gz_path), "%s.gz", filename);
+				mg_snprintf(conn, gz_path, sizeof(gz_path), "%s.gz", filename);
 				if (mg_stat(conn, gz_path, filep)) {
 					if (filep) {
 						filep->gzipped = 1;
@@ -4711,9 +4711,14 @@ int mg_modify_passwords_file(const char *fname,
 		return 0;
 	}
 
-	/* Create a temporary file name */
-	(void)snprintf(tmp, sizeof(tmp) - 1, "%s.tmp", fname);
-	tmp[sizeof(tmp) - 1] = 0;
+	/* The maximum length of the path to the password file is limited */
+	if ((strlen(fname) + 4) >= PATH_MAX) {
+		return 0;
+	}
+
+	/* Create a temporary file name. Length has been checked before. */
+	strcpy(tmp, fname);
+	strcat(tmp, ".tmp");
 
 	/* Create the file if does not exist */
 	if ((fp = fopen(fname, "a+")) != NULL) {
@@ -4813,17 +4818,17 @@ static SOCKET conn2(struct mg_context *ctx /* may be null */,
 	}
 
 	if (host == NULL) {
-		snprintf(ebuf, ebuf_len, "%s", "NULL host");
+		mg_snprintf(NULL, ebuf, ebuf_len, "%s", "NULL host");
 		return INVALID_SOCKET;
 	}
 
 	if (port < 0 || !is_valid_port((unsigned)port)) {
-		snprintf(ebuf, ebuf_len, "%s", "invalid port");
+		mg_snprintf(NULL, ebuf, ebuf_len, "%s", "invalid port");
 		return INVALID_SOCKET;
 	}
 
 	if (use_ssl && (SSLv23_client_method == NULL)) {
-		snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
+		mg_snprintf(NULL, ebuf, ebuf_len, "%s", "SSL is not initialized");
 		return INVALID_SOCKET;
 	}
 
@@ -4834,14 +4839,14 @@ static SOCKET conn2(struct mg_context *ctx /* may be null */,
 		sa.sin6.sin6_port = htons((uint16_t)port);
 #endif
 	} else {
-		snprintf(ebuf, ebuf_len, "%s", "host not found");
+		mg_snprintf(NULL, ebuf, ebuf_len, "%s", "host not found");
 		return INVALID_SOCKET;
 	}
 
 	sock = socket(PF_INET, SOCK_STREAM, 0);
 
 	if (sock == INVALID_SOCKET) {
-		snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
+		mg_snprintf(NULL, ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
 		return INVALID_SOCKET;
 	}
 
@@ -4849,8 +4854,13 @@ static SOCKET conn2(struct mg_context *ctx /* may be null */,
 
 	/* TODO(mid): IPV6 */
 	if (connect(sock, (struct sockaddr *)&sa.sin, sizeof(sa.sin)) != 0) {
-		snprintf(
-		    ebuf, ebuf_len, "connect(%s:%d): %s", host, port, strerror(ERRNO));
+		mg_snprintf(NULL,
+		            ebuf,
+		            ebuf_len,
+		            "connect(%s:%d): %s",
+		            host,
+		            port,
+		            strerror(ERRNO));
 		closesocket(sock);
 		sock = INVALID_SOCKET;
 	}
@@ -5303,11 +5313,12 @@ static int parse_range_header(const char *header, int64_t *a, int64_t *b)
 static void construct_etag(char *buf, size_t buf_len, const struct file *filep)
 {
 	if (filep != NULL && buf != NULL) {
-		snprintf(buf,
-		         buf_len,
-		         "\"%lx.%" INT64_FMT "\"",
-		         (unsigned long)filep->last_modified,
-		         filep->size);
+		mg_snprintf(NULL,
+		            buf,
+		            buf_len,
+		            "\"%lx.%" INT64_FMT "\"",
+		            (unsigned long)filep->last_modified,
+		            filep->size);
 	}
 }
 
@@ -5360,7 +5371,7 @@ static void handle_static_file_request(struct mg_connection *conn,
 	 * it's important to rewrite the filename after resolving
 	 * the mime type from it, to preserve the actual file's type */
 	if (filep->gzipped) {
-		snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
+		mg_snprintf(conn, gz_path, sizeof(gz_path), "%s.gz", path);
 		path = gz_path;
 		encoding = "Content-Encoding: gzip\r\n";
 	}
@@ -5787,7 +5798,7 @@ static char *addenv(struct cgi_env_block *block,
  * pointer into the vars array. */
 static char *addenv(struct cgi_env_block *block, const char *fmt, ...)
 {
-	int n, space;
+	unsigned int n, space;
 	char *added;
 	va_list ap;
 
@@ -5796,9 +5807,8 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...)
 	}
 
 	/* Calculate how much space is left in the buffer */
-	space = (int)(sizeof(block->buf) - block->len) - 2;
-	/* assert(space >= 0); */
-	if (space < 0) {
+	space = (sizeof(block->buf) - block->len) - 2;
+	if (space <= 0) {
 		return NULL;
 	}
 
@@ -5807,15 +5817,18 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...)
 
 	/* Copy VARIABLE=VALUE\0 string into the free space */
 	va_start(ap, fmt);
-	n = mg_vsnprintf(block->conn, added, (size_t)space, fmt, ap);
+	mg_vsnprintf(block->conn, added, (size_t)space, fmt, ap);
 	va_end(ap);
 
+	/* Number of bytes added to the environment */
+	n = strlen(added) + 1;
+
 	/* Make sure we do not overflow buffer and the envp array */
-	if (n > 0 && n + 1 < space && block->nvars + 2 < ARRAY_SIZE(block->vars)) {
+	if (n < space && block->nvars + 2 < ARRAY_SIZE(block->vars)) {
 		/* Append a pointer to the added string into the envp array */
 		block->vars[block->nvars++] = added;
 		/* Bump up used length counter. Include \0 terminator */
-		block->len += (unsigned int)(n) + 1;
+		block->len += n;
 	} else {
 		mg_cry(block->conn,
 		       "%s: CGI env buffer truncated for [%s]",
@@ -7585,7 +7598,7 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir)
 
 		/* There data is written to a temporary file first. */
 		/* Different users should use a different destination_dir. */
-		snprintf(path, sizeof(path) - 1, "%s/%s", destination_dir, s);
+		mg_snprintf(conn, path, sizeof(path) - 1, "%s/%s", destination_dir, s);
 		strcpy(tmp_path, path);
 		strcat(tmp_path, "~");
 
@@ -8695,19 +8708,20 @@ static void log_access(const struct mg_connection *conn)
 	referer = header_val(conn, "Referer");
 	user_agent = header_val(conn, "User-Agent");
 
-	snprintf(buf,
-	         sizeof(buf),
-	         "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT " %s %s",
-	         src_addr,
-	         ri->remote_user == NULL ? "-" : ri->remote_user,
-	         date,
-	         ri->request_method ? ri->request_method : "-",
-	         ri->uri ? ri->uri : "-",
-	         ri->http_version,
-	         conn->status_code,
-	         conn->num_bytes_sent,
-	         referer,
-	         user_agent);
+	mg_snprintf(conn,
+	            buf,
+	            sizeof(buf),
+	            "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT " %s %s",
+	            src_addr,
+	            ri->remote_user == NULL ? "-" : ri->remote_user,
+	            date,
+	            ri->request_method ? ri->request_method : "-",
+	            ri->uri ? ri->uri : "-",
+	            ri->http_version,
+	            conn->status_code,
+	            conn->num_bytes_sent,
+	            referer,
+	            user_agent);
 
 	if (conn->ctx->callbacks.log_access) {
 		conn->ctx->callbacks.log_access(conn, buf);
@@ -9224,13 +9238,13 @@ struct mg_connection *mg_connect_client(
 	    INVALID_SOCKET) {
 	} else if ((conn = (struct mg_connection *)mg_calloc(
 	                1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
-		snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
+		mg_snprintf(NULL, ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
 		closesocket(sock);
 #ifndef NO_SSL
 	} else if (use_ssl &&
 	           (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method())) ==
 	               NULL) {
-		snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
+		mg_snprintf(NULL, ebuf, ebuf_len, "SSL_CTX_new error");
 		closesocket(sock);
 		mg_free(conn);
 		conn = NULL;
@@ -9284,7 +9298,7 @@ getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
 	reset_per_request_attributes(conn);
 
 	if (!conn) {
-		snprintf(ebuf, ebuf_len, "%s", "Internal error");
+		mg_snprintf(conn, ebuf, ebuf_len, "%s", "Internal error");
 		*err = 500;
 		return 0;
 	}
@@ -9296,29 +9310,31 @@ getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
 	    read_request(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
 	/* assert(conn->request_len < 0 || conn->data_len >= conn->request_len); */
 	if (conn->request_len >= 0 && conn->data_len < conn->request_len) {
-		snprintf(ebuf, ebuf_len, "%s", "Invalid request size");
+		mg_snprintf(conn, ebuf, ebuf_len, "%s", "Invalid request size");
 		*err = 500;
 		return 0;
 	}
 
 	if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
-		snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
+		mg_snprintf(conn, ebuf, ebuf_len, "%s", "Request Too Large");
 		*err = 413;
 		return 0;
 	} else if (conn->request_len <= 0) {
 		if (conn->data_len > 0) {
-			snprintf(ebuf, ebuf_len, "%s", "Client sent malformed request");
+			mg_snprintf(
+			    conn, ebuf, ebuf_len, "%s", "Client sent malformed request");
 			*err = 400;
 		} else {
 			/* Server did not send anything -> just close the connection */
 			conn->must_close = 1;
-			snprintf(ebuf, ebuf_len, "%s", "Client did not send a request");
+			mg_snprintf(
+			    conn, ebuf, ebuf_len, "%s", "Client did not send a request");
 			*err = 0;
 		}
 		return 0;
 	} else if (parse_http_message(
 	               conn->buf, conn->buf_size, &conn->request_info) <= 0) {
-		snprintf(ebuf, ebuf_len, "%s", "Bad Request");
+		mg_snprintf(conn, ebuf, ebuf_len, "%s", "Bad Request");
 		*err = 400;
 		return 0;
 	} else {
@@ -9328,7 +9344,7 @@ getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
 			char *endptr = NULL;
 			conn->content_len = strtoll(cl, &endptr, 10);
 			if (endptr == cl) {
-				snprintf(ebuf, ebuf_len, "%s", "Bad Request");
+				mg_snprintf(conn, ebuf, ebuf_len, "%s", "Bad Request");
 				*err = 411;
 				return 0;
 			}
@@ -9367,7 +9383,7 @@ int mg_get_response(struct mg_connection *conn,
 		char txt[32];
 
 		if (timeout >= 0) {
-			snprintf(txt, sizeof(txt), "%i", timeout);
+			mg_snprintf(conn, txt, sizeof(txt), "%i", timeout);
 			rctx.config[REQUEST_TIMEOUT] = txt;
 			set_sock_timeout(conn->client.sock, timeout);
 		} else {
@@ -9407,7 +9423,7 @@ struct mg_connection *mg_download(const char *host,
 	if (conn != NULL) {
 		i = mg_vprintf(conn, fmt, ap);
 		if (i <= 0) {
-			snprintf(ebuf, ebuf_len, "%s", "Error sending request");
+			mg_snprintf(conn, ebuf, ebuf_len, "%s", "Error sending request");
 		} else {
 			getreq(conn, ebuf, ebuf_len, &reqerr);
 		}
@@ -9598,14 +9614,16 @@ static void process_new_connection(struct mg_connection *conn)
 					send_http_error(conn, reqerr, "%s", ebuf);
 				}
 			} else if (!is_valid_uri(conn->request_info.uri)) {
-				snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
+				mg_snprintf(
+				    conn, ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
 				send_http_error(conn, 400, "%s", ebuf);
 			} else if (strcmp(ri->http_version, "1.0") &&
 			           strcmp(ri->http_version, "1.1")) {
-				snprintf(ebuf,
-				         sizeof(ebuf),
-				         "Bad HTTP version: [%s]",
-				         ri->http_version);
+				mg_snprintf(conn,
+				            ebuf,
+				            sizeof(ebuf),
+				            "Bad HTTP version: [%s]",
+				            ri->http_version);
 				send_http_error(conn, 505, "%s", ebuf);
 			}
 

+ 6 - 2
src/mod_lua.inl

@@ -324,8 +324,12 @@ static int lsp(struct mg_connection *conn,
 				if ((j + 1) < len && p[j] == '?' && p[j + 1] == '>') {
 					mg_write(conn, p + pos, i - pos);
 
-					snprintf(
-					    chunkname, sizeof(chunkname), "@%s+%i", path, lines);
+					mg_snprintf(conn,
+					            chunkname,
+					            sizeof(chunkname),
+					            "@%s+%i",
+					            path,
+					            lines);
 					lua_pushlightuserdata(L, conn);
 					lua_pushcclosure(L, lsp_error, 1);