소스 검색

Merge branch 'master' of https://github.com/civetweb/civetweb

bel2125 5 년 전
부모
커밋
b585bdaea7
3개의 변경된 파일126개의 추가작업 그리고 161개의 파일을 삭제
  1. 3 7
      include/CivetServer.h
  2. 73 109
      src/CivetServer.cpp
  3. 50 45
      src/civetweb.c

+ 3 - 7
include/CivetServer.h

@@ -245,7 +245,7 @@ class CIVETWEB_CXX_API CivetServer
 	CivetServer(const char **options,
 	            const struct CivetCallbacks *callbacks = 0,
 	            const void *UserContext = 0);
-	CivetServer(std::vector<std::string> options,
+	CivetServer(const std::vector<std::string> &options,
 	            const struct CivetCallbacks *callbacks = 0,
 	            const void *UserContext = 0);
 
@@ -583,15 +583,11 @@ class CIVETWEB_CXX_API CivetServer
 	class CivetConnection
 	{
 	  public:
-		char *postData;
-		unsigned long postDataLen;
-
-		CivetConnection();
-		~CivetConnection();
+		std::vector<char> postData;
 	};
 
 	struct mg_context *context;
-	std::map<struct mg_connection *, class CivetConnection> connections;
+	std::map<const struct mg_connection *, CivetConnection> connections;
 
 	// generic user context which can be set/read,
 	// the server does nothing with this apart from keep it.

+ 73 - 109
src/CivetServer.cpp

@@ -8,7 +8,6 @@
 
 #include <assert.h>
 #include <stdexcept>
-#include <stdlib.h>
 #include <string.h>
 
 #ifndef UNUSED_PARAMETER
@@ -295,7 +294,7 @@ CivetServer::CivetServer(const char **options,
 		                     "Possible problem binding to port.");
 }
 
-CivetServer::CivetServer(std::vector<std::string> options,
+CivetServer::CivetServer(const std::vector<std::string> &options,
                          const struct CivetCallbacks *_callbacks,
                          const void *UserContextIn)
     : context(0)
@@ -312,11 +311,11 @@ CivetServer::CivetServer(std::vector<std::string> options,
 	}
 	callbacks.connection_close = closeHandler;
 
-	std::vector<const char *> pointers(options.size());
+	std::vector<const char *> pointers(options.size() + 1);
 	for (size_t i = 0; i < options.size(); i++) {
 		pointers[i] = (options[i].c_str());
 	}
-	pointers.push_back(0);
+	pointers.back() = NULL;
 
 	context = mg_start(&callbacks, this, &pointers[0]);
 	if (context == NULL)
@@ -343,7 +342,7 @@ CivetServer::closeHandler(const struct mg_connection *conn)
 		me->userCloseHandler(conn);
 	}
 	mg_lock_context(me->context);
-	me->connections.erase(const_cast<struct mg_connection *>(conn));
+	me->connections.erase(conn);
 	mg_unlock_context(me->context);
 }
 
