|  | @@ -3887,6 +3887,7 @@ mg_getc(struct mg_connection *conn)
 | 
	
		
			
				|  |  |  	return c;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_read(struct mg_connection *conn, void *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
	
		
			
				|  | @@ -3966,6 +3967,7 @@ mg_read(struct mg_connection *conn, void *buf, size_t len)
 | 
	
		
			
				|  |  |  	return mg_read_inner(conn, buf, len);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_write(struct mg_connection *conn, const void *buf, size_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
	
		
			
				|  | @@ -4055,7 +4057,11 @@ alloc_vprintf2(char **buf, const char *fmt, va_list ap)
 | 
	
		
			
				|  |  |   * return buffer. If buffer is to small, allocate large enough buffer on heap,
 | 
	
		
			
				|  |  |   * and return allocated buffer. */
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  | -alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
 | 
	
		
			
				|  |  | +alloc_vprintf(char **out_buf,
 | 
	
		
			
				|  |  | +              char *prealloc_buf,
 | 
	
		
			
				|  |  | +              size_t prealloc_size,
 | 
	
		
			
				|  |  | +              const char *fmt,
 | 
	
		
			
				|  |  | +              va_list ap)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	va_list ap_copy;
 | 
	
		
			
				|  |  |  	int len;
 | 
	
	
		
			
				|  | @@ -4075,15 +4081,30 @@ alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
 | 
	
		
			
				|  |  |  		 * Switch to alternative code path that uses incremental allocations.
 | 
	
		
			
				|  |  |  		*/
 | 
	
		
			
				|  |  |  		va_copy(ap_copy, ap);
 | 
	
		
			
				|  |  | -		len = alloc_vprintf2(buf, fmt, 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 *)mg_malloc(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, len + 1, fmt, ap_copy));
 | 
	
		
			
				|  |  |  		va_end(ap_copy);
 | 
	
		
			
				|  |  | -	} else if ((size_t)(len) > size && (size = (size_t)(len) + 1) > 0
 | 
	
		
			
				|  |  | -	           && (*buf = (char *)mg_malloc(size)) == NULL) {
 | 
	
		
			
				|  |  | -		len = -1; /* Allocation failed, mark failure */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	} 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(*buf, size, fmt, ap_copy));
 | 
	
		
			
				|  |  | +		IGNORE_UNUSED_RESULT(
 | 
	
		
			
				|  |  | +		    vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy));
 | 
	
		
			
				|  |  |  		va_end(ap_copy);
 | 
	
		
			
				|  |  | +		*out_buf = prealloc_buf;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	return len;
 | 
	
	
		
			
				|  | @@ -4093,10 +4114,11 @@ alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -	char mem[MG_BUF_LEN], *buf = mem;
 | 
	
		
			
				|  |  | +	char mem[MG_BUF_LEN];
 | 
	
		
			
				|  |  | +	char *buf = NULL;
 | 
	
		
			
				|  |  |  	int len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
 | 
	
		
			
				|  |  | +	if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) {
 | 
	
		
			
				|  |  |  		len = mg_write(conn, buf, (size_t)len);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	if (buf != mem && buf != NULL) {
 | 
	
	
		
			
				|  | @@ -4106,6 +4128,7 @@ mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
 | 
	
		
			
				|  |  |  	return len;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_printf(struct mg_connection *conn, const char *fmt, ...)
 | 
	
		
			
				|  |  |  {
 | 
	
	
		
			
				|  | @@ -4119,6 +4142,7 @@ mg_printf(struct mg_connection *conn, const char *fmt, ...)
 | 
	
		
			
				|  |  |  	return result;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_url_decode(const char *src,
 | 
	
		
			
				|  |  |                int src_len,
 | 
	
	
		
			
				|  | @@ -4149,6 +4173,7 @@ mg_url_decode(const char *src,
 | 
	
		
			
				|  |  |  	return i >= src_len ? j : -1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_get_var(const char *data,
 | 
	
		
			
				|  |  |             size_t data_len,
 | 
	
	
		
			
				|  | @@ -4159,6 +4184,7 @@ mg_get_var(const char *data,
 | 
	
		
			
				|  |  |  	return mg_get_var2(data, data_len, name, dst, dst_len, 0);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_get_var2(const char *data,
 | 
	
		
			
				|  |  |              size_t data_len,
 | 
	
	
		
			
				|  | @@ -4215,6 +4241,7 @@ mg_get_var2(const char *data,
 | 
	
		
			
				|  |  |  	return len;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  mg_get_cookie(const char *cookie_header,
 | 
	
		
			
				|  |  |                const char *var_name,
 |