This revision has changes from Xabier Onecas comments on v3.

function                                             old     new   delta
http_response                                        160     176     +16
http_response_type                                    20      22      +2
httpd_main                                           874     871      -3
send_file_and_exit                                   802     796      -6
send_headers                                        1004     992     -12
send_cgi_and_exit                                   1016     914    -102
.rodata                                           156524  156407    -117
handle_incoming_and_exit                            2832    2708    -124
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/6 up/down: 18/-364)          Total: -346
bytes
   text    data     bss     dec     hex filename
1011861   17711    1888 1031460   fbd24 busybox_old
1011545   17743    1888 1031176   fbc08 busybox_unstripped
diff --git a/networking/httpd.c b/networking/httpd.c
index b52526a78..1157c6f1f 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -267,6 +267,7 @@
 #define DEBUG 0
 
 #define IOBUF_SIZE 8192
+#define MAX_HTTP_HEADER_SIZE (8*1024)
 #if PIPE_BUF >= IOBUF_SIZE
 # error "PIPE_BUF >= IOBUF_SIZE"
 #endif
@@ -305,6 +306,12 @@ typedef struct Htaccess_Proxy {
 	char *url_to;
 } Htaccess_Proxy;
 
+typedef struct HTTP_Header {
+    struct HTTP_Header *next;
+    char *name;
+    char *value;
+} HTTP_Header;
+
 enum {
 	HTTP_OK = 200,
 	HTTP_PARTIAL_CONTENT = 206,
@@ -316,6 +323,7 @@ enum {
 	HTTP_REQUEST_TIMEOUT = 408,
 	HTTP_NOT_IMPLEMENTED = 501,   /* used for unrecognized requests */
 	HTTP_INTERNAL_SERVER_ERROR = 500,
+	HTTP_ENTITY_TOO_LARGE = 413,
 	HTTP_CONTINUE = 100,
 #if 0   /* future use */
 	HTTP_SWITCHING_PROTOCOLS = 101,
@@ -347,6 +355,7 @@ static const uint16_t http_response_type[] ALIGN2 = {
 	HTTP_BAD_REQUEST,
 	HTTP_FORBIDDEN,
 	HTTP_INTERNAL_SERVER_ERROR,
+	HTTP_ENTITY_TOO_LARGE,
 #if 0   /* not implemented */
 	HTTP_CREATED,
 	HTTP_ACCEPTED,
@@ -377,6 +386,7 @@ static const struct {
 	{ "Bad Request", "Unsupported method" },
 	{ "Forbidden", ""  },
 	{ "Internal Server Error", "Internal Server Error" },
+	{ "Entity Too Large", "Entity Too Large" },
 #if 0   /* not implemented */
 	{ "Created" },
 	{ "Accepted" },
@@ -412,11 +422,7 @@ struct globals {
 
 	IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
 	IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
-	IF_FEATURE_HTTPD_CGI(char *referer;)
-	IF_FEATURE_HTTPD_CGI(char *user_agent;)
-	IF_FEATURE_HTTPD_CGI(char *host;)
-	IF_FEATURE_HTTPD_CGI(char *http_accept;)
-	IF_FEATURE_HTTPD_CGI(char *http_accept_language;)
+	IF_FEATURE_HTTPD_CGI(HTTP_Header *hdr_list;)
 
 	off_t file_size;        /* -1 - unknown */
 #if ENABLE_FEATURE_HTTPD_RANGES
@@ -1437,7 +1443,6 @@ static void setenv1(const char *name, const char *value)
  * const char *url              The requested URL (with leading /).
  * const char *orig_uri         The original URI before rewriting (if any)
  * int post_len                 Length of the POST body.
- * const char *cookie           For set HTTP_COOKIE.
  * const char *content_type     For set CONTENT_TYPE.
  */
 static void send_cgi_and_exit(
@@ -1445,14 +1450,12 @@ static void send_cgi_and_exit(
 		const char *orig_uri,
 		const char *request,
 		int post_len,
-		const char *cookie,
 		const char *content_type) NORETURN;
 static void send_cgi_and_exit(
 		const char *url,
 		const char *orig_uri,
 		const char *request,
 		int post_len,
-		const char *cookie,
 		const char *content_type)
 {
 	struct fd_pair fromCgi;  /* CGI -> httpd pipe */
@@ -1531,15 +1534,8 @@ static void send_cgi_and_exit(
 #endif
 		}
 	}
-	setenv1("HTTP_USER_AGENT", G.user_agent);
-	if (G.http_accept)
-		setenv1("HTTP_ACCEPT", G.http_accept);
-	if (G.http_accept_language)
-		setenv1("HTTP_ACCEPT_LANGUAGE", G.http_accept_language);
 	if (post_len)
 		putenv(xasprintf("CONTENT_LENGTH=%u", post_len));
-	if (cookie)
-		setenv1("HTTP_COOKIE", cookie);
 	if (content_type)
 		setenv1("CONTENT_TYPE", content_type);
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -1548,12 +1544,17 @@ static void send_cgi_and_exit(
 		putenv((char*)"AUTH_TYPE=Basic");
 	}
 #endif
-	if (G.referer)
-		setenv1("HTTP_REFERER", G.referer);
-	setenv1("HTTP_HOST", G.host); /* set to "" if NULL */
 	/* setenv1("SERVER_NAME", safe_gethostname()); - don't do this,
 	 * just run "env SERVER_NAME=xyz httpd ..." instead */
 
+	if (G.hdr_list) {
+		HTTP_Header *cur = G.hdr_list;
+		do {
+			setenv1(cur->name, cur->value);
+			cur = cur->next;
+		} while (cur != G.hdr_list);
+	}
+
 	xpiped_pair(fromCgi);
 	xpiped_pair(toCgi);
 
@@ -2077,12 +2078,13 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 	char *urlcopy;
 	char *urlp;
 	char *tptr;
+	int hdr_len = 0;
 #if ENABLE_FEATURE_HTTPD_CGI
 	static const char request_HEAD[] ALIGN1 = "HEAD";
 	const char *prequest;
-	char *cookie = NULL;
 	char *content_type = NULL;
 	unsigned long length = 0;
+	HTTP_Header *last = NULL;
 #elif ENABLE_FEATURE_HTTPD_PROXY
 #define prequest request_GET
 	unsigned long length = 0;
@@ -2263,8 +2265,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 
 		/* Read until blank line */
 		while (1) {
-			if (!get_line())
+			int iobuf_len = get_line();
+			if (!iobuf_len)
 				break; /* EOF or error or empty line */
+			if ((hdr_len += iobuf_len) > MAX_HTTP_HEADER_SIZE)
+				send_headers_and_exit(HTTP_ENTITY_TOO_LARGE);
 			if (DEBUG)
 				bb_error_msg("header: '%s'", iobuf);
 
@@ -2299,30 +2304,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 					if (errno || length > INT_MAX)
 						send_headers_and_exit(HTTP_BAD_REQUEST);
 				}
-			}
-#endif
-#if ENABLE_FEATURE_HTTPD_CGI
-			else if (STRNCASECMP(iobuf, "Cookie:") == 0) {
-				if (!cookie) /* in case they send millions of these, do not OOM */
-					cookie = xstrdup(skip_whitespace(iobuf + sizeof("Cookie:")-1));
-			} else if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
-				if (!content_type)
-					content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
-			} else if (STRNCASECMP(iobuf, "Referer:") == 0) {
-				if (!G.referer)
-					G.referer = xstrdup(skip_whitespace(iobuf + sizeof("Referer:")-1));
-			} else if (STRNCASECMP(iobuf, "User-Agent:") == 0) {
-				if (!G.user_agent)
-					G.user_agent = xstrdup(skip_whitespace(iobuf + sizeof("User-Agent:")-1));
-			} else if (STRNCASECMP(iobuf, "Host:") == 0) {
-				if (!G.host)
-					G.host = xstrdup(skip_whitespace(iobuf + sizeof("Host:")-1));
-			} else if (STRNCASECMP(iobuf, "Accept:") == 0) {
-				if (!G.http_accept)
-					G.http_accept = xstrdup(skip_whitespace(iobuf + sizeof("Accept:")-1));
-			} else if (STRNCASECMP(iobuf, "Accept-Language:") == 0) {
-				if (!G.http_accept_language)
-					G.http_accept_language = xstrdup(skip_whitespace(iobuf + sizeof("Accept-Language:")-1));
+				continue;
 			}
 #endif
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -2338,6 +2320,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 				/* decodeBase64() skips whitespace itself */
 				decodeBase64(tptr);
 				authorized = check_user_passwd(urlcopy, tptr);
+				continue;
 			}
 #endif
 #if ENABLE_FEATURE_HTTPD_RANGES
@@ -2355,6 +2338,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 							range_start = -1;
 					}
 				}
+				continue;
 			}
 #endif
 #if ENABLE_FEATURE_HTTPD_GZIP
