[git commit] httpd: cgi-bin support for DELETE, PUT, OPTIONS etc methods

Denys Vlasenko vda.linux at googlemail.com
Tue May 4 17:20:50 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=36e932abdfd79f55fdded4142d10319ba843839e
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
handle_incoming_and_exit                            2217    2240     +23
static.request_POST                                    -       5      +5
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 28/0)               Total: 28 bytes

Signed-off-by: Alexander Sack <asac at pantacor.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/httpd.c | 85 +++++++++++++++++++++++++-----------------------------
 1 file changed, 40 insertions(+), 45 deletions(-)

diff --git a/networking/httpd.c b/networking/httpd.c
index e6757d943..09e19dc29 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -344,13 +344,6 @@ typedef struct Htaccess_Proxy {
 	char *url_to;
 } Htaccess_Proxy;
 
-typedef enum CGI_type {
-	CGI_NONE = 0,
-	CGI_NORMAL,
-	CGI_INDEX,
-	CGI_INTERPRETER,
-} CGI_type;
-
 enum {
 	HTTP_OK = 200,
 	HTTP_PARTIAL_CONTENT = 206,
@@ -2174,7 +2167,6 @@ static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM)
 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) NORETURN;
 static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 {
-	static const char request_GET[] ALIGN1 = "GET";
 	struct stat sb;
 	char *urlcopy;
 	char *urlp;
@@ -2186,13 +2178,17 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 	unsigned total_headers_len;
 #endif
 #if ENABLE_FEATURE_HTTPD_CGI
+	static const char request_GET[]  ALIGN1 = "GET";
 	static const char request_HEAD[] ALIGN1 = "HEAD";
+	static const char request_POST[] ALIGN1 = "POST";
 	const char *prequest;
-	unsigned long length = 0;
-	enum CGI_type cgi_type = CGI_NONE;
-#elif ENABLE_FEATURE_HTTPD_PROXY
-#define prequest request_GET
-	unsigned long length = 0;
+	unsigned long POST_length;
+	enum CGI_type {
+		CGI_NONE = 0,
+		CGI_NORMAL,
+		CGI_INDEX,
+		CGI_INTERPRETER,
+	} cgi_type = CGI_NONE;
 #endif
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
 	smallint authorized = -1;
@@ -2235,7 +2231,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 	if (!get_line()) /* EOF or error or empty line */
 		send_headers_and_exit(HTTP_BAD_REQUEST);
 
-	/* Determine type of request (GET/POST) */
+	/* Determine type of request (GET/POST/...) */
 	// rfc2616: method and URI is separated by exactly one space
 	//urlp = strpbrk(iobuf, " \t"); - no, tab isn't allowed
 	urlp = strchr(iobuf, ' ');
@@ -2244,16 +2240,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 	*urlp++ = '\0';
 #if ENABLE_FEATURE_HTTPD_CGI
 	prequest = request_GET;
-	if (strcasecmp(iobuf, prequest) != 0) {
-		prequest = request_HEAD;
-		if (strcasecmp(iobuf, prequest) != 0) {
-			prequest = "POST";
-			if (strcasecmp(iobuf, prequest) != 0)
-				send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
-		}
-	}
+	if (strcasecmp(iobuf, prequest) == 0)
+		goto found;
+	prequest = request_HEAD;
+	if (strcasecmp(iobuf, prequest) == 0)
+		goto found;
+	prequest = request_POST;
+	if (strcasecmp(iobuf, prequest) == 0)
+		goto found;
+	/* For CGI, allow other requests too (DELETE, PUT, OPTIONS, etc) */
+	prequest = alloca(16);
+	safe_strncpy((char*)prequest, iobuf, 16);
+ found:
 #else
-	if (strcasecmp(iobuf, request_GET) != 0)
+	if (strcasecmp(iobuf, "GET") != 0)
 		send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
 #endif
 	// rfc2616: method and URI is separated by exactly one space
@@ -2300,7 +2300,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 			 * to http://hostname[:port]/new/pathSFX
 			 */
 			fdprintf(proxy_fd, "%s %s%s %s\r\n",
-					prequest, /* "GET" or "POST" */
+					iobuf, /* "GET" / "POST" / etc */
 					proxy_entry->url_to, /* "/new/path" */
 					urlcopy + strlen(proxy_entry->url_from), /* "SFX" */
 					HTTP_slash /* "HTTP/xyz" */
@@ -2328,7 +2328,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 	/* Algorithm stolen from libbb bb_simplify_path(),
 	 * but don't strdup, retain trailing slash, protect root */
 	urlp = tptr = urlcopy;
-	for (;;) {
+	while (1) {
 		if (*urlp == '/') {
 			/* skip duplicate (or initial) slash */
 			if (*tptr == '/') {
@@ -2435,6 +2435,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 
 #if ENABLE_FEATURE_HTTPD_CGI
 	total_headers_len = 0;
+	POST_length = 0;
 #endif
 
 	/* Read until blank line */
@@ -2450,24 +2451,17 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 #endif
 		if (DEBUG)
 			bb_error_msg("header: '%s'", iobuf);
-#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_PROXY
-		/* Try and do our best to parse more lines */
-		if (STRNCASECMP(iobuf, "Content-Length:") == 0) {
-			/* extra read only for POST */
-			if (prequest != request_GET
-# if ENABLE_FEATURE_HTTPD_CGI
-			 && prequest != request_HEAD
-# endif
-			) {
-				tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1);
-				if (!tptr[0])
-					send_headers_and_exit(HTTP_BAD_REQUEST);
-				/* not using strtoul: it ignores leading minus! */
-				length = bb_strtou(tptr, NULL, 10);
-				/* length is "ulong", but we need to pass it to int later */
-				if (errno || length > INT_MAX)
-					send_headers_and_exit(HTTP_BAD_REQUEST);
-			}
+#if ENABLE_FEATURE_HTTPD_CGI
+		/* Only POST needs to know POST_length */
+		if (prequest == request_POST && STRNCASECMP(iobuf, "Content-Length:") == 0) {
+			tptr = skip_whitespace(iobuf + sizeof("Content-Length:") - 1);
+			if (!tptr[0])
+				send_headers_and_exit(HTTP_BAD_REQUEST);
+			/* not using strtoul: it ignores leading minus! */
+			POST_length = bb_strtou(tptr, NULL, 10);
+			/* length is "ulong", but we need to pass it to int later */
+			if (errno || POST_length > INT_MAX)
+				send_headers_and_exit(HTTP_BAD_REQUEST);
 			continue;
 		}
 #endif
@@ -2588,7 +2582,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 		send_cgi_and_exit(
 			(cgi_type == CGI_INDEX) ? "/cgi-bin/index.cgi"
 			/*CGI_NORMAL or CGI_INTERPRETER*/ : urlcopy,
-			urlcopy, prequest, length
+			urlcopy, prequest, POST_length
 		);
 	}
 #endif
@@ -2599,13 +2593,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 
 #if ENABLE_FEATURE_HTTPD_CGI
 	if (prequest != request_GET && prequest != request_HEAD) {
-		/* POST for files does not make sense */
+		/* POST / DELETE / PUT / OPTIONS for files do not make sense */
 		send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
 	}
 	send_file_and_exit(tptr,
 		(prequest != request_HEAD ? SEND_HEADERS_AND_BODY : SEND_HEADERS)
 	);
 #else
+	/* It was verified earlier that it is a "GET" */
 	send_file_and_exit(tptr, SEND_HEADERS_AND_BODY);
 #endif
 }


More information about the busybox-cvs mailing list