Squashed 'yocto-poky/' content from commit ea562de

git-subtree-dir: yocto-poky
git-subtree-split: ea562de57590c966cd5a75fda8defecd397e6436
diff --git a/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch b/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch
new file mode 100644
index 0000000..a9df174
--- /dev/null
+++ b/meta/recipes-extended/lighttpd/lighttpd/0001-mod_cgi-buffers-data-without-bound.patch
@@ -0,0 +1,387 @@
+From e6ccbab5d42b110ac4f6ce1f72cb1e9ccbe4400a Mon Sep 17 00:00:00 2001
+From: Li xin <lixin.fnst@cn.fujitsu.com>
+Date: Tue, 16 Jun 2015 19:02:38 +0900
+Subject: [PATCH] mod_cgi buffers data without bound so fix it
+
+Upstream-Status: Submitted [http://redmine.lighttpd.net/issues/1264]
+
+Signed-off-by: Li Xin <lixin.fnst@cn.fujitsu.com>
+
+Update context for 1.4.36.
+
+Signed-off-by: Kai Kang <kai.kang@windriver.com>
+---
+ doc/config/lighttpd.conf |   8 ++
+ src/mod_cgi.c            | 188 ++++++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 187 insertions(+), 9 deletions(-)
+
+diff --git a/doc/config/lighttpd.conf b/doc/config/lighttpd.conf
+index 60b0ae1..9c101a7 100644
+--- a/doc/config/lighttpd.conf
++++ b/doc/config/lighttpd.conf
+@@ -375,6 +375,14 @@ server.upload-dirs = ( "/var/tmp" )
+ ##
+ #######################################################################
+ 
++#######################################################################
++##
++##
++## maximum bytes in send_raw before backing off [KByte]
++##  cgi.high-waterlevel        = 10240
++## minimum bytes in send_raw to disable backoff [KByte]
++##  cgi.low-waterlevel         = 5120
++#######################################################################
+ 
+ #######################################################################
+ ##
+diff --git a/src/mod_cgi.c b/src/mod_cgi.c
+index 01b1877..7c67eb5 100644
+--- a/src/mod_cgi.c
++++ b/src/mod_cgi.c
+@@ -38,6 +38,10 @@
+ 
+ #include "version.h"
+ 
++/* for output logs */
++char msgbuf[2048];
++
++
+ enum {EOL_UNSET, EOL_N, EOL_RN};
+ 
+ typedef struct {
+@@ -53,9 +57,19 @@ typedef struct {
+ 	size_t size;
+ } buffer_pid_t;
+ 
++struct handler_ctx;
++
++typedef struct {
++	struct handler_ctx **hctx;
++	size_t used;
++	size_t size;
++} buffer_ctx_t;
++
+ typedef struct {
+ 	array *cgi;
+ 	unsigned short execute_x_only;
++	unsigned int high_waterlevel; /* maximum bytes in send_raw before backing off */
++	unsigned int low_waterlevel;  /* minimum bytes in send_raw to disable backoff */
+ } plugin_config;
+ 
+ typedef struct {
+@@ -68,9 +82,11 @@ typedef struct {
+ 	plugin_config **config_storage;
+ 
+ 	plugin_config conf;
++
++	buffer_ctx_t cgi_ctx;
+ } plugin_data;
+ 
+-typedef struct {
++typedef struct handler_ctx {
+ 	pid_t pid;
+ 	int fd;
+ 	int fde_ndx; /* index into the fd-event buffer */
+@@ -78,11 +94,16 @@ typedef struct {
+ 	connection *remote_conn;  /* dumb pointer */
+ 	plugin_data *plugin_data; /* dumb pointer */
+ 
++	int throttling;        /* 1=waiting for send_raw buffer to drain */
++	off_t high_waterlevel; /* maximum bytes in send_raw before backing off */
++	off_t low_waterlevel;  /* minimum bytes in send_raw to disable backoff */
++	off_t bytes_in_buffer;
++
+ 	buffer *response;
+ 	buffer *response_header;
+ } handler_ctx;
+ 
+-static handler_ctx * cgi_handler_ctx_init(void) {
++static handler_ctx * cgi_handler_ctx_init(plugin_data *p) {
+ 	handler_ctx *hctx = calloc(1, sizeof(*hctx));
+ 
+ 	force_assert(hctx);
+@@ -90,13 +111,26 @@ static handler_ctx * cgi_handler_ctx_init(void) {
+ 	hctx->response = buffer_init();
+ 	hctx->response_header = buffer_init();
+ 
++	hctx->throttling = 0;
++	hctx->high_waterlevel = (off_t)p->conf.high_waterlevel * 1024;
++	hctx->low_waterlevel  = (off_t)p->conf.low_waterlevel  * 1024;
++	if (hctx->low_waterlevel >= hctx->high_waterlevel) {
++	    hctx->low_waterlevel = hctx->high_waterlevel * 3 / 4; /* 75% */
++	}
++	hctx->bytes_in_buffer = 0;
++
+ 	return hctx;
+ }
+ 
+-static void cgi_handler_ctx_free(handler_ctx *hctx) {
++static void cgi_handler_ctx_free(server *srv, handler_ctx *hctx) {
+ 	buffer_free(hctx->response);
+ 	buffer_free(hctx->response_header);
+ 
++	/* to avoid confusion */
++	if (hctx->throttling) {
++	    log_error_write(srv, __FILE__, __LINE__, "s", "unthrottled");
++	}
++
+ 	free(hctx);
+ }
+ 
+@@ -154,6 +188,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ 	config_values_t cv[] = {
+ 		{ "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
+ 		{ "cgi.execute-x-only",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },     /* 1 */
++		{ "cgi.high-waterlevel",         NULL, T_CONFIG_INT,   T_CONFIG_SCOPE_CONNECTION },       /* 2 */
++		{ "cgi.low-waterlevel",          NULL, T_CONFIG_INT,   T_CONFIG_SCOPE_CONNECTION },       /* 3 */
+ 		{ NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
+ 	};
+ 
+@@ -169,9 +205,13 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ 
+ 		s->cgi    = array_init();
+ 		s->execute_x_only = 0;
++		s->high_waterlevel = 0; /* 0 == disabled */
++		s->low_waterlevel  = 0;
+ 
+ 		cv[0].destination = s->cgi;
+ 		cv[1].destination = &(s->execute_x_only);
++		cv[2].destination = &(s->high_waterlevel);
++		cv[3].destination = &(s->low_waterlevel);
+ 
+ 		p->config_storage[i] = s;
+ 
+@@ -184,6 +224,51 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
+ }
+ 
+ 
++static void cgi_recount_bytes_in_buffer(handler_ctx *hctx)
++{
++	chunkqueue *cq = hctx->remote_conn->write_queue;
++	hctx->bytes_in_buffer = chunkqueue_length(cq) - chunkqueue_written(cq);
++}
++
++
++static void cgi_throttling_control(server *srv, handler_ctx *hctx)
++{
++	cgi_recount_bytes_in_buffer(hctx);
++
++#ifdef DEBUG
++	sprintf(msgbuf, "throttling=%d, chars=%llu, high=%llu, low=%llu",
++		hctx->throttling, hctx->bytes_in_buffer,
++		hctx->high_waterlevel, hctx->low_waterlevel);
++	log_error_write(srv, __FILE__, __LINE__, "ss",
++			"(debug) throttling control,", msgbuf);
++#endif
++
++	if (hctx->throttling) {
++		sprintf(msgbuf, "throttling; chars in queue=%llu,"
++			" low-waterlevel=%llu, high-waterlevel=%llu",
++			hctx->bytes_in_buffer,
++			hctx->low_waterlevel, hctx->high_waterlevel);
++		log_error_write(srv, __FILE__, __LINE__, "s", msgbuf);
++		if (hctx->bytes_in_buffer <= hctx->low_waterlevel) {
++			fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
++			hctx->throttling = 0;
++			log_error_write(srv, __FILE__, __LINE__, "s", "unthrottled");
++		}
++	} else {
++		if (hctx->high_waterlevel != 0 &&
++			hctx->high_waterlevel <= hctx->bytes_in_buffer) {
++			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
++			hctx->throttling = 1;
++			sprintf(msgbuf, "throttled; chars in queue=%llu,"
++				" low-waterlevel=%llu, high-waterlevel=%llu",
++				hctx->bytes_in_buffer,
++				hctx->low_waterlevel, hctx->high_waterlevel);
++			log_error_write(srv, __FILE__, __LINE__, "s", msgbuf);
++		}
++	}
++}
++
++
+ static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {
+ 	int m = -1;
+ 	size_t i;
+@@ -230,6 +315,39 @@ static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
+ 	return 0;
+ }
+ 
++
++static void cgi_ctx_add(plugin_data *p, handler_ctx *hctx) {
++	buffer_ctx_t *r = &(p->cgi_ctx);
++
++	if (r->size == 0) {
++		r->size = 16;
++		r->hctx = malloc(sizeof(*r->hctx) * r->size);
++	} else if (r->used == r->size) {
++		r->size += 16;
++		r->hctx = realloc(r->hctx, sizeof(*r->hctx) * r->size);
++	}
++
++	r->hctx[r->used++] = hctx;
++}
++
++static void cgi_ctx_del(plugin_data *p, handler_ctx *hctx) {
++	size_t i;
++	buffer_ctx_t *r = &(p->cgi_ctx);
++
++	for (i = 0; i < r->used; i++) {
++		if (r->hctx[i] == hctx) break;
++	}
++
++	if (i != r->used) {
++		/* found */
++
++		if (i != r->used - 1) {
++			r->hctx[i] = r->hctx[r->used - 1];
++		}
++		r->used--;
++	}
++}
++
+ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
+ 	char *ns;
+ 	const char *s;
+@@ -380,6 +498,14 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ 
+ 		buffer_commit(hctx->response, n);
+ 
++#ifdef DEBUG
++		sprintf(msgbuf, "n=%d, bytes_out=%llu, bytes_in=%llu", n,
++			(unsigned long long)con->write_queue->bytes_out,
++			(unsigned long long)con->write_queue->bytes_in);
++		log_error_write(srv, __FILE__, __LINE__, "ss",
++				"(debug) read,", msgbuf);
++#endif
++
+ 		/* split header from body */
+ 
+ 		if (con->file_started == 0) {
+@@ -503,7 +629,20 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
+ 			}
+ 		} else {
+ 			http_chunk_append_buffer(srv, con, hctx->response);
++#ifdef DEBUG
++			sprintf(msgbuf, "n=%d, bytes_out=%llu, bytes_in=%llu, limit=%llu", n,
++				(unsigned long long)con->write_queue->bytes_out,
++				(unsigned long long)con->write_queue->bytes_in,
++				(unsigned long long)hctx->high_waterlevel);
++			log_error_write(srv, __FILE__, __LINE__,
++					"ss", "(debug) append,", msgbuf);
++#endif
+ 			joblist_append(srv, con);
++
++			cgi_throttling_control(srv, hctx);
++			if (hctx->throttling) {
++				return FDEVENT_HANDLED_NOT_FINISHED;
++			}
+ 		}
+ 
+ #if 0
+@@ -553,8 +692,9 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
+ 	con->plugin_ctx[p->id] = NULL;
+ 
+ 	/* is this a good idea ? */
+-	cgi_handler_ctx_free(hctx);
+-
++	cgi_ctx_del(p, hctx);
++	cgi_handler_ctx_free(srv, hctx);
++	
+ 	/* if waitpid hasn't been called by response.c yet, do it here */
+ 	if (pid) {
+ 		/* check if the CGI-script is already gone */
+@@ -1105,7 +1245,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ 		con->mode = p->id;
+ 		buffer_reset(con->physical.path);
+ 
+-		hctx = cgi_handler_ctx_init();
++		hctx = cgi_handler_ctx_init(p);
++		cgi_ctx_add(p, hctx);
+ 
+ 		hctx->remote_conn = con;
+ 		hctx->plugin_data = p;
+@@ -1114,6 +1255,11 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ 		hctx->fde_ndx = -1;
+ 
+ 		con->plugin_ctx[p->id] = hctx;
++#ifdef DEBUG
++		sprintf(msgbuf, "hctx=%p, con=%p", (void*)hctx, (void*)con);
++		log_error_write(srv, __FILE__, __LINE__, "ss",
++				"(debug) hctx generated, ", msgbuf);
++#endif
+ 
+ 		fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
+ 		fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+@@ -1128,7 +1274,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
+ 
+ 			close(hctx->fd);
+ 
+-			cgi_handler_ctx_free(hctx);
++			cgi_ctx_del(p, hctx);
++			cgi_handler_ctx_free(srv, hctx);
+ 
+ 			con->plugin_ctx[p->id] = NULL;
+ 
+@@ -1153,6 +1300,8 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p
+ 
+ 	PATCH(cgi);
+ 	PATCH(execute_x_only);
++	PATCH(high_waterlevel);
++	PATCH(low_waterlevel);
+ 
+ 	/* skip the first, the global context */
+ 	for (i = 1; i < srv->config_context->used; i++) {
+@@ -1170,6 +1319,10 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p
+ 				PATCH(cgi);
+ 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) {
+ 				PATCH(execute_x_only);
++			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.high-waterlevel"))) {
++				PATCH(high_waterlevel);
++			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.low-waterlevel"))) {
++				PATCH(low_waterlevel);
+ 			}
+ 		}
+ 	}
+@@ -1222,6 +1375,21 @@ URIHANDLER_FUNC(cgi_is_handled) {
+ TRIGGER_FUNC(cgi_trigger) {
+ 	plugin_data *p = p_d;
+ 	size_t ndx;
++
++	for (ndx = 0; ndx < p->cgi_ctx.used; ndx++) {
++		handler_ctx *hctx = p->cgi_ctx.hctx[ndx];
++#ifdef DEBUG
++		connection *con = hctx->remote_conn;
++	
++		sprintf(msgbuf, "hctx=%p, con=%p, bytes_in_buffer=%llu",
++			(void*)hctx, (void*)con,
++			(unsigned long long)hctx->bytes_in_buffer);
++		log_error_write(srv, __FILE__, __LINE__, "ss",
++				"(debug) found using ctx,", msgbuf);
++#endif
++		cgi_throttling_control(srv, hctx);
++	}
++
+ 	/* the trigger handle only cares about lonely PID which we have to wait for */
+ #ifndef __WIN32
+ 
+@@ -1330,7 +1498,8 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
+ 			log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
+ 		}
+ 
+-		cgi_handler_ctx_free(hctx);
++		cgi_ctx_del(p, hctx);
++		cgi_handler_ctx_free(srv, hctx);
+ 
+ 		con->plugin_ctx[p->id] = NULL;
+ 
+@@ -1362,7 +1531,8 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
+ 			log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
+ 		}
+ 
+-		cgi_handler_ctx_free(hctx);
++		cgi_ctx_del(p, hctx);
++		cgi_handler_ctx_free(srv, hctx);
+ 
+ 		con->plugin_ctx[p->id] = NULL;
+ 		return HANDLER_FINISHED;