@@ -2372,6 +2356,43 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 						content_gzip = 1;
 					//}
 				}
+				continue;
+			}
+#endif
+#if ENABLE_FEATURE_HTTPD_CGI
+			if (STRNCASECMP(iobuf, "Content-Type:") == 0) {
+				if (!content_type)
+					content_type = xstrdup(skip_whitespace(iobuf + sizeof("Content-Type:")-1));
+			} else {
+				HTTP_Header *cur;
+				char *after_colon = strchr(iobuf, ':');
+				char *ch = iobuf;
+
+				if (!after_colon)
+					continue;
+
+				cur = xmalloc(sizeof(HTTP_Header));
+				*after_colon++ = '\0';
+
+				while (*ch) {
+					if (isalpha(*ch))
+						*ch &= ~0x20;
+					else if (!isdigit(*ch))
+						*ch = '_';
+					ch++;
+				}
+
+				cur->name = xasprintf("HTTP_%s", iobuf);
+				cur->value = xstrdup(skip_whitespace(after_colon));
+
+				/* Insert new header into header list */
+				if (!G.hdr_list) {
+					G.hdr_list = cur;
+				} else {
+					last->next = cur;
+				}
+				cur->next = G.hdr_list;
+				last = cur;
 			}
 #endif
 		} /* while extra header reading */
@@ -2435,7 +2456,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 			/* protect listing "cgi-bin/" */
 			send_headers_and_exit(HTTP_FORBIDDEN);
 		}
-		send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
+		send_cgi_and_exit(urlcopy, urlcopy, prequest, length, content_type);
 	}
 #endif
 
@@ -2456,7 +2477,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 			Htaccess *cur;
 			for (cur = script_i; cur; cur = cur->next) {
 				if (strcmp(cur->before_colon + 1, suffix) == 0) {
-					send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
+					send_cgi_and_exit(urlcopy, urlcopy, prequest, length, content_type);
 				}
 			}
 		}
@@ -2470,7 +2491,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 		 * Try cgi-bin/index.cgi */
 		if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
 			urlp[0] = '\0'; /* remove index_page */
-			send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type);
+			send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, content_type);
 		}
 	}
 	/* else fall through to send_file, it errors out if open fails: */
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to