@@ -439,24 +438,16 @@ CivetServer::urlDecode(const char *src,
                        std::string &dst,
                        bool is_form_url_encoded)
 {
-	int i, j, a, b;
-#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
-
-	dst.clear();
-	for (i = j = 0; i < (int)src_len; i++, j++) {
-		if (i < (int)src_len - 2 && src[i] == '%'
-		    && isxdigit((unsigned char)src[i + 1])
-		    && isxdigit((unsigned char)src[i + 2])) {
-			a = tolower((unsigned char)src[i + 1]);
-			b = tolower((unsigned char)src[i + 2]);
-			dst.push_back((char)((HEXTOI(a) << 4) | HEXTOI(b)));
-			i += 2;
-		} else if (is_form_url_encoded && src[i] == '+') {
-			dst.push_back(' ');
-		} else {
-			dst.push_back(src[i]);
-		}
+	// assign enough buffer
+	std::vector<char> buf(src_len + 1);
+	int r = mg_url_decode(src, static_cast<int>(src_len), &buf[0],
+	                      static_cast<int>(buf.size()), is_form_url_encoded);
+	if (r < 0) {
+		// never reach here
+		throw std::out_of_range("");
 	}
+	// dst can contain NUL characters
+	dst.assign(buf.begin(), buf.begin() + r);
 }
 
 bool
@@ -476,44 +467,31 @@ CivetServer::getParam(struct mg_connection *conn,
 	mg_lock_connection(conn);
 	mg_unlock_context(me->context);
 
-	if (conobj.postData != NULL) {
-		// check if form parameter are already stored
-		formParams = conobj.postData;
-	} else {
-		// otherwise, check if there is a request body
-		const char *con_len_str = mg_get_header(conn, "Content-Length");
-		if (con_len_str) {
-			char *end = 0;
-			unsigned long con_len = strtoul(con_len_str, &end, 10);
-			if ((end == NULL) || (*end != 0)) {
-				// malformed header
-				mg_unlock_connection(conn);
-				return false;
-			}
-			if ((con_len > 0) && (con_len <= MAX_PARAM_BODY_LENGTH)) {
-				// Body is within a reasonable range
-
-				// Allocate memory:
-				// Add one extra character: in case the post-data is a text, it
-				// is required as 0-termination.
-				// Do not increment con_len, since the 0 terminating is not part
-				// of the content (text or binary).
-				conobj.postData = (char *)malloc(con_len + 1);
-				if (conobj.postData != NULL) {
-					// malloc may fail for huge requests
-					mg_read(conn, conobj.postData, con_len);
-					conobj.postData[con_len] = 0;
-					formParams = conobj.postData;
-					conobj.postDataLen = con_len;
+	if (conobj.postData.empty()) {
+		// check if there is a request body
+		for (;;) {
+			char buf[2048];
+			int r = mg_read(conn, buf, sizeof(buf));
+			try {
+				if (r == 0) {
+					conobj.postData.push_back('\0');
+					break;
+				} else if ((r < 0) || ((conobj.postData.size() + r)
+				                       > MAX_PARAM_BODY_LENGTH)) {
+					conobj.postData.assign(1, '\0');
+					break;
 				}
-			}
-			if (conobj.postData == NULL) {
-				// we cannot store the body
-				mg_unlock_connection(conn);
-				return false;
+				conobj.postData.insert(conobj.postData.end(), buf, buf + r);
+			} catch (...) {
+				conobj.postData.clear();
+				break;
 			}
 		}
 	}
+	if (!conobj.postData.empty()) {
+		// check if form parameter are already stored
+		formParams = &conobj.postData[0];
+	}
 
 	if (ri->query_string != NULL) {
 		// get requests do store html <form> field values in the http
@@ -543,36 +521,29 @@ CivetServer::getParam(const char *data,
                       std::string &dst,
                       size_t occurrence)
 {
-	const char *p, *e, *s;
-	size_t name_len;
-
-	dst.clear();
-	if (data == NULL || name == NULL || data_len == 0) {
-		return false;
-	}
-	name_len = strlen(name);
-	e = data + data_len;
-
-	// data is "var1=val1&var2=val2...". Find variable first
-	for (p = data; p + name_len < e; p++) {
-		if ((p == data || p[-1] == '&') && p[name_len] == '='
-		    && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
-
-			// Point p to variable value
-			p += name_len + 1;
-
-			// Point s to the end of the value
-			s = (const char *)memchr(p, '&', (size_t)(e - p));
-			if (s == NULL) {
-				s = e;
+	char buf[256];
+	int r = mg_get_var2(data, data_len, name, buf, sizeof(buf), occurrence);
+	if (r >= 0) {
+		// dst can contain NUL characters
+		dst.assign(buf, r);
+		return true;
+	} else if (r == -2) {
+		// more buffer
+		std::vector<char> vbuf(sizeof(buf) * 2);
+		for (;;) {
+			r = mg_get_var2(data, data_len, name, &vbuf[0], vbuf.size(),
+			                occurrence);
+			if (r >= 0) {
+				dst.assign(vbuf.begin(), vbuf.begin() + r);
+				return true;
+			} else if (r != -2) {
+				break;
 			}
-			assert(s >= p);
-
-			// Decode variable into destination buffer
-			urlDecode(p, (s - p), dst, true);
-			return true;
+			// more buffer
+			vbuf.resize(vbuf.size() * 2);
 		}
 	}
+	dst.clear();
 	return false;
 }
 
@@ -603,19 +574,21 @@ CivetServer::urlEncode(const char *src,
                        std::string &dst,
                        bool append)
 {
-	static const char *dont_escape = "._-$,;~()";
-	static const char *hex = "0123456789abcdef";
-
 	if (!append)
 		dst.clear();
 
 	for (; src_len > 0; src++, src_len--) {
-		if (isalnum((unsigned char)*src) || strchr(dont_escape, *src) != NULL) {
+		if (*src == '\0') {
+			// src and dst can contain NUL characters without encoding
 			dst.push_back(*src);
 		} else {
-			dst.push_back('%');
-			dst.push_back(hex[(unsigned char)*src >> 4]);
-			dst.push_back(hex[(unsigned char)*src & 0xf]);
+			char buf[2] = {*src, '\0'};
+			char dst_buf[4];
+			if (mg_url_encode(buf, dst_buf, sizeof(dst_buf)) < 0) {
+				// never reach here
+				throw std::out_of_range("");
+			}
+			dst.append(dst_buf);
 		}
 	}
 }
@@ -636,25 +609,16 @@ CivetServer::getListeningPorts()
 std::vector<struct mg_server_port>
 CivetServer::getListeningPortsFull()
 {
-	std::vector<struct mg_server_port> server_ports(50);
-	int size = mg_get_server_ports(context,
-	                               (int)server_ports.size(),
-	                               &server_ports[0]);
-	if (size <= 0) {
-		server_ports.resize(0);
-		return server_ports;
+	std::vector<struct mg_server_port> server_ports(8);
+	for (;;) {
+		int size = mg_get_server_ports(context,
+		                               static_cast<int>(server_ports.size()),
+		                               &server_ports[0]);
+		if (size < static_cast<int>(server_ports.size())) {
+			server_ports.resize(size < 0 ? 0 : size);
+			break;
+		}
+		server_ports.resize(server_ports.size() * 2);
 	}
-	server_ports.resize(size);
 	return server_ports;
 }
-
-CivetServer::CivetConnection::CivetConnection()
-{
-	postData = NULL;
-	postDataLen = 0;
-}
-
-CivetServer::CivetConnection::~CivetConnection()
-{
-	free(postData);
-}

+ 50 - 45
src/civetweb.c

@@ -587,10 +587,18 @@ typedef long off_t;
 #endif /* CRYPTO_LIB */
 #else  /* defined(_WIN64) || defined(__MINGW64__) */
 #if !defined(SSL_LIB)
+#if defined(OPENSSL_API_1_1)
+#define SSL_LIB "libssl-1_1.dll"
+#else
 #define SSL_LIB "ssleay32.dll"
+#endif
 #endif /* SSL_LIB */
 #if !defined(CRYPTO_LIB)
+#if defined(OPENSSL_API_1_1)
+#define CRYPTO_LIB "libcrypto-1_1.dll"
+#else
 #define CRYPTO_LIB "libeay32.dll"
+#endif
 #endif /* CRYPTO_LIB */
 #endif /* defined(_WIN64) || defined(__MINGW64__) */
 
@@ -8149,14 +8157,11 @@ remove_dot_segments(char *inout)
 	/* Windows backend protection
 	 * (https://tools.ietf.org/html/rfc3986#section-7.3): Replace backslash
 	 * in URI by slash */
-	char *in_copy = inout ? mg_strdup(inout) : NULL;
-	char *out_begin = inout;
 	char *out_end = inout;
-	char *in = in_copy;
-	int replaced;
+	char *in = inout;
 
 	if (!in) {
-		/* Param error or OOM. */
+		/* Param error. */
 		return;
 	}
 
@@ -8173,11 +8178,13 @@ remove_dot_segments(char *inout)
 	 * The input buffer is initialized.
 	 * The output buffer is initialized to the empty string.
 	 */
-	in = in_copy;
+	in = inout;
 
 	/* Step 2:
 	 * While the input buffer is not empty, loop as follows:
 	 */
+	/* Less than out_end of the inout buffer is used as output, so keep
+	 * condition: out_end <= in */
 	while (*in) {
 		/* Step 2a:
 		 * If the input buffer begins with a prefix of "../" or "./",
@@ -8209,21 +8216,19 @@ remove_dot_segments(char *inout)
 		 */
 		else if (!strncmp(in, "/../", 4)) {
 			in += 3;
-			if (out_begin != out_end) {
+			if (inout != out_end) {
 				/* remove last segment */
 				do {
 					out_end--;
-				} while ((out_begin != out_end) && (*out_end != '/'));
-				*out_end = 0;
+				} while ((inout != out_end) && (*out_end != '/'));
 			}
 		} else if (!strcmp(in, "/..")) {
 			in[1] = 0;
-			if (out_begin != out_end) {
+			if (inout != out_end) {
 				/* remove last segment */
 				do {
 					out_end--;
-				} while ((out_begin != out_end) && (*out_end != '/'));
-				*out_end = 0;
+				} while ((inout != out_end) && (*out_end != '/'));
 			}
 		}
 		/* otherwise */
@@ -8262,42 +8267,40 @@ remove_dot_segments(char *inout)
 	 * the end. Also replace all "//" by "/". Repeat until there is no "./"
 	 * or "//" anymore.
 	 */
-	do {
-		replaced = 0;
-
-		/* replace ./ by / */
-		out_end = out_begin;
-		while (*out_end) {
-			if ((*out_end == '.')
-			    && ((out_end[1] == '/') || (out_end[1] == 0))) {
-				char *r = out_end;
-				do {
-					r[0] = r[1];
-					r++;
-					replaced = 1;
-				} while (r[0] != 0);
-			}
-			out_end++;
-		}
-
-		/* replace ./ by / */
-		out_end = out_begin;
-		while (*out_end) {
-			if ((out_end[0] == '/') && (out_end[1] == '/')) {
-				char *c = out_end;
-				while (*c) {
-					c[0] = c[1];
-					c++;
+	out_end = in = inout;
+	while (*in) {
+		if (*in == '.') {
+			/* remove . at the end or preceding of / */
+			char *in_ahead = in;
+			do {
+				in_ahead++;
+			} while (*in_ahead == '.');
+			if (*in_ahead == '/') {
+				in = in_ahead;
+				if ((out_end != inout) && (out_end[-1] == '/')) {
+					/* remove generated // */
+					out_end--;
 				}
-				replaced = 1;
+			} else if (*in_ahead == 0) {
+				in = in_ahead;
+			} else {
+				do {
+					*out_end++ = '.';
+					in++;
+				} while (in != in_ahead);
 			}
-			out_end++;
+		} else if (*in == '/') {
+			/* replace // by / */
+			*out_end++ = '/';
+			do {
+				in++;
+			} while (*in == '/');
+		} else {
+			*out_end++ = *in;
+			in++;
 		}
-
-	} while (replaced);
-
-	/* Free temporary copies */
-	mg_free(in_copy);
+	}
+	*out_end = 0;
 }
 
 
@@ -15275,6 +15278,8 @@ set_ports_option(struct mg_context *phys_ctx)
 			                    "%s value \"%s\" is invalid",
 			                    config_options[LISTEN_BACKLOG_SIZE].name,
 			                    opt_txt);
+			closesocket(so.sock);
+			so.sock = INVALID_SOCKET;
 			continue;
 		}