Просмотр исходного кода

uhttpd: switch to external git repo + cmake build system

SVN-Revision: 33775
Jo-Philipp Wich 13 лет назад
Родитель
Сommit
14e14faa0b

+ 23 - 21
package/network/services/uhttpd/Makefile

@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+# Copyright (C) 2010-2012 Jo-Philipp Wich <jow@openwrt.org>
 #
 # This is free software, licensed under the GNU General Public License v2.
 # See /LICENSE for more information.
@@ -8,9 +8,16 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uhttpd
-PKG_RELEASE:=40
+PKG_VERSION:=2012-10-15
+PKG_RELEASE=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://nbd.name/uhttpd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=fa43d1a62864f912e4450affb9c86f3accbe026a
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+PKG_MAINTAINER:=Jo-Philipp Wich <[email protected]>
 
-PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 PKG_CONFIG_DEPENDS := \
 	CONFIG_PACKAGE_uhttpd_debug \
 	CONFIG_PACKAGE_uhttpd-mod-lua \
@@ -20,13 +27,14 @@ PKG_CONFIG_DEPENDS := \
 	CONFIG_PACKAGE_uhttpd-mod-ubus
 
 include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
 
 define Package/uhttpd/default
   SECTION:=net
   CATEGORY:=Network
   SUBMENU:=Web Servers/Proxies
   TITLE:=uHTTPd - tiny, single threaded HTTP server
-  MAINTAINER:=Jo-Philipp Wich <[email protected]>
 endef
 
 define Package/uhttpd
@@ -71,19 +79,18 @@ define Package/uhttpd-mod-tls/config
   endchoice
 endef
 
-UHTTPD_TLS:=
+UHTTPD_TLS:=none
 TLS_CFLAGS:=
 TLS_LDFLAGS:=
 
 ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_cyassl),)
   UHTTPD_TLS:=cyassl
-  TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl -DTLS_IS_CYASSL
+  TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl
   TLS_LDFLAGS:=-lcyassl -lm
 endif
 
 ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
   UHTTPD_TLS:=openssl
-  TLS_CFLAGS:=-DTLS_IS_OPENSSL
   TLS_LDFLAGS:=-lssl
 endif
 
@@ -111,21 +118,16 @@ define Package/uhttpd-mod-ubus/description
 endef
 
 
-TARGET_CFLAGS += $(TLS_CFLAGS) $(if $(CONFIG_PACKAGE_uhttpd_debug),-DDEBUG) -ggdb3
-TARGET_LDFLAGS += -lubox -Wl,-rpath-link=$(STAGING_DIR)/usr/lib
-MAKE_VARS += \
-	FPIC="$(FPIC)" \
-	LUA_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-lua),1)" \
-	TLS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-tls),1)" \
-	UBUS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-ubus),1)" \
-	UHTTPD_TLS="$(UHTTPD_TLS)" \
-	TLS_CFLAGS="$(TLS_CFLAGS)" \
-	TLS_LDFLAGS="$(TLS_LDFLAGS)"
+TARGET_LDFLAGS += -lubox -lcrypt
+
+CMAKE_OPTIONS += \
+	-DDEBUG=$(if $(CONFIG_PACKAGE_uhttpd_debug),ON,OFF) \
+	-DLUA_SUPPORT=$(if $(CONFIG_PACKAGE_uhttpd-mod-lua),ON,OFF) \
+	-DUBUS_SUPPORT=$(if $(CONFIG_PACKAGE_uhttpd-mod-ubus),ON,OFF) \
+	-DTLS_SUPPORT=$(UHTTPD_TLS) \
+	-DTLS_CFLAGS="$(TLS_CFLAGS)" \
+	-DTLS_LDFLAGS="$(TLS_LDFLAGS)" \
 
-define Build/Prepare
-	mkdir -p $(PKG_BUILD_DIR)
-	$(CP) ./src/* $(PKG_BUILD_DIR)/
-endef
 
 define Package/uhttpd/conffiles
 /etc/config/uhttpd

+ 0 - 89
package/network/services/uhttpd/src/Makefile

@@ -1,89 +0,0 @@
-CGI_SUPPORT ?= 1
-LUA_SUPPORT ?= 1
-TLS_SUPPORT ?= 1
-UHTTPD_TLS ?= cyassl
-
-CFLAGS ?= -I./lua-5.1.4/src $(TLS_CFLAGS) -O0 -ggdb3
-LDFLAGS ?= -L./lua-5.1.4/src
-
-CFLAGS += -Wall --std=gnu99
-
-ifeq ($(UHTTPD_TLS),openssl)
-  TLS_LDFLAGS ?= -L./openssl-0.9.8m -lssl
-  TLS_CFLAGS ?= -I./openssl-0.9.8m/include -DTLS_IS_OPENSSL
-else
-  TLS_LDFLAGS ?= -L./cyassl-1.4.0/src/.libs -lcyassl
-  TLS_CFLAGS ?= -I./cyassl-1.4.0/include -DTLS_IS_CYASSL
-endif
-
-OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
-LIB := -Wl,--export-dynamic -lcrypt -ldl
-
-TLSLIB :=
-LUALIB :=
-
-HAVE_SHADOW=$(shell echo 'int main(void){ return !getspnam("root"); }' | \
-	$(CC) -include shadow.h -xc -o/dev/null - 2>/dev/null && echo yes)
-
-ifeq ($(HAVE_SHADOW),yes)
-  CFLAGS += -DHAVE_SHADOW
-endif
-
-ifeq ($(TLS_SUPPORT),1)
-  CFLAGS += -DHAVE_TLS
-endif
-
-ifeq ($(CGI_SUPPORT),1)
-  CFLAGS += -DHAVE_CGI
-endif
-
-ifeq ($(LUA_SUPPORT),1)
-  CFLAGS += -DHAVE_LUA
-endif
-
-ifeq ($(UBUS_SUPPORT),1)
-  CFLAGS += -DHAVE_UBUS
-endif
-
-
-world: compile
-
-ifeq ($(CGI_SUPPORT),1)
-  OBJ += uhttpd-cgi.o
-endif
-
-ifeq ($(LUA_SUPPORT),1)
-  LUALIB := uhttpd_lua.so
-
-  $(LUALIB): uhttpd-lua.c
-		$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
-			-shared -lm -llua -ldl \
-			-o $(LUALIB) uhttpd-lua.c
-endif
-
-ifeq ($(TLS_SUPPORT),1)
-  TLSLIB := uhttpd_tls.so
-
-  $(TLSLIB): uhttpd-tls.c
-		$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
-			-shared $(TLS_LDFLAGS) \
-			-o $(TLSLIB) uhttpd-tls.c
-endif
-
-ifeq ($(UBUS_SUPPORT),1)
-  UBUSLIB := uhttpd_ubus.so
-
-  $(UBUSLIB): uhttpd-ubus.c
-		$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
-			-shared -lubus -ljson -lblobmsg_json \
-			-o $(UBUSLIB) uhttpd-ubus.c
-endif
-
-%.o: %.c
-	$(CC) $(CFLAGS) -c -o $@ $<
-
-compile: $(OBJ) $(TLSLIB) $(LUALIB) $(UBUSLIB)
-	$(CC) -o uhttpd $(LDFLAGS) $(OBJ) $(LIB)
-
-clean:
-	rm -f *.o *.so uhttpd

+ 0 - 556
package/network/services/uhttpd/src/uhttpd-cgi.c

@@ -1,556 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - CGI handler
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#include "uhttpd.h"
-#include "uhttpd-utils.h"
-#include "uhttpd-cgi.h"
-
-
-static bool
-uh_cgi_header_parse(struct http_response *res, char *buf, int len, int *off)
-{
-	char *bufptr = NULL;
-	char *hdrname = NULL;
-	int hdrcount = 0;
-	int pos = 0;
-
-	if (((bufptr = strfind(buf, len, "\r\n\r\n", 4)) != NULL) ||
-	    ((bufptr = strfind(buf, len, "\n\n", 2)) != NULL))
-	{
-		*off = (int)(bufptr - buf) + ((bufptr[0] == '\r') ? 4 : 2);
-
-		memset(res, 0, sizeof(*res));
-
-		res->statuscode = 200;
-		res->statusmsg  = "OK";
-
-		bufptr = &buf[0];
-
-		for (pos = 0; pos < *off; pos++)
-		{
-			if (!hdrname && (buf[pos] == ':'))
-			{
-				buf[pos++] = 0;
-
-				if ((pos < len) && (buf[pos] == ' '))
-					pos++;
-
-				if (pos < len)
-				{
-					hdrname = bufptr;
-					bufptr = &buf[pos];
-				}
-			}
-
-			else if ((buf[pos] == '\r') || (buf[pos] == '\n'))
-			{
-				if (! hdrname)
-					break;
-
-				buf[pos++] = 0;
-
-				if ((pos < len) && (buf[pos] == '\n'))
-					pos++;
-
-				if (pos <= len)
-				{
-					if ((hdrcount+1) < array_size(res->headers))
-					{
-						if (!strcasecmp(hdrname, "Status"))
-						{
-							res->statuscode = atoi(bufptr);
-
-							if (res->statuscode < 100)
-								res->statuscode = 200;
-
-							if (((bufptr = strchr(bufptr, ' ')) != NULL) &&
-								(&bufptr[1] != 0))
-							{
-								res->statusmsg = &bufptr[1];
-							}
-
-							D("CGI: HTTP/1.x %03d %s\n",
-							  res->statuscode, res->statusmsg);
-						}
-						else
-						{
-							D("CGI: HTTP: %s: %s\n", hdrname, bufptr);
-
-							res->headers[hdrcount++] = hdrname;
-							res->headers[hdrcount++] = bufptr;
-						}
-
-						bufptr = &buf[pos];
-						hdrname = NULL;
-					}
-					else
-					{
-						return false;
-					}
-				}
-			}
-		}
-
-		return true;
-	}
-
-	return false;
-}
-
-static char * uh_cgi_header_lookup(struct http_response *res,
-								   const char *hdrname)
-{
-	int i;
-
-	foreach_header(i, res->headers)
-	{
-		if (!strcasecmp(res->headers[i], hdrname))
-			return res->headers[i+1];
-	}
-
-	return NULL;
-}
-
-static void uh_cgi_shutdown(struct uh_cgi_state *state)
-{
-	free(state);
-}
-
-static bool uh_cgi_socket_cb(struct client *cl)
-{
-	int i, len, blen, hdroff;
-	char buf[UH_LIMIT_MSGHEAD];
-
-	struct uh_cgi_state *state = (struct uh_cgi_state *)cl->priv;
-	struct http_response *res = &cl->response;
-	struct http_request *req = &cl->request;
-
-	/* there is unread post data waiting */
-	while (state->content_length > 0)
-	{
-		/* remaining data in http head buffer ... */
-		if (cl->httpbuf.len > 0)
-		{
-			len = min(state->content_length, cl->httpbuf.len);
-
-			D("CGI: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
-
-			memcpy(buf, cl->httpbuf.ptr, len);
-
-			cl->httpbuf.len -= len;
-			cl->httpbuf.ptr +=len;
-		}
-
-		/* read it from socket ... */
-		else
-		{
-			len = uh_tcp_recv(cl, buf,
-							  min(state->content_length, sizeof(buf)));
-
-			if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
-				break;
-
-			D("CGI: Child(%d) feed %d/%d TCP socket bytes\n",
-			  cl->proc.pid, len, min(state->content_length, sizeof(buf)));
-		}
-
-		if (len)
-			state->content_length -= len;
-		else
-			state->content_length = 0;
-
-		/* ... write to CGI process */
-		len = uh_raw_send(cl->wpipe.fd, buf, len,
-						  cl->server->conf->script_timeout);
-
-		/* explicit EOF notification for the child */
-		if (state->content_length <= 0)
-			uh_ufd_remove(&cl->wpipe);
-	}
-
-	/* try to read data from child */
-	while ((len = uh_raw_recv(cl->rpipe.fd, buf, state->header_sent
-	                          ? sizeof(buf) : state->httpbuf.len, -1)) > 0)
-	{
-		/* we have not pushed out headers yet, parse input */
-		if (!state->header_sent)
-		{
-			/* try to parse header ... */
-			memcpy(state->httpbuf.ptr, buf, len);
-			state->httpbuf.len -= len;
-			state->httpbuf.ptr += len;
-
-			blen = state->httpbuf.ptr - state->httpbuf.buf;
-
-			if (uh_cgi_header_parse(res, state->httpbuf.buf, blen, &hdroff))
-			{
-				/* write status */
-				ensure_out(uh_http_sendf(cl, NULL,
-					"%s %03d %s\r\n"
-					"Connection: close\r\n",
-					http_versions[req->version],
-					res->statuscode, res->statusmsg));
-
-				/* add Content-Type if no Location or Content-Type */
-				if (!uh_cgi_header_lookup(res, "Location") &&
-					!uh_cgi_header_lookup(res, "Content-Type"))
-				{
-					ensure_out(uh_http_send(cl, NULL,
-						"Content-Type: text/plain\r\n", -1));
-				}
-
-				/* if request was HTTP 1.1 we'll respond chunked */
-				if ((req->version > UH_HTTP_VER_1_0) &&
-					!uh_cgi_header_lookup(res, "Transfer-Encoding"))
-				{
-					ensure_out(uh_http_send(cl, NULL,
-						"Transfer-Encoding: chunked\r\n", -1));
-				}
-
-				/* write headers from CGI program */
-				foreach_header(i, res->headers)
-				{
-					ensure_out(uh_http_sendf(cl, NULL, "%s: %s\r\n",
-						res->headers[i], res->headers[i+1]));
-				}
-
-				/* terminate header */
-				ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
-
-				state->header_sent = true;
-
-				/* push out remaining head buffer */
-				if (hdroff < blen)
-				{
-					D("CGI: Child(%d) relaying %d rest bytes\n",
-					  cl->proc.pid, blen - hdroff);
-
-					ensure_out(uh_http_send(cl, req,
-					                        state->httpbuf.buf + hdroff,
-					                        blen - hdroff));
-				}
-			}
-
-			/* ... failed and head buffer exceeded */
-			else if (!state->httpbuf.len)
-			{
-				/* I would do this ...
-				 *
-				 *    uh_cgi_error_500(cl, req,
-				 *        "The CGI program generated an "
-				 *        "invalid response:\n\n");
-				 *
-				 * ... but in order to stay as compatible as possible,
-				 * treat whatever we got as text/plain response and
-				 * build the required headers here.
-				 */
-
-				ensure_out(uh_http_sendf(cl, NULL,
-										 "%s 200 OK\r\n"
-										 "Content-Type: text/plain\r\n"
-										 "%s\r\n",
-										 http_versions[req->version],
-										 (req->version > UH_HTTP_VER_1_0)
-										 ? "Transfer-Encoding: chunked\r\n" : ""
-				));
-
-				state->header_sent = true;
-
-				D("CGI: Child(%d) relaying %d invalid bytes\n",
-				  cl->proc.pid, len);
-
-				ensure_out(uh_http_send(cl, req, buf, len));
-			}
-		}
-		else
-		{
-			/* headers complete, pass through buffer to socket */
-			D("CGI: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
-			ensure_out(uh_http_send(cl, req, buf, len));
-		}
-	}
-
-	/* got EOF or read error from child */
-	if ((len == 0) ||
-		((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
-	{
-		D("CGI: Child(%d) presumed dead [%s]\n", cl->proc.pid, strerror(errno));
-
-		goto out;
-	}
-
-	return true;
-
-out:
-	if (!state->header_sent)
-	{
-		if (cl->timeout.pending)
-			uh_http_sendhf(cl, 502, "Bad Gateway",
-						   "The CGI process did not produce any response\n");
-		else
-			uh_http_sendhf(cl, 504, "Gateway Timeout",
-						   "The CGI process took too long to produce a "
-						   "response\n");
-	}
-	else
-	{
-		uh_http_send(cl, req, "", 0);
-	}
-
-	uh_cgi_shutdown(state);
-	return false;
-}
-
-bool uh_cgi_request(struct client *cl, struct path_info *pi,
-					struct interpreter *ip)
-{
-	int i;
-
-	int rfd[2] = { 0, 0 };
-	int wfd[2] = { 0, 0 };
-
-	pid_t child;
-
-	struct uh_cgi_state *state;
-	struct http_request *req = &cl->request;
-
-	/* allocate state */
-	if (!(state = malloc(sizeof(*state))))
-	{
-		uh_http_sendhf(cl, 500, "Internal Server Error", "Out of memory");
-		return false;
-	}
-
-	/* spawn pipes for me->child, child->me */
-	if ((pipe(rfd) < 0) || (pipe(wfd) < 0))
-	{
-		if (rfd[0] > 0) close(rfd[0]);
-		if (rfd[1] > 0) close(rfd[1]);
-		if (wfd[0] > 0) close(wfd[0]);
-		if (wfd[1] > 0) close(wfd[1]);
-
-		uh_http_sendhf(cl, 500, "Internal Server Error",
-						"Failed to create pipe: %s\n", strerror(errno));
-
-		return false;
-	}
-
-	/* fork off child process */
-	switch ((child = fork()))
-	{
-	/* oops */
-	case -1:
-		uh_http_sendhf(cl, 500, "Internal Server Error",
-						"Failed to fork child: %s\n", strerror(errno));
-
-		return false;
-
-	/* exec child */
-	case 0:
-#ifdef DEBUG
-		sleep(atoi(getenv("UHTTPD_SLEEP_ON_FORK") ?: "0"));
-#endif
-
-		/* do not leak parent epoll descriptor */
-		uloop_done();
-
-		/* close loose pipe ends */
-		close(rfd[0]);
-		close(wfd[1]);
-
-		/* patch stdout and stdin to pipes */
-		dup2(rfd[1], 1);
-		dup2(wfd[0], 0);
-
-		/* avoid leaking our pipe into child-child processes */
-		fd_cloexec(rfd[1]);
-		fd_cloexec(wfd[0]);
-
-		/* check for regular, world-executable file _or_ interpreter */
-		if (((pi->stat.st_mode & S_IFREG) &&
-			 (pi->stat.st_mode & S_IXOTH)) || (ip != NULL))
-		{
-			/* build environment */
-			clearenv();
-
-			/* common information */
-			setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
-			setenv("SERVER_SOFTWARE", "uHTTPd", 1);
-			setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
-
-#ifdef HAVE_TLS
-			/* https? */
-			if (cl->tls)
-				setenv("HTTPS", "on", 1);
-#endif
-
-			/* addresses */
-			setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1);
-			setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1);
-			setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1);
-			setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1);
-			setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1);
-			setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1);
-
-			/* path information */
-			setenv("SCRIPT_NAME", pi->name, 1);
-			setenv("SCRIPT_FILENAME", pi->phys, 1);
-			setenv("DOCUMENT_ROOT", pi->root, 1);
-			setenv("QUERY_STRING", pi->query ? pi->query : "", 1);
-
-			if (pi->info)
-				setenv("PATH_INFO", pi->info, 1);
-
-			/* REDIRECT_STATUS, php-cgi wants it */
-			switch (req->redirect_status)
-			{
-				case 404:
-					setenv("REDIRECT_STATUS", "404", 1);
-					break;
-
-				default:
-					setenv("REDIRECT_STATUS", "200", 1);
-					break;
-			}
-
-			/* http version */
-			setenv("SERVER_PROTOCOL", http_versions[req->version], 1);
-
-			/* request method */
-			setenv("REQUEST_METHOD", http_methods[req->method], 1);
-
-			/* request url */
-			setenv("REQUEST_URI", req->url, 1);
-
-			/* remote user */
-			if (req->realm)
-				setenv("REMOTE_USER", req->realm->user, 1);
-
-			/* request message headers */
-			foreach_header(i, req->headers)
-			{
-				if (!strcasecmp(req->headers[i], "Accept"))
-					setenv("HTTP_ACCEPT", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Accept-Charset"))
-					setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Accept-Encoding"))
-					setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Accept-Language"))
-					setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Authorization"))
-					setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Connection"))
-					setenv("HTTP_CONNECTION", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Cookie"))
-					setenv("HTTP_COOKIE", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Host"))
-					setenv("HTTP_HOST", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Referer"))
-					setenv("HTTP_REFERER", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "User-Agent"))
-					setenv("HTTP_USER_AGENT", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Content-Type"))
-					setenv("CONTENT_TYPE", req->headers[i+1], 1);
-
-				else if (!strcasecmp(req->headers[i], "Content-Length"))
-					setenv("CONTENT_LENGTH", req->headers[i+1], 1);
-			}
-
-
-			/* execute child code ... */
-			if (chdir(pi->root))
-				perror("chdir()");
-
-			if (ip != NULL)
-				execl(ip->path, ip->path, pi->phys, NULL);
-			else
-				execl(pi->phys, pi->phys, NULL);
-
-			/* in case it fails ... */
-			printf("Status: 500 Internal Server Error\r\n\r\n"
-				   "Unable to launch the requested CGI program:\n"
-				   "  %s: %s\n", ip ? ip->path : pi->phys, strerror(errno));
-		}
-
-		/* 403 */
-		else
-		{
-			printf("Status: 403 Forbidden\r\n\r\n"
-				   "Access to this resource is forbidden\n");
-		}
-
-		close(wfd[0]);
-		close(rfd[1]);
-		exit(0);
-
-		break;
-
-	/* parent; handle I/O relaying */
-	default:
-		memset(state, 0, sizeof(*state));
-
-		cl->rpipe.fd = rfd[0];
-		cl->wpipe.fd = wfd[1];
-		cl->proc.pid = child;
-
-		/* make pipe non-blocking */
-		fd_nonblock(cl->rpipe.fd);
-		fd_nonblock(cl->wpipe.fd);
-
-		/* close unneeded pipe ends */
-		close(rfd[1]);
-		close(wfd[0]);
-
-		D("CGI: Child(%d) created: rfd(%d) wfd(%d)\n", child, rfd[0], wfd[1]);
-
-		state->httpbuf.ptr = state->httpbuf.buf;
-		state->httpbuf.len = sizeof(state->httpbuf.buf);
-
-		state->content_length = cl->httpbuf.len;
-
-		/* find content length */
-		if (req->method == UH_HTTP_MSG_POST)
-		{
-			foreach_header(i, req->headers)
-			{
-				if (!strcasecmp(req->headers[i], "Content-Length"))
-				{
-					state->content_length = atoi(req->headers[i+1]);
-					break;
-				}
-			}
-		}
-
-		cl->cb = uh_cgi_socket_cb;
-		cl->priv = state;
-
-		break;
-	}
-
-	return true;
-}

+ 0 - 43
package/network/services/uhttpd/src/uhttpd-cgi.h

@@ -1,43 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - CGI header
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_CGI_
-
-#include <errno.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <linux/limits.h>
-
-#include <time.h>
-
-
-struct uh_cgi_state {
-	struct {
-		char buf[UH_LIMIT_MSGHEAD];
-		char *ptr;
-		int len;
-	} httpbuf;
-	int content_length;
-	bool header_sent;
-};
-
-bool uh_cgi_request(struct client *cl, struct path_info *pi,
-					struct interpreter *ip);
-
-#endif

+ 0 - 438
package/network/services/uhttpd/src/uhttpd-file.c

@@ -1,438 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Static file handler
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#define _XOPEN_SOURCE 500	/* strptime() */
-#define _BSD_SOURCE			/* scandir(), timegm() */
-
-#include "uhttpd.h"
-#include "uhttpd-utils.h"
-#include "uhttpd-file.h"
-
-#include "uhttpd-mimetypes.h"
-
-
-static const char * uh_file_mime_lookup(const char *path)
-{
-	struct mimetype *m = &uh_mime_types[0];
-	const char *e;
-
-	while (m->extn)
-	{
-		e = &path[strlen(path)-1];
-
-		while (e >= path)
-		{
-			if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
-				return m->mime;
-
-			e--;
-		}
-
-		m++;
-	}
-
-	return "application/octet-stream";
-}
-
-static const char * uh_file_mktag(struct stat *s)
-{
-	static char tag[128];
-
-	snprintf(tag, sizeof(tag), "\"%x-%x-%x\"",
-			 (unsigned int) s->st_ino,
-			 (unsigned int) s->st_size,
-			 (unsigned int) s->st_mtime);
-
-	return tag;
-}
-
-static time_t uh_file_date2unix(const char *date)
-{
-	struct tm t;
-
-	memset(&t, 0, sizeof(t));
-
-	if (strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL)
-		return timegm(&t);
-
-	return 0;
-}
-
-static char * uh_file_unix2date(time_t ts)
-{
-	static char str[128];
-	struct tm *t = gmtime(&ts);
-
-	strftime(str, sizeof(str), "%a, %d %b %Y %H:%M:%S GMT", t);
-
-	return str;
-}
-
-static char * uh_file_header_lookup(struct client *cl, const char *name)
-{
-	int i;
-
-	foreach_header(i, cl->request.headers)
-	{
-		if (!strcasecmp(cl->request.headers[i], name))
-			return cl->request.headers[i+1];
-	}
-
-	return NULL;
-}
-
-
-static int uh_file_response_ok_hdrs(struct client *cl, struct stat *s)
-{
-	ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n"));
-
-	if (s)
-	{
-		ensure_ret(uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s)));
-		ensure_ret(uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n",
-								 uh_file_unix2date(s->st_mtime)));
-	}
-
-	return uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL)));
-}
-
-static int uh_file_response_200(struct client *cl, struct stat *s)
-{
-	ensure_ret(uh_http_sendf(cl, NULL, "%s 200 OK\r\n",
-							 http_versions[cl->request.version]));
-
-	return uh_file_response_ok_hdrs(cl, s);
-}
-
-static int uh_file_response_304(struct client *cl, struct stat *s)
-{
-	ensure_ret(uh_http_sendf(cl, NULL, "%s 304 Not Modified\r\n",
-							 http_versions[cl->request.version]));
-
-	return uh_file_response_ok_hdrs(cl, s);
-}
-
-static int uh_file_response_412(struct client *cl)
-{
-	return uh_http_sendf(cl, NULL,
-						 "%s 412 Precondition Failed\r\n"
-						 "Connection: close\r\n",
-	                     http_versions[cl->request.version]);
-}
-
-static int uh_file_if_match(struct client *cl, struct stat *s, int *ok)
-{
-	const char *tag = uh_file_mktag(s);
-	char *hdr = uh_file_header_lookup(cl, "If-Match");
-	char *p;
-	int i;
-
-	if (hdr)
-	{
-		p = &hdr[0];
-
-		for (i = 0; i < strlen(hdr); i++)
-		{
-			if ((hdr[i] == ' ') || (hdr[i] == ','))
-			{
-				hdr[i++] = 0;
-				p = &hdr[i];
-			}
-			else if (!strcmp(p, "*") || !strcmp(p, tag))
-			{
-				*ok = 1;
-				return *ok;
-			}
-		}
-
-		*ok = 0;
-		ensure_ret(uh_file_response_412(cl));
-		return *ok;
-	}
-
-	*ok = 1;
-	return *ok;
-}
-
-static int uh_file_if_modified_since(struct client *cl, struct stat *s, int *ok)
-{
-	char *hdr = uh_file_header_lookup(cl, "If-Modified-Since");
-	*ok = 1;
-
-	if (hdr)
-	{
-		if (uh_file_date2unix(hdr) >= s->st_mtime)
-		{
-			*ok = 0;
-			ensure_ret(uh_file_response_304(cl, s));
-		}
-	}
-
-	return *ok;
-}
-
-static int uh_file_if_none_match(struct client *cl, struct stat *s, int *ok)
-{
-	const char *tag = uh_file_mktag(s);
-	char *hdr = uh_file_header_lookup(cl, "If-None-Match");
-	char *p;
-	int i;
-	*ok = 1;
-
-	if (hdr)
-	{
-		p = &hdr[0];
-
-		for (i = 0; i < strlen(hdr); i++)
-		{
-			if ((hdr[i] == ' ') || (hdr[i] == ','))
-			{
-				hdr[i++] = 0;
-				p = &hdr[i];
-			}
-			else if (!strcmp(p, "*") || !strcmp(p, tag))
-			{
-				*ok = 0;
-
-				if ((cl->request.method == UH_HTTP_MSG_GET) ||
-				    (cl->request.method == UH_HTTP_MSG_HEAD))
-				{
-					ensure_ret(uh_file_response_304(cl, s));
-				}
-				else
-				{
-					ensure_ret(uh_file_response_412(cl));
-				}
-
-				break;
-			}
-		}
-	}
-
-	return *ok;
-}
-
-static int uh_file_if_range(struct client *cl, struct stat *s, int *ok)
-{
-	char *hdr = uh_file_header_lookup(cl, "If-Range");
-	*ok = 1;
-
-	if (hdr)
-	{
-		*ok = 0;
-		ensure_ret(uh_file_response_412(cl));
-	}
-
-	return *ok;
-}
-
-static int uh_file_if_unmodified_since(struct client *cl, struct stat *s,
-									   int *ok)
-{
-	char *hdr = uh_file_header_lookup(cl, "If-Unmodified-Since");
-	*ok = 1;
-
-	if (hdr)
-	{
-		if (uh_file_date2unix(hdr) <= s->st_mtime)
-		{
-			*ok = 0;
-			ensure_ret(uh_file_response_412(cl));
-		}
-	}
-
-	return *ok;
-}
-
-
-static int uh_file_scandir_filter_dir(const struct dirent *e)
-{
-	return strcmp(e->d_name, ".") ? 1 : 0;
-}
-
-static void uh_file_dirlist(struct client *cl, struct path_info *pi)
-{
-	int i;
-	int count = 0;
-	char filename[PATH_MAX];
-	char *pathptr;
-	struct dirent **files = NULL;
-	struct stat s;
-
-	ensure_out(uh_http_sendf(cl, &cl->request,
-							 "<html><head><title>Index of %s</title></head>"
-							 "<body><h1>Index of %s</h1><hr /><ol>",
-							 pi->name, pi->name));
-
-	if ((count = scandir(pi->phys, &files, uh_file_scandir_filter_dir,
-						 alphasort)) > 0)
-	{
-		memset(filename, 0, sizeof(filename));
-		memcpy(filename, pi->phys, sizeof(filename));
-		pathptr = &filename[strlen(filename)];
-
-		/* list subdirs */
-		for (i = 0; i < count; i++)
-		{
-			strncat(filename, files[i]->d_name,
-					sizeof(filename) - strlen(files[i]->d_name));
-
-			if (!stat(filename, &s) &&
-				(s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH))
-			{
-				ensure_out(uh_http_sendf(cl, &cl->request,
-										 "<li><strong><a href='%s%s'>%s</a>/"
-										 "</strong><br /><small>modified: %s"
-										 "<br />directory - %.02f kbyte<br />"
-										 "<br /></small></li>",
-										 pi->name, files[i]->d_name,
-										 files[i]->d_name,
-										 uh_file_unix2date(s.st_mtime),
-										 s.st_size / 1024.0));
-			}
-
-			*pathptr = 0;
-		}
-
-		/* list files */
-		for (i = 0; i < count; i++)
-		{
-			strncat(filename, files[i]->d_name,
-					sizeof(filename) - strlen(files[i]->d_name));
-
-			if (!stat(filename, &s) &&
-				!(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH))
-			{
-				ensure_out(uh_http_sendf(cl, &cl->request,
-										 "<li><strong><a href='%s%s'>%s</a>"
-										 "</strong><br /><small>modified: %s"
-										 "<br />%s - %.02f kbyte<br />"
-										 "<br /></small></li>",
-										 pi->name, files[i]->d_name,
-										 files[i]->d_name,
-										 uh_file_unix2date(s.st_mtime),
-										 uh_file_mime_lookup(filename),
-										 s.st_size / 1024.0));
-			}
-
-			*pathptr = 0;
-		}
-	}
-
-	ensure_out(uh_http_sendf(cl, &cl->request, "</ol><hr /></body></html>"));
-	ensure_out(uh_http_sendf(cl, &cl->request, ""));
-
-out:
-	if (files)
-	{
-		for (i = 0; i < count; i++)
-			free(files[i]);
-
-		free(files);
-	}
-}
-
-
-bool uh_file_request(struct client *cl, struct path_info *pi)
-{
-	int rlen;
-	int ok = 1;
-	int fd = -1;
-	char buf[UH_LIMIT_MSGHEAD];
-
-	/* we have a file */
-	if ((pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0))
-	{
-		/* test preconditions */
-		if (ok) ensure_out(uh_file_if_modified_since(cl, &pi->stat, &ok));
-		if (ok) ensure_out(uh_file_if_match(cl, &pi->stat, &ok));
-		if (ok) ensure_out(uh_file_if_range(cl, &pi->stat, &ok));
-		if (ok) ensure_out(uh_file_if_unmodified_since(cl, &pi->stat, &ok));
-		if (ok) ensure_out(uh_file_if_none_match(cl, &pi->stat, &ok));
-
-		if (ok > 0)
-		{
-			/* write status */
-			ensure_out(uh_file_response_200(cl, &pi->stat));
-
-			ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n",
-									 uh_file_mime_lookup(pi->name)));
-
-			ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n",
-									 pi->stat.st_size));
-
-			/* if request was HTTP 1.1 we'll respond chunked */
-			if ((cl->request.version > 1.0) &&
-				(cl->request.method != UH_HTTP_MSG_HEAD))
-			{
-				ensure_out(uh_http_send(cl, NULL,
-										"Transfer-Encoding: chunked\r\n", -1));
-			}
-
-			/* close header */
-			ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
-
-			/* send body */
-			if (cl->request.method != UH_HTTP_MSG_HEAD)
-			{
-				/* pump file data */
-				while ((rlen = read(fd, buf, sizeof(buf))) > 0)
-					ensure_out(uh_http_send(cl, &cl->request, buf, rlen));
-
-				/* send trailer in chunked mode */
-				ensure_out(uh_http_send(cl, &cl->request, "", 0));
-			}
-		}
-
-		/* one of the preconditions failed, terminate opened header and exit */
-		else
-		{
-			ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
-		}
-	}
-
-	/* directory */
-	else if ((pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists)
-	{
-		/* write status */
-		ensure_out(uh_file_response_200(cl, NULL));
-
-		if (cl->request.version > 1.0)
-			ensure_out(uh_http_send(cl, NULL,
-									"Transfer-Encoding: chunked\r\n", -1));
-
-		ensure_out(uh_http_send(cl, NULL,
-								"Content-Type: text/html\r\n\r\n", -1));
-
-		/* content */
-		uh_file_dirlist(cl, pi);
-	}
-
-	/* 403 */
-	else
-	{
-		ensure_out(uh_http_sendhf(cl, 403, "Forbidden",
-								  "Access to this resource is forbidden"));
-	}
-
-out:
-	if (fd > -1)
-		close(fd);
-
-	return false;
-}

+ 0 - 36
package/network/services/uhttpd/src/uhttpd-file.h

@@ -1,36 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Static file header
- *
- *   Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_FILE_
-
-#include <fcntl.h>
-#include <time.h>
-#include <strings.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <linux/limits.h>
-
-struct mimetype {
-	const char *extn;
-	const char *mime;
-};
-
-bool uh_file_request(struct client *cl, struct path_info *pi);
-
-#endif

+ 0 - 579
package/network/services/uhttpd/src/uhttpd-lua.c

@@ -1,579 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Lua handler
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#include "uhttpd.h"
-#include "uhttpd-utils.h"
-#include "uhttpd-lua.h"
-
-
-static int uh_lua_recv(lua_State *L)
-{
-	size_t length;
-
-	char buffer[UH_LIMIT_MSGHEAD];
-
-	int to = 1;
-	int fd = fileno(stdin);
-	int rlen = 0;
-
-	length = luaL_checknumber(L, 1);
-
-	if ((length > 0) && (length <= sizeof(buffer)))
-	{
-		/* receive data */
-		rlen = uh_raw_recv(fd, buffer, length, to);
-
-		/* data read */
-		if (rlen > 0)
-		{
-			lua_pushnumber(L, rlen);
-			lua_pushlstring(L, buffer, rlen);
-			return 2;
-		}
-
-		/* eof */
-		else if (rlen == 0)
-		{
-			lua_pushnumber(L, 0);
-			return 1;
-		}
-
-		/* no, timeout and actually no data */
-		else
-		{
-			lua_pushnumber(L, -1);
-			return 1;
-		}
-	}
-
-	/* parameter error */
-	lua_pushnumber(L, -2);
-	return 1;
-}
-
-static int uh_lua_send_common(lua_State *L, bool chunked)
-{
-	size_t length;
-
-	char chunk[16];
-	const char *buffer;
-
-	int rv;
-	int to = 1;
-	int fd = fileno(stdout);
-	int slen = 0;
-
-	buffer = luaL_checklstring(L, 1, &length);
-
-	if (chunked)
-	{
-		if (length > 0)
-		{
-			snprintf(chunk, sizeof(chunk), "%X\r\n", length);
-
-			ensure_out(rv = uh_raw_send(fd, chunk, strlen(chunk), to));
-			slen += rv;
-
-			ensure_out(rv = uh_raw_send(fd, buffer, length, to));
-			slen += rv;
-
-			ensure_out(rv = uh_raw_send(fd, "\r\n", 2, to));
-			slen += rv;
-		}
-		else
-		{
-			slen = uh_raw_send(fd, "0\r\n\r\n", 5, to);
-		}
-	}
-	else
-	{
-		slen = uh_raw_send(fd, buffer, length, to);
-	}
-
-out:
-	lua_pushnumber(L, slen);
-	return 1;
-}
-
-static int uh_lua_send(lua_State *L)
-{
-	return uh_lua_send_common(L, false);
-}
-
-static int uh_lua_sendc(lua_State *L)
-{
-	return uh_lua_send_common(L, true);
-}
-
-static int uh_lua_str2str(lua_State *L, int (*xlate_func) (char *, int, const char *, int))
-{
-	size_t inlen;
-	int outlen;
-	const char *inbuf;
-	char outbuf[UH_LIMIT_MSGHEAD];
-
-	inbuf = luaL_checklstring(L, 1, &inlen);
-	outlen = (* xlate_func)(outbuf, sizeof(outbuf), inbuf, inlen);
-	if (outlen < 0)
-		luaL_error(L, "%s on URL-encode codec",
-				   (outlen==-1) ? "buffer overflow" : "malformed string");
-
-	lua_pushlstring(L, outbuf, outlen);
-	return 1;
-}
-
-static int uh_lua_urldecode(lua_State *L)
-{
-	return uh_lua_str2str( L, uh_urldecode );
-}
-
-
-static int uh_lua_urlencode(lua_State *L)
-{
-	return uh_lua_str2str( L, uh_urlencode );
-}
-
-
-lua_State * uh_lua_init(const struct config *conf)
-{
-	lua_State *L = lua_open();
-	const char *err_str = NULL;
-
-	/* Load standard libaries */
-	luaL_openlibs(L);
-
-	/* build uhttpd api table */
-	lua_newtable(L);
-
-	/* register global send and receive functions */
-	lua_pushcfunction(L, uh_lua_recv);
-	lua_setfield(L, -2, "recv");
-
-	lua_pushcfunction(L, uh_lua_send);
-	lua_setfield(L, -2, "send");
-
-	lua_pushcfunction(L, uh_lua_sendc);
-	lua_setfield(L, -2, "sendc");
-
-	lua_pushcfunction(L, uh_lua_urldecode);
-	lua_setfield(L, -2, "urldecode");
-
-	lua_pushcfunction(L, uh_lua_urlencode);
-	lua_setfield(L, -2, "urlencode");
-
-	/* Pass the document-root to the Lua handler by placing it in
-	** uhttpd.docroot.  It could alternatively be placed in env.DOCUMENT_ROOT
-	** which would more closely resemble the CGI protocol; but would mean that
-	** it is not available at the time when the handler-chunk is loaded but
-	** rather not until the handler is called, without any code savings. */
-	lua_pushstring(L, conf->docroot);
-	lua_setfield(L, -2, "docroot");
-
-	/* _G.uhttpd = { ... } */
-	lua_setfield(L, LUA_GLOBALSINDEX, "uhttpd");
-
-
-	/* load Lua handler */
-	switch (luaL_loadfile(L, conf->lua_handler))
-	{
-		case LUA_ERRSYNTAX:
-			fprintf(stderr,
-					"Lua handler contains syntax errors, unable to continue\n");
-			exit(1);
-
-		case LUA_ERRMEM:
-			fprintf(stderr,
-					"Lua handler ran out of memory, unable to continue\n");
-			exit(1);
-
-		case LUA_ERRFILE:
-			fprintf(stderr,
-					"Lua cannot open the handler script, unable to continue\n");
-			exit(1);
-
-		default:
-			/* compile Lua handler */
-			switch (lua_pcall(L, 0, 0, 0))
-			{
-				case LUA_ERRRUN:
-					err_str = luaL_checkstring(L, -1);
-					fprintf(stderr,
-							"Lua handler had runtime error, "
-							"unable to continue\n"
-							"Error: %s\n", err_str);
-					exit(1);
-
-				case LUA_ERRMEM:
-					err_str = luaL_checkstring(L, -1);
-					fprintf(stderr,
-							"Lua handler ran out of memory, "
-							"unable to continue\n"
-							"Error: %s\n", err_str);
-					exit(1);
-
-				default:
-					/* test handler function */
-					lua_getglobal(L, UH_LUA_CALLBACK);
-
-					if (! lua_isfunction(L, -1))
-					{
-						fprintf(stderr,
-								"Lua handler provides no "UH_LUA_CALLBACK"(), "
-								"unable to continue\n");
-						exit(1);
-					}
-
-					lua_pop(L, 1);
-					break;
-			}
-
-			break;
-	}
-
-	return L;
-}
-
-static void uh_lua_shutdown(struct uh_lua_state *state)
-{
-	free(state);
-}
-
-static bool uh_lua_socket_cb(struct client *cl)
-{
-	int len;
-	char buf[UH_LIMIT_MSGHEAD];
-
-	struct uh_lua_state *state = (struct uh_lua_state *)cl->priv;
-
-	/* there is unread post data waiting */
-	while (state->content_length > 0)
-	{
-		/* remaining data in http head buffer ... */
-		if (cl->httpbuf.len > 0)
-		{
-			len = min(state->content_length, cl->httpbuf.len);
-
-			D("Lua: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
-
-			memcpy(buf, cl->httpbuf.ptr, len);
-
-			cl->httpbuf.len -= len;
-			cl->httpbuf.ptr += len;
-		}
-
-		/* read it from socket ... */
-		else
-		{
-			len = uh_tcp_recv(cl, buf, min(state->content_length, sizeof(buf)));
-
-			if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
-				break;
-
-			D("Lua: Child(%d) feed %d/%d TCP socket bytes\n",
-			  cl->proc.pid, len, min(state->content_length, sizeof(buf)));
-		}
-
-		if (len)
-			state->content_length -= len;
-		else
-			state->content_length = 0;
-
-		/* ... write to Lua process */
-		len = uh_raw_send(cl->wpipe.fd, buf, len,
-						  cl->server->conf->script_timeout);
-
-		/* explicit EOF notification for the child */
-		if (state->content_length <= 0)
-			uh_ufd_remove(&cl->wpipe);
-	}
-
-	/* try to read data from child */
-	while ((len = uh_raw_recv(cl->rpipe.fd, buf, sizeof(buf), -1)) > 0)
-	{
-		/* pass through buffer to socket */
-		D("Lua: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
-		ensure_out(uh_tcp_send(cl, buf, len));
-		state->data_sent = true;
-	}
-
-	/* got EOF or read error from child */
-	if ((len == 0) ||
-		((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
-	{
-		D("Lua: Child(%d) presumed dead [%s]\n",
-		  cl->proc.pid, strerror(errno));
-
-		goto out;
-	}
-
-	return true;
-
-out:
-	if (!state->data_sent)
-	{
-		if (cl->timeout.pending)
-			uh_http_sendhf(cl, 502, "Bad Gateway",
-						   "The Lua process did not produce any response\n");
-		else
-			uh_http_sendhf(cl, 504, "Gateway Timeout",
-						   "The Lua process took too long to produce a "
-						   "response\n");
-	}
-
-	uh_lua_shutdown(state);
-	return false;
-}
-
-bool uh_lua_request(struct client *cl, lua_State *L)
-{
-	int i;
-	char *query_string;
-	const char *prefix = cl->server->conf->lua_prefix;
-	const char *err_str = NULL;
-
-	int rfd[2] = { 0, 0 };
-	int wfd[2] = { 0, 0 };
-
-	pid_t child;
-
-	struct uh_lua_state *state;
-	struct http_request *req = &cl->request;
-
-	int content_length = cl->httpbuf.len;
-
-
-	/* allocate state */
-	if (!(state = malloc(sizeof(*state))))
-	{
-		uh_client_error(cl, 500, "Internal Server Error", "Out of memory");
-		return false;
-	}
-
-	/* spawn pipes for me->child, child->me */
-	if ((pipe(rfd) < 0) || (pipe(wfd) < 0))
-	{
-		if (rfd[0] > 0) close(rfd[0]);
-		if (rfd[1] > 0) close(rfd[1]);
-		if (wfd[0] > 0) close(wfd[0]);
-		if (wfd[1] > 0) close(wfd[1]);
-
-		uh_client_error(cl, 500, "Internal Server Error",
-						"Failed to create pipe: %s", strerror(errno));
-
-		return false;
-	}
-
-
-	switch ((child = fork()))
-	{
-	case -1:
-		uh_client_error(cl, 500, "Internal Server Error",
-						"Failed to fork child: %s", strerror(errno));
-
-		return false;
-
-	case 0:
-#ifdef DEBUG
-		sleep(atoi(getenv("UHTTPD_SLEEP_ON_FORK") ?: "0"));
-#endif
-
-		/* do not leak parent epoll descriptor */
-		uloop_done();
-
-		/* close loose pipe ends */
-		close(rfd[0]);
-		close(wfd[1]);
-
-		/* patch stdout and stdin to pipes */
-		dup2(rfd[1], 1);
-		dup2(wfd[0], 0);
-
-		/* avoid leaking our pipe into child-child processes */
-		fd_cloexec(rfd[1]);
-		fd_cloexec(wfd[0]);
-
-		/* put handler callback on stack */
-		lua_getglobal(L, UH_LUA_CALLBACK);
-
-		/* build env table */
-		lua_newtable(L);
-
-		/* request method */
-		lua_pushstring(L, http_methods[req->method]);
-		lua_setfield(L, -2, "REQUEST_METHOD");
-
-		/* request url */
-		lua_pushstring(L, req->url);
-		lua_setfield(L, -2, "REQUEST_URI");
-
-		/* script name */
-		lua_pushstring(L, cl->server->conf->lua_prefix);
-		lua_setfield(L, -2, "SCRIPT_NAME");
-
-		/* query string, path info */
-		if ((query_string = strchr(req->url, '?')) != NULL)
-		{
-			lua_pushstring(L, query_string + 1);
-			lua_setfield(L, -2, "QUERY_STRING");
-
-			if ((int)(query_string - req->url) > strlen(prefix))
-			{
-				lua_pushlstring(L,
-					&req->url[strlen(prefix)],
-					(int)(query_string - req->url) - strlen(prefix)
-				);
-
-				lua_setfield(L, -2, "PATH_INFO");
-			}
-		}
-		else if (strlen(req->url) > strlen(prefix))
-		{
-			lua_pushstring(L, &req->url[strlen(prefix)]);
-			lua_setfield(L, -2, "PATH_INFO");
-		}
-
-		/* http protcol version */
-		lua_pushnumber(L, 0.9 + (req->version / 10.0));
-		lua_setfield(L, -2, "HTTP_VERSION");
-
-		lua_pushstring(L, http_versions[req->version]);
-		lua_setfield(L, -2, "SERVER_PROTOCOL");
-
-
-		/* address information */
-		lua_pushstring(L, sa_straddr(&cl->peeraddr));
-		lua_setfield(L, -2, "REMOTE_ADDR");
-
-		lua_pushinteger(L, sa_port(&cl->peeraddr));
-		lua_setfield(L, -2, "REMOTE_PORT");
-
-		lua_pushstring(L, sa_straddr(&cl->servaddr));
-		lua_setfield(L, -2, "SERVER_ADDR");
-
-		lua_pushinteger(L, sa_port(&cl->servaddr));
-		lua_setfield(L, -2, "SERVER_PORT");
-
-		/* essential env vars */
-		foreach_header(i, req->headers)
-		{
-			if (!strcasecmp(req->headers[i], "Content-Length"))
-			{
-				content_length = atoi(req->headers[i+1]);
-			}
-			else if (!strcasecmp(req->headers[i], "Content-Type"))
-			{
-				lua_pushstring(L, req->headers[i+1]);
-				lua_setfield(L, -2, "CONTENT_TYPE");
-			}
-		}
-
-		lua_pushnumber(L, content_length);
-		lua_setfield(L, -2, "CONTENT_LENGTH");
-
-		/* misc. headers */
-		lua_newtable(L);
-
-		foreach_header(i, req->headers)
-		{
-			if( strcasecmp(req->headers[i], "Content-Length") &&
-				strcasecmp(req->headers[i], "Content-Type"))
-			{
-				lua_pushstring(L, req->headers[i+1]);
-				lua_setfield(L, -2, req->headers[i]);
-			}
-		}
-
-		lua_setfield(L, -2, "headers");
-
-
-		/* call */
-		switch (lua_pcall(L, 1, 0, 0))
-		{
-			case LUA_ERRMEM:
-			case LUA_ERRRUN:
-				err_str = luaL_checkstring(L, -1);
-
-				if (! err_str)
-					err_str = "Unknown error";
-
-				printf("%s 500 Internal Server Error\r\n"
-					   "Connection: close\r\n"
-					   "Content-Type: text/plain\r\n"
-					   "Content-Length: %i\r\n\r\n"
-					   "Lua raised a runtime error:\n  %s\n",
-					   http_versions[req->version],
-					   31 + strlen(err_str), err_str);
-
-				break;
-
-			default:
-				break;
-		}
-
-		close(wfd[0]);
-		close(rfd[1]);
-		exit(0);
-
-		break;
-
-	/* parent; handle I/O relaying */
-	default:
-		memset(state, 0, sizeof(*state));
-
-		cl->rpipe.fd = rfd[0];
-		cl->wpipe.fd = wfd[1];
-		cl->proc.pid = child;
-
-		/* make pipe non-blocking */
-		fd_nonblock(cl->rpipe.fd);
-		fd_nonblock(cl->wpipe.fd);
-
-		/* close unneeded pipe ends */
-		close(rfd[1]);
-		close(wfd[0]);
-
-		D("Lua: Child(%d) created: rfd(%d) wfd(%d)\n", child, rfd[0], wfd[1]);
-
-		state->content_length = cl->httpbuf.len;
-
-		/* find content length */
-		if (req->method == UH_HTTP_MSG_POST)
-		{
-			foreach_header(i, req->headers)
-			{
-				if (!strcasecmp(req->headers[i], "Content-Length"))
-				{
-					state->content_length = atoi(req->headers[i+1]);
-					break;
-				}
-			}
-		}
-
-		cl->cb = uh_lua_socket_cb;
-		cl->priv = state;
-
-		break;
-	}
-
-	return true;
-}
-
-void uh_lua_close(lua_State *L)
-{
-	lua_close(L);
-}

+ 0 - 44
package/network/services/uhttpd/src/uhttpd-lua.h

@@ -1,44 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Lua header
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_LUA_
-
-#include <math.h>  /* floor() */
-#include <errno.h>
-
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-
-#define UH_LUA_CALLBACK		"handle_request"
-
-#define UH_LUA_ERR_TIMEOUT -1
-#define UH_LUA_ERR_TOOBIG  -2
-#define UH_LUA_ERR_PARAM   -3
-
-
-struct uh_lua_state {
-	int content_length;
-	bool data_sent;
-};
-
-lua_State * uh_lua_init(const struct config *conf);
-bool uh_lua_request(struct client *cl, lua_State *L);
-void uh_lua_close(lua_State *L);
-
-#endif

+ 0 - 86
package/network/services/uhttpd/src/uhttpd-mimetypes.h

@@ -1,86 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - MIME type definitions
- *
- *   Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_MIMETYPES_
-
-static struct mimetype uh_mime_types[] = {
-
-	{ "txt",     "text/plain" },
-	{ "log",     "text/plain" },
-	{ "js",      "text/javascript" },
-	{ "css",     "text/css" },
-	{ "htm",     "text/html" },
-	{ "html",    "text/html" },
-	{ "diff",    "text/x-patch" },
-	{ "patch",   "text/x-patch" },
-	{ "c",       "text/x-csrc" },
-	{ "h",       "text/x-chdr" },
-	{ "o",       "text/x-object" },
-	{ "ko",      "text/x-object" },
-
-	{ "bmp",     "image/bmp" },
-	{ "gif",     "image/gif" },
-	{ "png",     "image/png" },
-	{ "jpg",     "image/jpeg" },
-	{ "jpeg",    "image/jpeg" },
-	{ "svg",     "image/svg+xml" },
-
-	{ "zip",     "application/zip" },
-	{ "pdf",     "application/pdf" },
-	{ "xml",     "application/xml" },
-	{ "xsl",     "application/xml" },
-	{ "doc",     "application/msword" },
-	{ "ppt",     "application/vnd.ms-powerpoint" },
-	{ "xls",     "application/vnd.ms-excel" },
-	{ "odt",     "application/vnd.oasis.opendocument.text" },
-	{ "odp",     "application/vnd.oasis.opendocument.presentation" },
-	{ "pl",      "application/x-perl" },
-	{ "sh",      "application/x-shellscript" },
-	{ "php",     "application/x-php" },
-	{ "deb",     "application/x-deb" },
-	{ "iso",     "application/x-cd-image" },
-	{ "tar.gz",  "application/x-compressed-tar" },
-	{ "tgz",     "application/x-compressed-tar" },
-	{ "gz",      "application/x-gzip" },
-	{ "tar.bz2", "application/x-bzip-compressed-tar" },
-	{ "tbz",     "application/x-bzip-compressed-tar" },
-	{ "bz2",     "application/x-bzip" },
-	{ "tar",     "application/x-tar" },
-	{ "rar",     "application/x-rar-compressed" },
-
-	{ "mp3",     "audio/mpeg" },
-	{ "ogg",     "audio/x-vorbis+ogg" },
-	{ "wav",     "audio/x-wav" },
-
-	{ "mpg",     "video/mpeg" },
-	{ "mpeg",    "video/mpeg" },
-	{ "avi",     "video/x-msvideo" },
-
-	{ "README",  "text/plain" },
-	{ "log",     "text/plain" },
-	{ "cfg",     "text/plain" },
-	{ "conf",    "text/plain" },
-
-	{ "pac",		"application/x-ns-proxy-autoconfig" },
-	{ "wpad.dat",	"application/x-ns-proxy-autoconfig" },
-
-	{ NULL, NULL }
-};
-
-#endif
-

+ 0 - 170
package/network/services/uhttpd/src/uhttpd-tls.c

@@ -1,170 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - TLS helper
- *
- *   Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#include "uhttpd.h"
-#include "uhttpd-tls.h"
-#include "uhttpd-utils.h"
-
-#include <syslog.h>
-#define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
-
-SSL_CTX * uh_tls_ctx_init(void)
-{
-	SSL_CTX *c;
-
-	SSL_load_error_strings();
-	SSL_library_init();
-
-#if TLS_IS_OPENSSL
-	if ((c = SSL_CTX_new(SSLv23_server_method())) != NULL)
-#else
-	if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
-#endif
-		SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
-
-	return c;
-}
-
-int uh_tls_ctx_cert(SSL_CTX *c, const char *file)
-{
-	int rv;
-
-	if( (rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_PEM)) < 1 )
-		rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_ASN1);
-
-	return rv;
-}
-
-int uh_tls_ctx_key(SSL_CTX *c, const char *file)
-{
-	int rv;
-
-	if( (rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_PEM)) < 1 )
-		rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_ASN1);
-
-	return rv;
-}
-
-void uh_tls_ctx_free(struct listener *l)
-{
-	SSL_CTX_free(l->tls);
-}
-
-
-int uh_tls_client_accept(struct client *c)
-{
-	int rv, err;
-	int fd = c->fd.fd;
-
-	if (!c->server || !c->server->tls)
-	{
-		c->tls = NULL;
-		return 1;
-	}
-
-	if ((c->tls = SSL_new(c->server->tls)))
-	{
-		if ((rv = SSL_set_fd(c->tls, fd)) < 1)
-		{
-			SSL_free(c->tls);
-			c->tls = NULL;
-		}
-		else
-		{
-			while (true)
-			{
-				rv = SSL_accept(c->tls);
-				err = SSL_get_error(c->tls, rv);
-
-				if ((rv != 1) &&
-					(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE))
-				{
-					if (uh_socket_wait(fd, c->server->conf->network_timeout,
-									   (err == SSL_ERROR_WANT_WRITE)))
-					{
-						D("TLS: accept(%d) = retry\n", fd);
-						continue;
-					}
-
-					D("TLS: accept(%d) = timeout\n", fd);
-				}
-				else if (rv == 1)
-				{
-					D("TLS: accept(%d) = %p\n", fd, c->tls);
-					return 1;
-				}
-
-#ifdef TLS_IS_OPENSSL
-				D("TLS: accept(%d) = failed: %s\n",
-				  fd, ERR_error_string(ERR_get_error(), NULL));
-#endif
-
-				SSL_free(c->tls);
-				c->tls = NULL;
-				break;
-			}
-		}
-	}
-
-	return 0;
-}
-
-int uh_tls_client_recv(struct client *c, char *buf, int len)
-{
-	int rv = SSL_read(c->tls, buf, len);
-	int err = SSL_get_error(c->tls, 0);
-
-	if ((rv == -1) && (err == SSL_ERROR_WANT_READ))
-	{
-		D("TLS: recv(%d, %d) = retry\n", c->fd.fd, len);
-		errno = EAGAIN;
-		return -1;
-	}
-
-	D("TLS: recv(%d, %d) = %d\n", c->fd.fd, len, rv);
-	return rv;
-}
-
-int uh_tls_client_send(struct client *c, const char *buf, int len)
-{
-	int rv = SSL_write(c->tls, buf, len);
-	int err = SSL_get_error(c->tls, 0);
-
-	if ((rv == -1) && (err == SSL_ERROR_WANT_WRITE))
-	{
-		D("TLS: send(%d, %d) = retry\n", c->fd.fd, len);
-		errno = EAGAIN;
-		return -1;
-	}
-
-	D("TLS: send(%d, %d) = %d\n", c->fd.fd, len, rv);
-	return rv;
-}
-
-void uh_tls_client_close(struct client *c)
-{
-	if (c->tls)
-	{
-		D("TLS: close(%d)\n", c->fd.fd);
-
-		SSL_shutdown(c->tls);
-		SSL_free(c->tls);
-
-		c->tls = NULL;
-	}
-}

+ 0 - 36
package/network/services/uhttpd/src/uhttpd-tls.h

@@ -1,36 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - TLS header
- *
- *   Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_TLS_
-
-#include <openssl/ssl.h>
-#ifdef TLS_IS_OPENSSL
-#include <openssl/err.h>
-#endif
-
-SSL_CTX * uh_tls_ctx_init();
-int uh_tls_ctx_cert(SSL_CTX *c, const char *file);
-int uh_tls_ctx_key(SSL_CTX *c, const char *file);
-void uh_tls_ctx_free(struct listener *l);
-
-int uh_tls_client_accept(struct client *c);
-int uh_tls_client_recv(struct client *c, char *buf, int len);
-int uh_tls_client_send(struct client *c, const char *buf, int len);
-void uh_tls_client_close(struct client *c);
-
-#endif

+ 0 - 957
package/network/services/uhttpd/src/uhttpd-ubus.c

@@ -1,957 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - ubus handler
- *
- *   Copyright (C) 2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#include "uhttpd.h"
-#include "uhttpd-utils.h"
-#include "uhttpd-ubus.h"
-
-
-enum {
-	UH_UBUS_SN_TIMEOUT,
-	__UH_UBUS_SN_MAX,
-};
-
-static const struct blobmsg_policy new_policy[__UH_UBUS_SN_MAX] = {
-	[UH_UBUS_SN_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
-};
-
-
-enum {
-	UH_UBUS_SI_SID,
-	__UH_UBUS_SI_MAX,
-};
-
-static const struct blobmsg_policy sid_policy[__UH_UBUS_SI_MAX] = {
-	[UH_UBUS_SI_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
-};
-
-
-enum {
-	UH_UBUS_SS_SID,
-	UH_UBUS_SS_VALUES,
-	__UH_UBUS_SS_MAX,
-};
-
-static const struct blobmsg_policy set_policy[__UH_UBUS_SS_MAX] = {
-	[UH_UBUS_SS_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
-	[UH_UBUS_SS_VALUES] = { .name = "values", .type = BLOBMSG_TYPE_TABLE },
-};
-
-
-enum {
-	UH_UBUS_SG_SID,
-	UH_UBUS_SG_KEYS,
-	__UH_UBUS_SG_MAX,
-};
-
-static const struct blobmsg_policy get_policy[__UH_UBUS_SG_MAX] = {
-	[UH_UBUS_SG_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
-	[UH_UBUS_SG_KEYS] = { .name = "keys", .type = BLOBMSG_TYPE_ARRAY },
-};
-
-
-enum {
-	UH_UBUS_SA_SID,
-	UH_UBUS_SA_OBJECTS,
-	__UH_UBUS_SA_MAX,
-};
-
-static const struct blobmsg_policy acl_policy[__UH_UBUS_SA_MAX] = {
-	[UH_UBUS_SA_SID] = { .name = "sid", .type = BLOBMSG_TYPE_STRING },
-	[UH_UBUS_SA_OBJECTS] = { .name = "objects", .type = BLOBMSG_TYPE_ARRAY },
-};
-
-
-static bool
-uh_ubus_strmatch(const char *str, const char *pat)
-{
-	while (*pat)
-	{
-		if (*pat == '?')
-		{
-			if (!*str)
-				return false;
-
-			str++;
-			pat++;
-		}
-		else if (*pat == '*')
-		{
-			if (uh_ubus_strmatch(str, pat+1))
-				return true;
-
-			if (*str && uh_ubus_strmatch(str+1, pat))
-				return true;
-
-			return false;
-		}
-		else if (*str++ != *pat++)
-		{
-			return false;
-		}
-	}
-
-	return (!*str && !*pat);
-}
-
-static int
-uh_ubus_avlcmp(const void *k1, const void *k2, void *ptr)
-{
-	return strcmp((char *)k1, (char *)k2);
-}
-
-static void
-uh_ubus_random(char *dest)
-{
-	int i;
-	unsigned char buf[16] = { 0 };
-	FILE *f;
-
-	if ((f = fopen("/dev/urandom", "r")) != NULL)
-	{
-		fread(buf, 1, sizeof(buf), f);
-		fclose(f);
-	}
-
-	for (i = 0; i < sizeof(buf); i++)
-		sprintf(dest + (i<<1), "%02x", buf[i]);
-}
-
-static void
-uh_ubus_session_dump_data(struct uh_ubus_session *ses, struct blob_buf *b)
-{
-	struct uh_ubus_session_data *d;
-
-	avl_for_each_element(&ses->data, d, avl)
-	{
-		blobmsg_add_field(b, blobmsg_type(d->attr), blobmsg_name(d->attr),
-						  blobmsg_data(d->attr), blobmsg_data_len(d->attr));
-	}
-}
-
-static void
-uh_ubus_session_dump_acls(struct uh_ubus_session *ses, struct blob_buf *b)
-{
-	struct uh_ubus_session_acl *acl;
-	const char *lastobj = NULL;
-	void *c = NULL;
-
-	avl_for_each_element(&ses->acls, acl, avl)
-	{
-		if (!lastobj || strcmp(acl->object, lastobj))
-		{
-			if (c) blobmsg_close_array(b, c);
-			c = blobmsg_open_array(b, acl->object);
-		}
-
-		blobmsg_add_string(b, NULL, acl->function);
-		lastobj = acl->object;
-	}
-
-	if (c) blobmsg_close_array(b, c);
-}
-
-static void
-uh_ubus_session_dump(struct uh_ubus_session *ses,
-					 struct ubus_context *ctx,
-					 struct ubus_request_data *req)
-{
-	void *c;
-	struct blob_buf b;
-
-	memset(&b, 0, sizeof(b));
-	blob_buf_init(&b, 0);
-
-	blobmsg_add_string(&b, "sid", ses->id);
-	blobmsg_add_u32(&b, "timeout", ses->timeout);
-	blobmsg_add_u32(&b, "touched", ses->touched.tv_sec);
-
-	c = blobmsg_open_table(&b, "acls");
-	uh_ubus_session_dump_acls(ses, &b);
-	blobmsg_close_table(&b, c);
-
-	c = blobmsg_open_table(&b, "data");
-	uh_ubus_session_dump_data(ses, &b);
-	blobmsg_close_table(&b, c);
-
-	ubus_send_reply(ctx, req, b.head);
-	blob_buf_free(&b);
-}
-
-static struct uh_ubus_session *
-uh_ubus_session_create(struct uh_ubus_state *state, int timeout)
-{
-	struct uh_ubus_session *ses;
-
-	ses = malloc(sizeof(*ses));
-
-	/* failed to allocate memory... */
-	if (!ses)
-		return NULL;
-
-	memset(ses, 0, sizeof(*ses));
-
-	uh_ubus_random(ses->id);
-
-	ses->timeout  = timeout;
-	ses->avl.key  = ses->id;
-
-	avl_insert(&state->sessions, &ses->avl);
-	avl_init(&ses->acls, uh_ubus_avlcmp, true, NULL);
-	avl_init(&ses->data, uh_ubus_avlcmp, false, NULL);
-	clock_gettime(CLOCK_MONOTONIC, &ses->touched);
-
-	return ses;
-}
-
-
-static struct uh_ubus_session *
-uh_ubus_session_get(struct uh_ubus_state *state, const char *id)
-{
-	struct uh_ubus_session *ses;
-
-	ses = avl_find_element(&state->sessions, id, ses, avl);
-
-	if (ses)
-		clock_gettime(CLOCK_MONOTONIC, &ses->touched);
-
-	return ses;
-}
-
-static void
-uh_ubus_session_destroy(struct uh_ubus_state *state,
-						struct uh_ubus_session *ses)
-{
-	struct uh_ubus_session_acl *acl, *nacl;
-	struct uh_ubus_session_data *data, *ndata;
-
-	avl_remove_all_elements(&ses->acls, acl, avl, nacl)
-		free(acl);
-
-	avl_remove_all_elements(&ses->data, data, avl, ndata)
-		free(data);
-
-	avl_delete(&state->sessions, &ses->avl);
-	free(ses);
-}
-
-static void
-uh_ubus_session_cleanup(struct uh_ubus_state *state)
-{
-	struct timespec now;
-	struct uh_ubus_session *ses, *nses;
-
-	clock_gettime(CLOCK_MONOTONIC, &now);
-
-	avl_for_each_element_safe(&state->sessions, ses, avl, nses)
-	{
-		if ((now.tv_sec - ses->touched.tv_sec) >= ses->timeout)
-			uh_ubus_session_destroy(state, ses);
-	}
-}
-
-
-static int
-uh_ubus_handle_create(struct ubus_context *ctx, struct ubus_object *obj,
-					  struct ubus_request_data *req, const char *method,
-					  struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct blob_attr *tb[__UH_UBUS_SN_MAX];
-
-	int timeout = state->timeout;
-
-	blobmsg_parse(new_policy, __UH_UBUS_SN_MAX, tb, blob_data(msg), blob_len(msg));
-
-	/* TODO: make this a uloop timeout */
-	uh_ubus_session_cleanup(state);
-
-	if (tb[UH_UBUS_SN_TIMEOUT])
-		timeout = *(uint32_t *)blobmsg_data(tb[UH_UBUS_SN_TIMEOUT]);
-
-	ses = uh_ubus_session_create(state, timeout);
-
-	if (ses)
-		uh_ubus_session_dump(ses, ctx, req);
-
-	return 0;
-}
-
-static int
-uh_ubus_handle_list(struct ubus_context *ctx, struct ubus_object *obj,
-					struct ubus_request_data *req, const char *method,
-					struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct blob_attr *tb[__UH_UBUS_SI_MAX];
-
-	blobmsg_parse(sid_policy, __UH_UBUS_SI_MAX, tb, blob_data(msg), blob_len(msg));
-
-	/* TODO: make this a uloop timeout */
-	uh_ubus_session_cleanup(state);
-
-	if (!tb[UH_UBUS_SI_SID])
-	{
-		avl_for_each_element(&state->sessions, ses, avl)
-			uh_ubus_session_dump(ses, ctx, req);
-	}
-	else
-	{
-		ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SI_SID]));
-
-		if (!ses)
-			return UBUS_STATUS_NOT_FOUND;
-
-		uh_ubus_session_dump(ses, ctx, req);
-	}
-
-	return 0;
-}
-
-
-static int
-uh_ubus_session_grant(struct uh_ubus_session *ses, struct ubus_context *ctx,
-					  const char *object, const char *function)
-{
-	struct uh_ubus_session_acl *acl, *nacl;
-
-	acl = avl_find_element(&ses->acls, object, acl, avl);
-
-	if (acl)
-	{
-		avl_for_element_to_last(&ses->acls, acl, acl, avl)
-		{
-			if (!strcmp(acl->function, function))
-				return 1;
-		}
-	}
-
-	nacl = malloc(sizeof(*nacl) + strlen(object) + strlen(function) + 2);
-
-	if (nacl)
-	{
-		memset(nacl, 0, sizeof(*nacl));
-		nacl->function = nacl->object + 1;
-		nacl->function += sprintf(nacl->object, "%s", object);
-		sprintf(nacl->function, "%s", function);
-
-		nacl->avl.key = nacl->object;
-		avl_insert(&ses->acls, &nacl->avl);
-	}
-
-	return 0;
-}
-
-static int
-uh_ubus_session_revoke(struct uh_ubus_session *ses, struct ubus_context *ctx,
-					   const char *object, const char *function)
-{
-	struct uh_ubus_session_acl *acl, *nacl;
-
-	if (!object && !function)
-	{
-		avl_remove_all_elements(&ses->acls, acl, avl, nacl)
-			free(acl);
-	}
-	else
-	{
-		avl_for_each_element_safe(&ses->acls, acl, avl, nacl)
-		{
-			if (uh_ubus_strmatch(acl->object, object) &&
-				uh_ubus_strmatch(acl->function, function))
-			{
-				avl_delete(&ses->acls, &acl->avl);
-				free(acl);
-			}
-		}
-	}
-
-	return 0;
-}
-
-
-static int
-uh_ubus_handle_grant(struct ubus_context *ctx, struct ubus_object *obj,
-					 struct ubus_request_data *req, const char *method,
-					 struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct blob_attr *tb[__UH_UBUS_SA_MAX];
-	struct blob_attr *attr, *sattr;
-	const char *object, *function;
-	int rem1, rem2;
-
-	blobmsg_parse(acl_policy, __UH_UBUS_SA_MAX, tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[UH_UBUS_SA_SID] || !tb[UH_UBUS_SA_OBJECTS])
-		return UBUS_STATUS_INVALID_ARGUMENT;
-
-	ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SA_SID]));
-
-	if (!ses)
-		return UBUS_STATUS_NOT_FOUND;
-
-	blobmsg_for_each_attr(attr, tb[UH_UBUS_SA_OBJECTS], rem1)
-	{
-		if (blob_id(attr) != BLOBMSG_TYPE_ARRAY)
-			continue;
-
-		object = NULL;
-		function = NULL;
-
-		blobmsg_for_each_attr(sattr, attr, rem2)
-		{
-			if (blob_id(sattr) != BLOBMSG_TYPE_STRING)
-				continue;
-
-			if (!object)
-				object = blobmsg_data(sattr);
-			else if (!function)
-				function = blobmsg_data(sattr);
-			else
-				break;
-		}
-
-		if (object && function)
-			uh_ubus_session_grant(ses, ctx, object, function);
-	}
-
-	return 0;
-}
-
-static int
-uh_ubus_handle_revoke(struct ubus_context *ctx, struct ubus_object *obj,
-					  struct ubus_request_data *req, const char *method,
-					  struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct blob_attr *tb[__UH_UBUS_SA_MAX];
-	struct blob_attr *attr, *sattr;
-	const char *object, *function;
-	int rem1, rem2;
-
-	blobmsg_parse(acl_policy, __UH_UBUS_SA_MAX, tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[UH_UBUS_SA_SID])
-		return UBUS_STATUS_INVALID_ARGUMENT;
-
-	ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SA_SID]));
-
-	if (!ses)
-		return UBUS_STATUS_NOT_FOUND;
-
-	if (!tb[UH_UBUS_SA_OBJECTS])
-	{
-		uh_ubus_session_revoke(ses, ctx, NULL, NULL);
-	}
-	else
-	{
-		blobmsg_for_each_attr(attr, tb[UH_UBUS_SA_OBJECTS], rem1)
-		{
-			if (blob_id(attr) != BLOBMSG_TYPE_ARRAY)
-				continue;
-
-			object = NULL;
-			function = NULL;
-
-			blobmsg_for_each_attr(sattr, attr, rem2)
-			{
-				if (blob_id(sattr) != BLOBMSG_TYPE_STRING)
-					continue;
-
-				if (!object)
-					object = blobmsg_data(sattr);
-				else if (!function)
-					function = blobmsg_data(sattr);
-				else
-					break;
-			}
-
-			if (object && function)
-				uh_ubus_session_revoke(ses, ctx, object, function);
-		}
-	}
-
-	return 0;
-}
-
-static int
-uh_ubus_handle_set(struct ubus_context *ctx, struct ubus_object *obj,
-				   struct ubus_request_data *req, const char *method,
-				   struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct uh_ubus_session_data *data;
-	struct blob_attr *tb[__UH_UBUS_SA_MAX];
-	struct blob_attr *attr;
-	int rem;
-
-	blobmsg_parse(set_policy, __UH_UBUS_SS_MAX, tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[UH_UBUS_SS_SID] || !tb[UH_UBUS_SS_VALUES])
-		return UBUS_STATUS_INVALID_ARGUMENT;
-
-	ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SS_SID]));
-
-	if (!ses)
-		return UBUS_STATUS_NOT_FOUND;
-
-	blobmsg_for_each_attr(attr, tb[UH_UBUS_SS_VALUES], rem)
-	{
-		if (!blobmsg_name(attr)[0])
-			continue;
-
-		data = avl_find_element(&ses->data, blobmsg_name(attr), data, avl);
-
-		if (data)
-		{
-			avl_delete(&ses->data, &data->avl);
-			free(data);
-		}
-
-		data = malloc(sizeof(*data) + blob_pad_len(attr));
-
-		if (!data)
-			break;
-
-		memset(data, 0, sizeof(*data) + blob_pad_len(attr));
-		memcpy(data->attr, attr, blob_pad_len(attr));
-
-		data->avl.key = blobmsg_name(data->attr);
-		avl_insert(&ses->data, &data->avl);
-	}
-
-	return 0;
-}
-
-static int
-uh_ubus_handle_get(struct ubus_context *ctx, struct ubus_object *obj,
-				   struct ubus_request_data *req, const char *method,
-				   struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct uh_ubus_session_data *data;
-	struct blob_attr *tb[__UH_UBUS_SA_MAX];
-	struct blob_attr *attr;
-	struct blob_buf b;
-	void *c;
-	int rem;
-
-	blobmsg_parse(get_policy, __UH_UBUS_SG_MAX, tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[UH_UBUS_SG_SID])
-		return UBUS_STATUS_INVALID_ARGUMENT;
-
-	ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SG_SID]));
-
-	if (!ses)
-		return UBUS_STATUS_NOT_FOUND;
-
-	memset(&b, 0, sizeof(b));
-	blob_buf_init(&b, 0);
-	c = blobmsg_open_table(&b, "values");
-
-	if (!tb[UH_UBUS_SG_KEYS])
-	{
-		uh_ubus_session_dump_data(ses, &b);
-	}
-	else
-	{
-		blobmsg_for_each_attr(attr, tb[UH_UBUS_SG_KEYS], rem)
-		{
-			if (blob_id(attr) != BLOBMSG_TYPE_STRING)
-				continue;
-
-			data = avl_find_element(&ses->data, blobmsg_data(attr), data, avl);
-
-			if (!data)
-				continue;
-
-			blobmsg_add_field(&b, blobmsg_type(data->attr),
-							  blobmsg_name(data->attr),
-							  blobmsg_data(data->attr),
-							  blobmsg_data_len(data->attr));
-		}
-	}
-
-	blobmsg_close_table(&b, c);
-	ubus_send_reply(ctx, req, b.head);
-	blob_buf_free(&b);
-
-	return 0;
-}
-
-static int
-uh_ubus_handle_unset(struct ubus_context *ctx, struct ubus_object *obj,
-				     struct ubus_request_data *req, const char *method,
-				     struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct uh_ubus_session_data *data, *ndata;
-	struct blob_attr *tb[__UH_UBUS_SA_MAX];
-	struct blob_attr *attr;
-	int rem;
-
-	blobmsg_parse(get_policy, __UH_UBUS_SG_MAX, tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[UH_UBUS_SG_SID])
-		return UBUS_STATUS_INVALID_ARGUMENT;
-
-	ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SG_SID]));
-
-	if (!ses)
-		return UBUS_STATUS_NOT_FOUND;
-
-	if (!tb[UH_UBUS_SG_KEYS])
-	{
-		avl_remove_all_elements(&ses->data, data, avl, ndata)
-			free(data);
-	}
-	else
-	{
-		blobmsg_for_each_attr(attr, tb[UH_UBUS_SG_KEYS], rem)
-		{
-			if (blob_id(attr) != BLOBMSG_TYPE_STRING)
-				continue;
-
-			data = avl_find_element(&ses->data, blobmsg_data(attr), data, avl);
-
-			if (!data)
-				continue;
-
-			avl_delete(&ses->data, &data->avl);
-			free(data);
-		}
-	}
-
-	return 0;
-}
-
-static int
-uh_ubus_handle_destroy(struct ubus_context *ctx, struct ubus_object *obj,
-					   struct ubus_request_data *req, const char *method,
-					   struct blob_attr *msg)
-{
-	struct uh_ubus_state *state = container_of(obj, struct uh_ubus_state, ubus);
-	struct uh_ubus_session *ses;
-	struct blob_attr *tb[__UH_UBUS_SA_MAX];
-
-	blobmsg_parse(sid_policy, __UH_UBUS_SI_MAX, tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[UH_UBUS_SI_SID])
-		return UBUS_STATUS_INVALID_ARGUMENT;
-
-	ses = uh_ubus_session_get(state, blobmsg_data(tb[UH_UBUS_SI_SID]));
-
-	if (!ses)
-		return UBUS_STATUS_NOT_FOUND;
-
-	uh_ubus_session_destroy(state, ses);
-
-	return 0;
-}
-
-
-struct uh_ubus_state *
-uh_ubus_init(const struct config *conf)
-{
-	int rv;
-	struct uh_ubus_state *state;
-	struct ubus_object *session_object;
-
-	static struct ubus_method session_methods[] = {
-		UBUS_METHOD("create",  uh_ubus_handle_create,  new_policy),
-		UBUS_METHOD("list",    uh_ubus_handle_list,    sid_policy),
-		UBUS_METHOD("grant",   uh_ubus_handle_grant,   acl_policy),
-		UBUS_METHOD("revoke",  uh_ubus_handle_revoke,  acl_policy),
-		UBUS_METHOD("set",     uh_ubus_handle_set,     set_policy),
-		UBUS_METHOD("get",     uh_ubus_handle_get,     get_policy),
-		UBUS_METHOD("unset",   uh_ubus_handle_unset,   get_policy),
-		UBUS_METHOD("destroy", uh_ubus_handle_destroy, sid_policy),
-	};
-
-	static struct ubus_object_type session_type =
-		UBUS_OBJECT_TYPE("uhttpd", session_methods);
-
-	state = malloc(sizeof(*state));
-
-	if (!state)
-	{
-		fprintf(stderr, "Unable to allocate memory for ubus state\n");
-		exit(1);
-	}
-
-	memset(state, 0, sizeof(*state));
-	state->ctx = ubus_connect(conf->ubus_socket);
-	state->timeout = conf->script_timeout;
-
-	if (!state->ctx)
-	{
-		fprintf(stderr, "Unable to connect to ubus socket\n");
-		exit(1);
-	}
-
-	ubus_add_uloop(state->ctx);
-
-	session_object = &state->ubus;
-	session_object->name = "session";
-	session_object->type = &session_type;
-	session_object->methods = session_methods;
-	session_object->n_methods = ARRAY_SIZE(session_methods);
-
-	rv = ubus_add_object(state->ctx, &state->ubus);
-
-	if (rv)
-	{
-		fprintf(stderr, "Unable to publish ubus object: %s\n",
-				ubus_strerror(rv));
-		exit(1);
-	}
-
-	blob_buf_init(&state->buf, 0);
-	avl_init(&state->sessions, uh_ubus_avlcmp, false, NULL);
-
-	return state;
-}
-
-
-static bool
-uh_ubus_request_parse_url(struct client *cl, char **sid, char **obj, char **fun)
-{
-	char *url = cl->request.url + strlen(cl->server->conf->ubus_prefix);
-
-	for (; url && *url == '/'; *url++ = 0);
-	*sid = url;
-
-	for (url = url ? strchr(url, '/') : NULL; url && *url == '/'; *url++ = 0);
-	*obj = url;
-
-	for (url = url ? strchr(url, '/') : NULL; url && *url == '/'; *url++ = 0);
-	*fun = url;
-
-	for (url = url ? strchr(url, '/') : NULL; url && *url == '/'; *url++ = 0);
-	return (*sid && *obj && *fun);
-}
-
-static bool
-uh_ubus_request_parse_post(struct client *cl, int len, struct blob_buf *b)
-{
-	int rlen;
-	bool rv = false;
-	char buf[UH_LIMIT_MSGHEAD];
-
-	struct json_object *obj = NULL;
-	struct json_tokener *tok = NULL;
-
-	if (!len)
-		return NULL;
-
-	memset(b, 0, sizeof(*b));
-	blob_buf_init(b, 0);
-
-	tok = json_tokener_new();
-
-	while (len > 0)
-	{
-		/* remaining data in http head buffer ... */
-		if (cl->httpbuf.len > 0)
-		{
-			rlen = min(len, cl->httpbuf.len);
-
-			D("ubus: feed %d HTTP buffer bytes\n", rlen);
-
-			memcpy(buf, cl->httpbuf.ptr, rlen);
-
-			cl->httpbuf.len -= rlen;
-			cl->httpbuf.ptr += rlen;
-		}
-
-		/* read it from socket ... */
-		else
-		{
-			ensure_out(rlen = uh_tcp_recv(cl, buf, min(len, sizeof(buf))));
-
-			if ((rlen < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
-				break;
-
-			D("ubus: feed %d/%d TCP socket bytes\n",
-			  rlen, min(len, sizeof(buf)));
-		}
-
-		obj = json_tokener_parse_ex(tok, buf, rlen);
-		len -= rlen;
-
-		if (tok->err != json_tokener_continue && !is_error(obj))
-			break;
-	}
-
-out:
-	if (!is_error(obj))
-	{
-		if (json_object_get_type(obj) == json_type_object)
-		{
-			rv = true;
-			json_object_object_foreach(obj, key, val)
-			{
-				if (!blobmsg_add_json_element(b, key, val))
-				{
-					rv = false;
-					break;
-				}
-			}
-		}
-
-		json_object_put(obj);
-	}
-
-	json_tokener_free(tok);
-
-	if (!rv)
-		blob_buf_free(b);
-
-	return rv;
-}
-
-static void
-uh_ubus_request_cb(struct ubus_request *req, int type, struct blob_attr *msg)
-{
-	int len;
-	char *str;
-	struct client *cl = (struct client *)req->priv;
-
-	if (!msg)
-	{
-		uh_http_sendhf(cl, 204, "No content", "Function did not return data\n");
-		return;
-	}
-
-	str = blobmsg_format_json_indent(msg, true, 0);
-	len = strlen(str);
-
-	ensure_out(uh_http_sendf(cl, NULL, "HTTP/1.0 200 OK\r\n"));
-	ensure_out(uh_http_sendf(cl, NULL, "Content-Type: application/json\r\n"));
-	ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n\r\n", len));
-	ensure_out(uh_http_send(cl, NULL, str, len));
-
-out:
-	free(str);
-}
-
-bool
-uh_ubus_request(struct client *cl, struct uh_ubus_state *state)
-{
-	int i, len = 0;
-	bool access = false;
-	char *sid, *obj, *fun;
-
-	struct blob_buf buf;
-	struct uh_ubus_session *ses;
-	struct uh_ubus_session_acl *acl;
-
-	uint32_t obj_id;
-
-
-	memset(&buf, 0, sizeof(buf));
-	blob_buf_init(&buf, 0);
-
-	if (!uh_ubus_request_parse_url(cl, &sid, &obj, &fun))
-	{
-		uh_http_sendhf(cl, 400, "Bad Request", "Invalid Request\n");
-		goto out;
-	}
-
-	if (!(ses = uh_ubus_session_get(state, sid)))
-	{
-		uh_http_sendhf(cl, 404, "Not Found", "No such session\n");
-		goto out;
-	}
-
-	avl_for_each_element(&ses->acls, acl, avl)
-	{
-		if (uh_ubus_strmatch(obj, acl->object) &&
-			uh_ubus_strmatch(fun, acl->function))
-		{
-			access = true;
-			break;
-		}
-	}
-
-	if (!access)
-	{
-		uh_http_sendhf(cl, 403, "Denied", "Access to object denied\n");
-		goto out;
-	}
-
-	/* find content length */
-	if (cl->request.method == UH_HTTP_MSG_POST)
-	{
-		foreach_header(i, cl->request.headers)
-		{
-			if (!strcasecmp(cl->request.headers[i], "Content-Length"))
-			{
-				len = atoi(cl->request.headers[i+1]);
-				break;
-			}
-		}
-	}
-
-	if (len > UH_UBUS_MAX_POST_SIZE)
-	{
-		uh_http_sendhf(cl, 413, "Too Large", "Message too big\n");
-		goto out;
-	}
-
-	if (len && !uh_ubus_request_parse_post(cl, len, &buf))
-	{
-		uh_http_sendhf(cl, 400, "Bad Request", "Invalid JSON data\n");
-		goto out;
-	}
-
-	if (ubus_lookup_id(state->ctx, obj, &obj_id))
-	{
-		uh_http_sendhf(cl, 500, "Internal Error", "Unable to lookup object\n");
-		goto out;
-	}
-
-	if (ubus_invoke(state->ctx, obj_id, fun, buf.head,
-					uh_ubus_request_cb, cl, state->timeout * 1000))
-	{
-		uh_http_sendhf(cl, 500, "Internal Error", "Unable to invoke function\n");
-		goto out;
-	}
-
-out:
-	blob_buf_free(&buf);
-	return false;
-}
-
-void
-uh_ubus_close(struct uh_ubus_state *state)
-{
-	if (state->ctx)
-		ubus_free(state->ctx);
-
-	free(state);
-}

+ 0 - 70
package/network/services/uhttpd/src/uhttpd-ubus.h

@@ -1,70 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - ubus header
- *
- *   Copyright (C) 2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_UBUS_
-
-#include <time.h>
-
-#include <libubus.h>
-#include <libubox/avl.h>
-#include <libubox/blobmsg_json.h>
-#include <json/json.h>
-
-
-#define UH_UBUS_MAX_POST_SIZE	4096
-
-
-struct uh_ubus_state {
-	struct ubus_context *ctx;
-	struct ubus_object ubus;
-	struct blob_buf buf;
-	struct avl_tree sessions;
-	int timeout;
-};
-
-struct uh_ubus_request_data {
-	const char *sid;
-	const char *object;
-	const char *function;
-};
-
-struct uh_ubus_session {
-	char id[33];
-	int timeout;
-	struct avl_node avl;
-	struct avl_tree data;
-	struct avl_tree acls;
-	struct timespec touched;
-};
-
-struct uh_ubus_session_data {
-	struct avl_node avl;
-	struct blob_attr attr[];
-};
-
-struct uh_ubus_session_acl {
-	struct avl_node avl;
-	char *function;
-	char object[];
-};
-
-struct uh_ubus_state * uh_ubus_init(const struct config *conf);
-bool uh_ubus_request(struct client *cl, struct uh_ubus_state *state);
-void uh_ubus_close(struct uh_ubus_state *state);
-
-#endif

+ 0 - 1081
package/network/services/uhttpd/src/uhttpd-utils.c

@@ -1,1081 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Utility functions
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#define _XOPEN_SOURCE 500	/* crypt() */
-#define _BSD_SOURCE			/* strcasecmp(), strncasecmp() */
-
-#include "uhttpd.h"
-#include "uhttpd-utils.h"
-
-#ifdef HAVE_TLS
-#include "uhttpd-tls.h"
-#endif
-
-
-static char *uh_index_files[] = {
-	"index.html",
-	"index.htm",
-	"default.html",
-	"default.htm"
-};
-
-
-const char * sa_straddr(void *sa)
-{
-	static char str[INET6_ADDRSTRLEN];
-	struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
-	struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)sa;
-
-	if (v4->sin_family == AF_INET)
-		return inet_ntop(AF_INET, &(v4->sin_addr), str, sizeof(str));
-	else
-		return inet_ntop(AF_INET6, &(v6->sin6_addr), str, sizeof(str));
-}
-
-const char * sa_strport(void *sa)
-{
-	static char str[6];
-	snprintf(str, sizeof(str), "%i", sa_port(sa));
-	return str;
-}
-
-int sa_port(void *sa)
-{
-	return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
-}
-
-int sa_rfc1918(void *sa)
-{
-	struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
-	unsigned long a = htonl(v4->sin_addr.s_addr);
-
-	if (v4->sin_family == AF_INET)
-	{
-		return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
-		       ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
-		       ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
-	}
-
-	return 0;
-}
-
-/* Simple strstr() like function that takes len arguments for both haystack and needle. */
-char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
-{
-	int match = 0;
-	int i, j;
-
-	for (i = 0; i < hslen; i++)
-	{
-		if (haystack[i] == needle[0])
-		{
-			match = ((ndlen == 1) || ((i + ndlen) <= hslen));
-
-			for (j = 1; (j < ndlen) && ((i + j) < hslen); j++)
-			{
-				if (haystack[i+j] != needle[j])
-				{
-					match = 0;
-					break;
-				}
-			}
-
-			if (match)
-				return &haystack[i];
-		}
-	}
-
-	return NULL;
-}
-
-bool uh_socket_wait(int fd, int sec, bool write)
-{
-	int rv;
-	struct timeval timeout;
-
-	fd_set fds;
-
-	FD_ZERO(&fds);
-	FD_SET(fd, &fds);
-
-	timeout.tv_sec = sec;
-	timeout.tv_usec = 0;
-
-	while (((rv = select(fd+1, write ? NULL : &fds, write ? &fds : NULL,
-						 NULL, &timeout)) < 0) && (errno == EINTR))
-	{
-		D("IO: FD(%d) select interrupted: %s\n",
-				fd, strerror(errno));
-
-		continue;
-	}
-
-	if (rv <= 0)
-	{
-		D("IO: FD(%d) appears dead (rv=%d)\n", fd, rv);
-		return false;
-	}
-
-	return true;
-}
-
-static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec,
-						 int (*wfn) (struct client *, const char *, int))
-{
-	ssize_t rv;
-	int fd = cl->fd.fd;
-
-	while (true)
-	{
-		if ((rv = wfn(cl, buf, len)) < 0)
-		{
-			if (errno == EINTR)
-			{
-				D("IO: FD(%d) interrupted\n", cl->fd.fd);
-				continue;
-			}
-			else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
-			{
-				if (!uh_socket_wait(fd, sec, true))
-					return -1;
-			}
-			else
-			{
-				D("IO: FD(%d) write error: %s\n", fd, strerror(errno));
-				return -1;
-			}
-		}
-		/*
-		 * It is not entirely clear whether rv = 0 on nonblocking sockets
-		 * is an error. In real world fuzzing tests, not handling it as close
-		 * led to tight infinite loops in this send procedure, so treat it as
-		 * closed and break out.
-		 */
-		else if (rv == 0)
-		{
-			D("IO: FD(%d) appears closed\n", fd);
-			return 0;
-		}
-		else if (rv < len)
-		{
-			D("IO: FD(%d) short write %d/%d bytes\n", fd, rv, len);
-			len -= rv;
-			buf += rv;
-			continue;
-		}
-		else
-		{
-			D("IO: FD(%d) sent %d/%d bytes\n", fd, rv, len);
-			return rv;
-		}
-	}
-}
-
-int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len)
-{
-	return write(cl->fd.fd, buf, len);
-}
-
-int uh_raw_send(int fd, const char *buf, int len, int sec)
-{
-	struct client_light cl = { .fd = { .fd = fd } };
-	return __uh_raw_send((struct client *)&cl, buf, len, sec,
-						 uh_tcp_send_lowlevel);
-}
-
-int uh_tcp_send(struct client *cl, const char *buf, int len)
-{
-	int seconds = cl->server->conf->network_timeout;
-#ifdef HAVE_TLS
-	if (cl->tls)
-		return __uh_raw_send(cl, buf, len, seconds,
-							 cl->server->conf->tls_send);
-#endif
-	return __uh_raw_send(cl, buf, len, seconds, uh_tcp_send_lowlevel);
-}
-
-static int __uh_raw_recv(struct client *cl, char *buf, int len, int sec,
-						 int (*rfn) (struct client *, char *, int))
-{
-	ssize_t rv;
-	int fd = cl->fd.fd;
-
-	while (true)
-	{
-		if ((rv = rfn(cl, buf, len)) < 0)
-		{
-			if (errno == EINTR)
-			{
-				continue;
-			}
-			else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
-			{
-				if (!uh_socket_wait(fd, sec, false))
-					return -1;
-			}
-			else
-			{
-				D("IO: FD(%d) read error: %s\n", fd, strerror(errno));
-				return -1;
-			}
-		}
-		else if (rv == 0)
-		{
-			D("IO: FD(%d) appears closed\n", fd);
-			return 0;
-		}
-		else
-		{
-			D("IO: FD(%d) read %d bytes\n", fd, rv);
-			return rv;
-		}
-	}
-}
-
-int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
-{
-	return read(cl->fd.fd, buf, len);
-}
-
-int uh_raw_recv(int fd, char *buf, int len, int sec)
-{
-	struct client_light cl = { .fd = { .fd = fd } };
-	return __uh_raw_recv((struct client *)&cl, buf, len, sec,
-						 uh_tcp_recv_lowlevel);
-}
-
-int uh_tcp_recv(struct client *cl, char *buf, int len)
-{
-	int seconds = cl->server->conf->network_timeout;
-#ifdef HAVE_TLS
-	if (cl->tls)
-		return __uh_raw_recv(cl, buf, len, seconds,
-							 cl->server->conf->tls_recv);
-#endif
-	return __uh_raw_recv(cl, buf, len, seconds, uh_tcp_recv_lowlevel);
-}
-
-
-int uh_http_sendhf(struct client *cl, int code, const char *summary,
-				   const char *fmt, ...)
-{
-	va_list ap;
-
-	char buffer[UH_LIMIT_MSGHEAD];
-	int len;
-
-	len = snprintf(buffer, sizeof(buffer),
-		"HTTP/1.1 %03i %s\r\n"
-		"Connection: close\r\n"
-		"Content-Type: text/plain\r\n"
-		"Transfer-Encoding: chunked\r\n\r\n",
-			code, summary
-	);
-
-	ensure_ret(uh_tcp_send(cl, buffer, len));
-
-	va_start(ap, fmt);
-	len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
-	va_end(ap);
-
-	ensure_ret(uh_http_sendc(cl, buffer, len));
-	ensure_ret(uh_http_sendc(cl, NULL, 0));
-
-	return 0;
-}
-
-
-int uh_http_sendc(struct client *cl, const char *data, int len)
-{
-	char chunk[8];
-	int clen;
-
-	if (len == -1)
-		len = strlen(data);
-
-	if (len > 0)
-	{
-		clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
-		ensure_ret(uh_tcp_send(cl, chunk, clen));
-		ensure_ret(uh_tcp_send(cl, data, len));
-		ensure_ret(uh_tcp_send(cl, "\r\n", 2));
-	}
-	else
-	{
-		ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5));
-	}
-
-	return 0;
-}
-
-int uh_http_sendf(struct client *cl, struct http_request *req,
-				  const char *fmt, ...)
-{
-	va_list ap;
-	char buffer[UH_LIMIT_MSGHEAD];
-	int len;
-
-	va_start(ap, fmt);
-	len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
-	va_end(ap);
-
-	if ((req != NULL) && (req->version > UH_HTTP_VER_1_0))
-		ensure_ret(uh_http_sendc(cl, buffer, len));
-	else if (len > 0)
-		ensure_ret(uh_tcp_send(cl, buffer, len));
-
-	return 0;
-}
-
-int uh_http_send(struct client *cl, struct http_request *req,
-				 const char *buf, int len)
-{
-	if (len < 0)
-		len = strlen(buf);
-
-	if ((req != NULL) && (req->version > UH_HTTP_VER_1_0))
-		ensure_ret(uh_http_sendc(cl, buf, len));
-	else if (len > 0)
-		ensure_ret(uh_tcp_send(cl, buf, len));
-
-	return 0;
-}
-
-
-/* blen is the size of buf; slen is the length of src.  The input-string need
-** not be, and the output string will not be, null-terminated.  Returns the
-** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
-int uh_urldecode(char *buf, int blen, const char *src, int slen)
-{
-	int i;
-	int len = 0;
-
-#define hex(x) \
-	(((x) <= '9') ? ((x) - '0') : \
-		(((x) <= 'F') ? ((x) - 'A' + 10) : \
-			((x) - 'a' + 10)))
-
-	for (i = 0; (i < slen) && (len < blen); i++)
-	{
-		if (src[i] == '%')
-		{
-			if (((i+2) < slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]))
-			{
-				buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
-				i += 2;
-			}
-			else
-			{
-				/* Encoding error: it's hard to think of a
-				** scenario in which returning an incorrect
-				** 'decoding' of the malformed string is
-				** preferable to signaling an error condition. */
-				#if 0 /* WORSE_IS_BETTER */
-				    buf[len++] = '%';
-				#else
-				    return -2;
-				#endif
-			}
-		}
-		else
-		{
-			buf[len++] = src[i];
-		}
-	}
-
-	return (i == slen) ? len : -1;
-}
-
-/* blen is the size of buf; slen is the length of src.  The input-string need
-** not be, and the output string will not be, null-terminated.  Returns the
-** length of the encoded string, or -1 on error (buffer overflow) */
-int uh_urlencode(char *buf, int blen, const char *src, int slen)
-{
-	int i;
-	int len = 0;
-	const char hex[] = "0123456789abcdef";
-
-	for (i = 0; (i < slen) && (len < blen); i++)
-	{
-		if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
-		    (src[i] == '.') || (src[i] == '~') )
-		{
-			buf[len++] = src[i];
-		}
-		else if ((len+3) <= blen)
-		{
-			buf[len++] = '%';
-			buf[len++] = hex[(src[i] >> 4) & 15];
-			buf[len++] = hex[ src[i]       & 15];
-		}
-		else
-		{
-			len = -1;
-			break;
-		}
-	}
-
-	return (i == slen) ? len : -1;
-}
-
-int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
-{
-	int i = 0;
-	int len = 0;
-
-	unsigned int cin  = 0;
-	unsigned int cout = 0;
-
-
-	for (i = 0; (i <= slen) && (src[i] != 0); i++)
-	{
-		cin = src[i];
-
-		if ((cin >= '0') && (cin <= '9'))
-			cin = cin - '0' + 52;
-		else if ((cin >= 'A') && (cin <= 'Z'))
-			cin = cin - 'A';
-		else if ((cin >= 'a') && (cin <= 'z'))
-			cin = cin - 'a' + 26;
-		else if (cin == '+')
-			cin = 62;
-		else if (cin == '/')
-			cin = 63;
-		else if (cin == '=')
-			cin = 0;
-		else
-			continue;
-
-		cout = (cout << 6) | cin;
-
-		if ((i % 4) == 3)
-		{
-			if ((len + 3) < blen)
-			{
-				buf[len++] = (char)(cout >> 16);
-				buf[len++] = (char)(cout >> 8);
-				buf[len++] = (char)(cout);
-			}
-			else
-			{
-				break;
-			}
-		}
-	}
-
-	buf[len++] = 0;
-	return len;
-}
-
-static char * canonpath(const char *path, char *path_resolved)
-{
-	char path_copy[PATH_MAX];
-	char *path_cpy = path_copy;
-	char *path_res = path_resolved;
-
-	struct stat s;
-
-
-	/* relative -> absolute */
-	if (*path != '/')
-	{
-		getcwd(path_copy, PATH_MAX);
-		strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
-		strncat(path_copy, path, PATH_MAX - strlen(path_copy));
-	}
-	else
-	{
-		strncpy(path_copy, path, PATH_MAX);
-	}
-
-	/* normalize */
-	while ((*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)))
-	{
-		if (*path_cpy == '/')
-		{
-			/* skip repeating / */
-			if (path_cpy[1] == '/')
-			{
-				path_cpy++;
-				continue;
-			}
-
-			/* /./ or /../ */
-			else if (path_cpy[1] == '.')
-			{
-				/* skip /./ */
-				if ((path_cpy[2] == '/') || (path_cpy[2] == '\0'))
-				{
-					path_cpy += 2;
-					continue;
-				}
-
-				/* collapse /x/../ */
-				else if ((path_cpy[2] == '.') &&
-						 ((path_cpy[3] == '/') || (path_cpy[3] == '\0')))
-				{
-					while ((path_res > path_resolved) && (*--path_res != '/'))
-						;
-
-					path_cpy += 3;
-					continue;
-				}
-			}
-		}
-
-		*path_res++ = *path_cpy++;
-	}
-
-	/* remove trailing slash if not root / */
-	if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
-		path_res--;
-	else if (path_res == path_resolved)
-		*path_res++ = '/';
-
-	*path_res = '\0';
-
-	/* test access */
-	if (!stat(path_resolved, &s) && (s.st_mode & S_IROTH))
-		return path_resolved;
-
-	return NULL;
-}
-
-/* Returns NULL on error.
-** NB: improperly encoded URL should give client 400 [Bad Syntax]; returning
-** NULL here causes 404 [Not Found], but that's not too unreasonable. */
-struct path_info * uh_path_lookup(struct client *cl, const char *url)
-{
-	static char path_phys[PATH_MAX];
-	static char path_info[PATH_MAX];
-	static struct path_info p;
-
-	char buffer[UH_LIMIT_MSGHEAD];
-	char *docroot = cl->server->conf->docroot;
-	char *pathptr = NULL;
-
-	int slash = 0;
-	int no_sym = cl->server->conf->no_symlinks;
-	int i = 0;
-	struct stat s;
-
-	/* back out early if url is undefined */
-	if (url == NULL)
-		return NULL;
-
-	memset(path_phys, 0, sizeof(path_phys));
-	memset(path_info, 0, sizeof(path_info));
-	memset(buffer, 0, sizeof(buffer));
-	memset(&p, 0, sizeof(p));
-
-	/* copy docroot */
-	memcpy(buffer, docroot,
-		   min(strlen(docroot), sizeof(buffer) - 1));
-
-	/* separate query string from url */
-	if ((pathptr = strchr(url, '?')) != NULL)
-	{
-		p.query = pathptr[1] ? pathptr + 1 : NULL;
-
-		/* urldecode component w/o query */
-		if (pathptr > url)
-		{
-			if (uh_urldecode(&buffer[strlen(docroot)],
-							 sizeof(buffer) - strlen(docroot) - 1,
-							 url, pathptr - url ) < 0)
-			{
-				return NULL; /* bad URL */
-			}
-		}
-	}
-
-	/* no query string, decode all of url */
-	else
-	{
-		if (uh_urldecode(&buffer[strlen(docroot)],
-						 sizeof(buffer) - strlen(docroot) - 1,
-						 url, strlen(url) ) < 0)
-		{
-			return NULL; /* bad URL */
-		}
-	}
-
-	/* create canon path */
-	for (i = strlen(buffer), slash = (buffer[max(0, i-1)] == '/'); i >= 0; i--)
-	{
-		if ((buffer[i] == 0) || (buffer[i] == '/'))
-		{
-			memset(path_info, 0, sizeof(path_info));
-			memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
-
-			if (no_sym ? realpath(path_info, path_phys)
-			           : canonpath(path_info, path_phys))
-			{
-				memset(path_info, 0, sizeof(path_info));
-				memcpy(path_info, &buffer[i],
-					   min(strlen(buffer) - i, sizeof(path_info) - 1));
-
-				break;
-			}
-		}
-	}
-
-	/* check whether found path is within docroot */
-	if (strncmp(path_phys, docroot, strlen(docroot)) ||
-		((path_phys[strlen(docroot)] != 0) &&
-		 (path_phys[strlen(docroot)] != '/')))
-	{
-		return NULL;
-	}
-
-	/* test current path */
-	if (!stat(path_phys, &p.stat))
-	{
-		/* is a regular file */
-		if (p.stat.st_mode & S_IFREG)
-		{
-			p.root = docroot;
-			p.phys = path_phys;
-			p.name = &path_phys[strlen(docroot)];
-			p.info = path_info[0] ? path_info : NULL;
-		}
-
-		/* is a directory */
-		else if ((p.stat.st_mode & S_IFDIR) && !strlen(path_info))
-		{
-			/* ensure trailing slash */
-			if (path_phys[strlen(path_phys)-1] != '/')
-				path_phys[strlen(path_phys)] = '/';
-
-			/* try to locate index file */
-			memset(buffer, 0, sizeof(buffer));
-			memcpy(buffer, path_phys, sizeof(buffer));
-			pathptr = &buffer[strlen(buffer)];
-
-			/* if requested url resolves to a directory and a trailing slash
-			   is missing in the request url, redirect the client to the same
-			   url with trailing slash appended */
-			if (!slash)
-			{
-				uh_http_sendf(cl, NULL,
-					"HTTP/1.1 302 Found\r\n"
-					"Location: %s%s%s\r\n"
-					"Connection: close\r\n\r\n",
-						&path_phys[strlen(docroot)],
-						p.query ? "?" : "",
-						p.query ? p.query : ""
-				);
-
-				p.redirected = 1;
-			}
-			else if (cl->server->conf->index_file)
-			{
-				strncat(buffer, cl->server->conf->index_file, sizeof(buffer));
-
-				if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
-				{
-					memcpy(path_phys, buffer, sizeof(path_phys));
-					memcpy(&p.stat, &s, sizeof(p.stat));
-				}
-			}
-			else
-			{
-				for (i = 0; i < array_size(uh_index_files); i++)
-				{
-					strncat(buffer, uh_index_files[i], sizeof(buffer));
-
-					if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
-					{
-						memcpy(path_phys, buffer, sizeof(path_phys));
-						memcpy(&p.stat, &s, sizeof(p.stat));
-						break;
-					}
-
-					*pathptr = 0;
-				}
-			}
-
-			p.root = docroot;
-			p.phys = path_phys;
-			p.name = &path_phys[strlen(docroot)];
-		}
-	}
-
-	return p.phys ? &p : NULL;
-}
-
-
-static struct auth_realm *uh_realms = NULL;
-
-struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
-{
-	struct auth_realm *new = NULL;
-	struct passwd *pwd;
-
-#ifdef HAVE_SHADOW
-	struct spwd *spwd;
-#endif
-
-	if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)
-	{
-		memset(new, 0, sizeof(struct auth_realm));
-
-		memcpy(new->path, path,
-			   min(strlen(path), sizeof(new->path) - 1));
-
-		memcpy(new->user, user,
-			   min(strlen(user), sizeof(new->user) - 1));
-
-		/* given password refers to a passwd entry */
-		if ((strlen(pass) > 3) && !strncmp(pass, "$p$", 3))
-		{
-#ifdef HAVE_SHADOW
-			/* try to resolve shadow entry */
-			if (((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp)
-			{
-				memcpy(new->pass, spwd->sp_pwdp,
-					   min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1));
-			}
-
-			else
-#endif
-
-			/* try to resolve passwd entry */
-			if (((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd &&
-				(pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0))
-			{
-				memcpy(new->pass, pwd->pw_passwd,
-					   min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
-			}
-		}
-
-		/* ordinary pwd */
-		else
-		{
-			memcpy(new->pass, pass,
-				min(strlen(pass), sizeof(new->pass) - 1));
-		}
-
-		if (new->pass[0])
-		{
-			new->next = uh_realms;
-			uh_realms = new;
-
-			return new;
-		}
-
-		free(new);
-	}
-
-	return NULL;
-}
-
-int uh_auth_check(struct client *cl, struct http_request *req,
-				  struct path_info *pi)
-{
-	int i, plen, rlen, protected;
-	char buffer[UH_LIMIT_MSGHEAD];
-	char *user = NULL;
-	char *pass = NULL;
-
-	struct auth_realm *realm = NULL;
-
-	plen = strlen(pi->name);
-	protected = 0;
-
-	/* check whether at least one realm covers the requested url */
-	for (realm = uh_realms; realm; realm = realm->next)
-	{
-		rlen = strlen(realm->path);
-
-		if ((plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen))
-		{
-			req->realm = realm;
-			protected = 1;
-			break;
-		}
-	}
-
-	/* requested resource is covered by a realm */
-	if (protected)
-	{
-		/* try to get client auth info */
-		foreach_header(i, req->headers)
-		{
-			if (!strcasecmp(req->headers[i], "Authorization") &&
-				(strlen(req->headers[i+1]) > 6) &&
-				!strncasecmp(req->headers[i+1], "Basic ", 6))
-			{
-				memset(buffer, 0, sizeof(buffer));
-				uh_b64decode(buffer, sizeof(buffer) - 1,
-					(unsigned char *) &req->headers[i+1][6],
-					strlen(req->headers[i+1]) - 6);
-
-				if ((pass = strchr(buffer, ':')) != NULL)
-				{
-					user = buffer;
-					*pass++ = 0;
-				}
-
-				break;
-			}
-		}
-
-		/* have client auth */
-		if (user && pass)
-		{
-			/* find matching realm */
-			for (realm = uh_realms; realm; realm = realm->next)
-			{
-				rlen = strlen(realm->path);
-
-				if ((plen >= rlen) &&
-					!strncasecmp(pi->name, realm->path, rlen) &&
-					!strcmp(user, realm->user))
-				{
-					req->realm = realm;
-					break;
-				}
-			}
-
-			/* found a realm matching the username */
-			if (realm)
-			{
-				/* check user pass */
-				if (!strcmp(pass, realm->pass) ||
-				    !strcmp(crypt(pass, realm->pass), realm->pass))
-					return 1;
-			}
-		}
-
-		/* 401 */
-		uh_http_sendf(cl, NULL,
-		              "%s 401 Authorization Required\r\n"
-		              "WWW-Authenticate: Basic realm=\"%s\"\r\n"
-		              "Content-Type: text/plain\r\n"
-		              "Content-Length: 23\r\n\r\n"
-		              "Authorization Required\n",
-		              http_versions[req->version],
-		              cl->server->conf->realm);
-
-		return 0;
-	}
-
-	return 1;
-}
-
-
-static struct listener *uh_listeners = NULL;
-static struct client *uh_clients = NULL;
-
-struct listener * uh_listener_add(int sock, struct config *conf)
-{
-	struct listener *new = NULL;
-	socklen_t sl;
-
-	if ((new = (struct listener *)malloc(sizeof(struct listener))) != NULL)
-	{
-		memset(new, 0, sizeof(struct listener));
-
-		new->fd.fd = sock;
-		new->conf  = conf;
-
-
-		/* get local endpoint addr */
-		sl = sizeof(struct sockaddr_in6);
-		memset(&(new->addr), 0, sl);
-		getsockname(sock, (struct sockaddr *) &(new->addr), &sl);
-
-		new->next = uh_listeners;
-		uh_listeners = new;
-
-		return new;
-	}
-
-	return NULL;
-}
-
-struct listener * uh_listener_lookup(int sock)
-{
-	struct listener *cur = NULL;
-
-	for (cur = uh_listeners; cur; cur = cur->next)
-		if (cur->fd.fd == sock)
-			return cur;
-
-	return NULL;
-}
-
-
-struct client * uh_client_add(int sock, struct listener *serv,
-                              struct sockaddr_in6 *peer)
-{
-	struct client *new = NULL;
-	socklen_t sl;
-
-	if ((new = (struct client *)malloc(sizeof(struct client))) != NULL)
-	{
-		memset(new, 0, sizeof(struct client));
-		memcpy(&new->peeraddr, peer, sizeof(new->peeraddr));
-
-		new->fd.fd  = sock;
-		new->server = serv;
-
-		new->rpipe.fd = -1;
-		new->wpipe.fd = -1;
-
-		/* get local endpoint addr */
-		sl = sizeof(struct sockaddr_in6);
-		getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
-
-		new->next = uh_clients;
-		uh_clients = new;
-
-		serv->n_clients++;
-
-		D("IO: Client(%d) allocated\n", new->fd.fd);
-	}
-
-	return new;
-}
-
-struct client * uh_client_lookup(int sock)
-{
-	struct client *cur = NULL;
-
-	for (cur = uh_clients; cur; cur = cur->next)
-		if (cur->fd.fd == sock)
-			return cur;
-
-	return NULL;
-}
-
-void uh_client_shutdown(struct client *cl)
-{
-#ifdef HAVE_TLS
-	/* free client tls context */
-	if (cl->server && cl->server->conf->tls)
-		cl->server->conf->tls_close(cl);
-#endif
-
-	/* remove from global client list */
-	uh_client_remove(cl);
-}
-
-void uh_client_remove(struct client *cl)
-{
-	struct client *cur = NULL;
-	struct client *prv = NULL;
-
-	for (cur = uh_clients; cur; prv = cur, cur = cur->next)
-	{
-		if (cur == cl)
-		{
-			if (prv)
-				prv->next = cur->next;
-			else
-				uh_clients = cur->next;
-
-			if (cur->timeout.pending)
-				uloop_timeout_cancel(&cur->timeout);
-
-			if (cur->proc.pid)
-				uloop_process_delete(&cur->proc);
-
-			D("IO: Client(%d) freeing\n", cur->fd.fd);
-
-			uh_ufd_remove(&cur->rpipe);
-			uh_ufd_remove(&cur->wpipe);
-			uh_ufd_remove(&cur->fd);
-
-			cur->server->n_clients--;
-
-			free(cur);
-			break;
-		}
-	}
-}
-
-
-void uh_ufd_add(struct uloop_fd *u, uloop_fd_handler h, unsigned int ev)
-{
-	if (h != NULL)
-	{
-		u->cb = h;
-		uloop_fd_add(u, ev);
-		D("IO: FD(%d) added to uloop\n", u->fd);
-	}
-}
-
-void uh_ufd_remove(struct uloop_fd *u)
-{
-	if (u->cb != NULL)
-	{
-		uloop_fd_delete(u);
-		D("IO: FD(%d) removed from uloop\n", u->fd);
-		u->cb = NULL;
-	}
-
-	if (u->fd > -1)
-	{
-		close(u->fd);
-		D("IO: FD(%d) closed\n", u->fd);
-		u->fd = -1;
-	}
-}
-
-
-#ifdef HAVE_CGI
-static struct interpreter *uh_interpreters = NULL;
-
-struct interpreter * uh_interpreter_add(const char *extn, const char *path)
-{
-	struct interpreter *new = NULL;
-
-	if ((new = (struct interpreter *)malloc(sizeof(struct interpreter))) != NULL)
-	{
-		memset(new, 0, sizeof(struct interpreter));
-
-		memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1));
-		memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1));
-
-		new->next = uh_interpreters;
-		uh_interpreters = new;
-
-		return new;
-	}
-
-	return NULL;
-}
-
-struct interpreter * uh_interpreter_lookup(const char *path)
-{
-	struct interpreter *cur = NULL;
-	const char *e;
-
-	for (cur = uh_interpreters; cur; cur = cur->next)
-	{
-		e = &path[max(strlen(path) - strlen(cur->extn), 0)];
-
-		if (!strcmp(e, cur->extn))
-			return cur;
-	}
-
-	return NULL;
-}
-#endif

+ 0 - 140
package/network/services/uhttpd/src/uhttpd-utils.h

@@ -1,140 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Utility header
- *
- *   Copyright (C) 2010-2012 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_UTILS_
-
-#include <stdarg.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <sys/stat.h>
-
-#include <libubox/uloop.h>
-
-
-#ifdef HAVE_SHADOW
-#include <shadow.h>
-#endif
-
-#define min(x, y) (((x) < (y)) ? (x) : (y))
-#define max(x, y) (((x) > (y)) ? (x) : (y))
-
-#define array_size(x) \
-	(sizeof(x) / sizeof(x[0]))
-
-#define foreach_header(i, h) \
-	for( i = 0; (i + 1) < (sizeof(h) / sizeof(h[0])) && h[i]; i += 2 )
-
-#define fd_cloexec(fd) \
-	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)
-
-#define fd_nonblock(fd) \
-	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
-
-#define ensure_out(x) \
-	do { if((x) < 0) goto out; } while(0)
-
-#define ensure_ret(x) \
-	do { if((x) < 0) return -1; } while(0)
-
-
-struct path_info {
-	char *root;
-	char *phys;
-	char *name;
-	char *info;
-	char *query;
-	int redirected;
-	struct stat stat;
-};
-
-
-const char * sa_straddr(void *sa);
-const char * sa_strport(void *sa);
-int sa_port(void *sa);
-int sa_rfc1918(void *sa);
-
-char *strfind(char *haystack, int hslen, const char *needle, int ndlen);
-
-bool uh_socket_wait(int fd, int sec, bool write);
-
-int uh_raw_send(int fd, const char *buf, int len, int seconds);
-int uh_raw_recv(int fd, char *buf, int len, int seconds);
-int uh_tcp_send(struct client *cl, const char *buf, int len);
-int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len);
-int uh_tcp_recv(struct client *cl, char *buf, int len);
-int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len);
-
-int uh_http_sendhf(struct client *cl, int code, const char *summary,
-				   const char *fmt, ...);
-
-#define uh_http_response(cl, code, message) \
-	uh_http_sendhf(cl, code, message, message)
-
-int uh_http_sendc(struct client *cl, const char *data, int len);
-
-int uh_http_sendf(
-	struct client *cl, struct http_request *req,
-	const char *fmt, ...
-);
-
-int uh_http_send(
-	struct client *cl, struct http_request *req,
-	const char *buf, int len
-);
-
-
-int uh_urldecode(char *buf, int blen, const char *src, int slen);
-int uh_urlencode(char *buf, int blen, const char *src, int slen);
-int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen);
-
-
-struct auth_realm * uh_auth_add(char *path, char *user, char *pass);
-
-int uh_auth_check(
-	struct client *cl, struct http_request *req, struct path_info *pi
-);
-
-
-struct path_info * uh_path_lookup(struct client *cl, const char *url);
-
-struct listener * uh_listener_add(int sock, struct config *conf);
-struct listener * uh_listener_lookup(int sock);
-
-struct client * uh_client_add(int sock, struct listener *serv,
-                              struct sockaddr_in6 *peer);
-
-struct client * uh_client_lookup(int sock);
-
-#define uh_client_error(cl, code, status, ...) do { \
-	uh_http_sendhf(cl, code, status, __VA_ARGS__);  \
-	uh_client_shutdown(cl);                         \
-} while(0)
-
-void uh_client_shutdown(struct client *cl);
-void uh_client_remove(struct client *cl);
-
-void uh_ufd_add(struct uloop_fd *u, uloop_fd_handler h, unsigned int ev);
-void uh_ufd_remove(struct uloop_fd *u);
-
-
-#ifdef HAVE_CGI
-struct interpreter * uh_interpreter_add(const char *extn, const char *path);
-struct interpreter * uh_interpreter_lookup(const char *path);
-#endif
-
-#endif

+ 0 - 1288
package/network/services/uhttpd/src/uhttpd.c

@@ -1,1288 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Main component
- *
- *   Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#define _XOPEN_SOURCE 500	/* crypt() */
-
-#include "uhttpd.h"
-#include "uhttpd-utils.h"
-#include "uhttpd-file.h"
-
-#ifdef HAVE_CGI
-#include "uhttpd-cgi.h"
-#endif
-
-#ifdef HAVE_LUA
-#include "uhttpd-lua.h"
-#endif
-
-#ifdef HAVE_TLS
-#include "uhttpd-tls.h"
-#endif
-
-
-const char * http_methods[] = { "GET", "POST", "HEAD", };
-const char * http_versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", };
-
-static int run = 1;
-
-static void uh_sigterm(int sig)
-{
-	run = 0;
-}
-
-static void uh_config_parse(struct config *conf)
-{
-	FILE *c;
-	char line[512];
-	char *col1 = NULL;
-	char *col2 = NULL;
-	char *eol  = NULL;
-
-	const char *path = conf->file ? conf->file : "/etc/httpd.conf";
-
-
-	if ((c = fopen(path, "r")) != NULL)
-	{
-		memset(line, 0, sizeof(line));
-
-		while (fgets(line, sizeof(line) - 1, c))
-		{
-			if ((line[0] == '/') && (strchr(line, ':') != NULL))
-			{
-				if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
-				    !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
-					!(eol = strchr(col2, '\n')) || (*eol++  = 0))
-				{
-					continue;
-				}
-
-				if (!uh_auth_add(line, col1, col2))
-				{
-					fprintf(stderr,
-							"Notice: No password set for user %s, ignoring "
-							"authentication on %s\n", col1, line
-					);
-				}
-			}
-			else if (!strncmp(line, "I:", 2))
-			{
-				if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
-				    !(eol = strchr(col1, '\n')) || (*eol++  = 0))
-				{
-				   	continue;
-				}
-
-				conf->index_file = strdup(col1);
-			}
-			else if (!strncmp(line, "E404:", 5))
-			{
-				if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
-				    !(eol = strchr(col1, '\n')) || (*eol++  = 0))
-				{
-					continue;
-				}
-
-				conf->error_handler = strdup(col1);
-			}
-#ifdef HAVE_CGI
-			else if ((line[0] == '*') && (strchr(line, ':') != NULL))
-			{
-				if (!(col1 = strchr(line, '*')) || (*col1++ = 0) ||
-				    !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
-				    !(eol = strchr(col2, '\n')) || (*eol++  = 0))
-				{
-					continue;
-				}
-
-				if (!uh_interpreter_add(col1, col2))
-				{
-					fprintf(stderr,
-							"Unable to add interpreter %s for extension %s: "
-							"Out of memory\n", col2, col1
-					);
-				}
-			}
-#endif
-		}
-
-		fclose(c);
-	}
-}
-
-static void uh_listener_cb(struct uloop_fd *u, unsigned int events);
-
-static int uh_socket_bind(const char *host, const char *port,
-                          struct addrinfo *hints, int do_tls,
-                          struct config *conf)
-{
-	int sock = -1;
-	int yes = 1;
-	int status;
-	int bound = 0;
-
-	int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt;
-
-	struct listener *l = NULL;
-	struct addrinfo *addrs = NULL, *p = NULL;
-
-	if ((status = getaddrinfo(host, port, hints, &addrs)) != 0)
-	{
-		fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
-	}
-
-	/* try to bind a new socket to each found address */
-	for (p = addrs; p; p = p->ai_next)
-	{
-		/* get the socket */
-		if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
-		{
-			perror("socket()");
-			goto error;
-		}
-
-		/* "address already in use" */
-		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
-		{
-			perror("setsockopt()");
-			goto error;
-		}
-
-		/* TCP keep-alive */
-		if (conf->tcp_keepalive > 0)
-		{
-			tcp_ka_idl = 1;
-			tcp_ka_cnt = 3;
-			tcp_ka_int = conf->tcp_keepalive;
-
-			if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
-			    setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,  &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
-			    setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
-			    setsockopt(sock, SOL_TCP, TCP_KEEPCNT,   &tcp_ka_cnt, sizeof(tcp_ka_cnt)))
-			{
-			    fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
-			    	strerror(errno));
-			}
-		}
-
-		/* required to get parallel v4 + v6 working */
-		if (p->ai_family == AF_INET6)
-		{
-			if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1)
-			{
-				perror("setsockopt()");
-				goto error;
-			}
-		}
-
-		/* bind */
-		if (bind(sock, p->ai_addr, p->ai_addrlen) == -1)
-		{
-			perror("bind()");
-			goto error;
-		}
-
-		/* listen */
-		if (listen(sock, UH_LIMIT_CLIENTS) == -1)
-		{
-			perror("listen()");
-			goto error;
-		}
-
-		/* add listener to global list */
-		if (!(l = uh_listener_add(sock, conf)))
-		{
-			fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");
-			goto error;
-		}
-
-#ifdef HAVE_TLS
-		/* init TLS */
-		l->tls = do_tls ? conf->tls : NULL;
-#endif
-
-		/* add socket to uloop */
-		fd_cloexec(sock);
-		uh_ufd_add(&l->fd, uh_listener_cb, ULOOP_READ);
-
-		bound++;
-		continue;
-
-		error:
-		if (sock > 0)
-			close(sock);
-	}
-
-	freeaddrinfo(addrs);
-
-	return bound;
-}
-
-static struct http_request * uh_http_header_parse(struct client *cl,
-												  char *buffer, int buflen)
-{
-	char *method  = buffer;
-	char *path    = NULL;
-	char *version = NULL;
-
-	char *headers = NULL;
-	char *hdrname = NULL;
-	char *hdrdata = NULL;
-
-	int i;
-	int hdrcount = 0;
-
-	struct http_request *req = &cl->request;
-
-
-	/* terminate initial header line */
-	if ((headers = strfind(buffer, buflen, "\r\n", 2)) != NULL)
-	{
-		buffer[buflen-1] = 0;
-
-		*headers++ = 0;
-		*headers++ = 0;
-
-		/* find request path */
-		if ((path = strchr(buffer, ' ')) != NULL)
-			*path++ = 0;
-
-		/* find http version */
-		if ((path != NULL) && ((version = strchr(path, ' ')) != NULL))
-			*version++ = 0;
-
-
-		/* check method */
-		if (method && !strcmp(method, "GET"))
-			req->method = UH_HTTP_MSG_GET;
-		else if (method && !strcmp(method, "POST"))
-			req->method = UH_HTTP_MSG_POST;
-		else if (method && !strcmp(method, "HEAD"))
-			req->method = UH_HTTP_MSG_HEAD;
-		else
-		{
-			/* invalid method */
-			uh_http_response(cl, 405, "Method Not Allowed");
-			return NULL;
-		}
-
-		/* check path */
-		if (!path || !strlen(path))
-		{
-			/* malformed request */
-			uh_http_response(cl, 400, "Bad Request");
-			return NULL;
-		}
-		else
-		{
-			req->url = path;
-		}
-
-		/* check version */
-		if (version && !strcmp(version, "HTTP/0.9"))
-			req->version = UH_HTTP_VER_0_9;
-		else if (version && !strcmp(version, "HTTP/1.0"))
-			req->version = UH_HTTP_VER_1_0;
-		else if (version && !strcmp(version, "HTTP/1.1"))
-			req->version = UH_HTTP_VER_1_1;
-		else
-		{
-			/* unsupported version */
-			uh_http_response(cl, 400, "Bad Request");
-			return NULL;
-		}
-
-		D("SRV: %s %s %s\n",
-		  http_methods[req->method], req->url, http_versions[req->version]);
-
-		/* process header fields */
-		for (i = (int)(headers - buffer); i < buflen; i++)
-		{
-			/* found eol and have name + value, push out header tuple */
-			if (hdrname && hdrdata && (buffer[i] == '\r' || buffer[i] == '\n'))
-			{
-				buffer[i] = 0;
-
-				/* store */
-				if ((hdrcount + 1) < array_size(req->headers))
-				{
-					D("SRV: HTTP: %s: %s\n", hdrname, hdrdata);
-
-					req->headers[hdrcount++] = hdrname;
-					req->headers[hdrcount++] = hdrdata;
-
-					hdrname = hdrdata = NULL;
-				}
-
-				/* too large */
-				else
-				{
-					D("SRV: HTTP: header too big (too many headers)\n");
-					uh_http_response(cl, 413, "Request Entity Too Large");
-					return NULL;
-				}
-			}
-
-			/* have name but no value and found a colon, start of value */
-			else if (hdrname && !hdrdata &&
-					 ((i+1) < buflen) && (buffer[i] == ':'))
-			{
-				buffer[i] = 0;
-				hdrdata = &buffer[i+1];
-
-				while ((hdrdata + 1) < (buffer + buflen) && *hdrdata == ' ')
-					hdrdata++;
-			}
-
-			/* have no name and found [A-Za-z], start of name */
-			else if (!hdrname && isalpha(buffer[i]))
-			{
-				hdrname = &buffer[i];
-			}
-		}
-
-		/* valid enough */
-		req->redirect_status = 200;
-		return req;
-	}
-
-	/* Malformed request */
-	uh_http_response(cl, 400, "Bad Request");
-	return NULL;
-}
-
-
-static struct http_request * uh_http_header_recv(struct client *cl)
-{
-	char *bufptr = cl->httpbuf.buf;
-	char *idxptr = NULL;
-
-	ssize_t blen = sizeof(cl->httpbuf.buf)-1;
-	ssize_t rlen = 0;
-
-	memset(bufptr, 0, sizeof(cl->httpbuf.buf));
-
-	while (blen > 0)
-	{
-		/* receive data */
-		ensure_out(rlen = uh_tcp_recv(cl, bufptr, blen));
-		D("SRV: Client(%d) peek(%d) = %d\n", cl->fd.fd, blen, rlen);
-
-		if (rlen <= 0)
-		{
-			D("SRV: Client(%d) dead [%s]\n", cl->fd.fd, strerror(errno));
-			return NULL;
-		}
-
-		blen -= rlen;
-		bufptr += rlen;
-
-		if ((idxptr = strfind(cl->httpbuf.buf, sizeof(cl->httpbuf.buf),
-							  "\r\n\r\n", 4)))
-		{
-			/* header read complete ... */
-			cl->httpbuf.ptr = idxptr + 4;
-			cl->httpbuf.len = bufptr - cl->httpbuf.ptr;
-
-			return uh_http_header_parse(cl, cl->httpbuf.buf,
-										(cl->httpbuf.ptr - cl->httpbuf.buf));
-		}
-	}
-
-	/* request entity too large */
-	D("SRV: HTTP: header too big (buffer exceeded)\n");
-	uh_http_response(cl, 413, "Request Entity Too Large");
-
-out:
-	return NULL;
-}
-
-#if defined(HAVE_LUA) || defined(HAVE_CGI)
-static int uh_path_match(const char *prefix, const char *url)
-{
-	if ((strstr(url, prefix) == url) &&
-		((prefix[strlen(prefix)-1] == '/') ||
-		 (strlen(url) == strlen(prefix))   ||
-		 (url[strlen(prefix)] == '/')))
-	{
-		return 1;
-	}
-
-	return 0;
-}
-#endif
-
-static bool uh_dispatch_request(struct client *cl, struct http_request *req)
-{
-	struct path_info *pin;
-	struct interpreter *ipr = NULL;
-	struct config *conf = cl->server->conf;
-
-#ifdef HAVE_LUA
-	/* Lua request? */
-	if (conf->lua_state &&
-		uh_path_match(conf->lua_prefix, req->url))
-	{
-		return conf->lua_request(cl, conf->lua_state);
-	}
-	else
-#endif
-
-#ifdef HAVE_UBUS
-	/* ubus request? */
-	if (conf->ubus_state &&
-		uh_path_match(conf->ubus_prefix, req->url))
-	{
-		return conf->ubus_request(cl, conf->ubus_state);
-	}
-	else
-#endif
-
-	/* dispatch request */
-	if ((pin = uh_path_lookup(cl, req->url)) != NULL)
-	{
-		/* auth ok? */
-		if (!pin->redirected && uh_auth_check(cl, req, pin))
-		{
-#ifdef HAVE_CGI
-			if (uh_path_match(conf->cgi_prefix, pin->name) ||
-				(ipr = uh_interpreter_lookup(pin->phys)) != NULL)
-			{
-				return uh_cgi_request(cl, pin, ipr);
-			}
-#endif
-			return uh_file_request(cl, pin);
-		}
-	}
-
-	/* 404 - pass 1 */
-	else
-	{
-		/* Try to invoke an error handler */
-		if ((pin = uh_path_lookup(cl, conf->error_handler)) != NULL)
-		{
-			/* auth ok? */
-			if (uh_auth_check(cl, req, pin))
-			{
-				req->redirect_status = 404;
-#ifdef HAVE_CGI
-				if (uh_path_match(conf->cgi_prefix, pin->name) ||
-					(ipr = uh_interpreter_lookup(pin->phys)) != NULL)
-				{
-					return uh_cgi_request(cl, pin, ipr);
-				}
-#endif
-				return uh_file_request(cl, pin);
-			}
-		}
-
-		/* 404 - pass 2 */
-		else
-		{
-			uh_http_sendhf(cl, 404, "Not Found", "No such file or directory");
-		}
-	}
-
-	return false;
-}
-
-static void uh_socket_cb(struct uloop_fd *u, unsigned int events);
-
-static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
-{
-	int new_fd;
-	struct listener *serv;
-	struct client *cl;
-	struct config *conf;
-
-	struct sockaddr_in6 sa;
-	socklen_t sl = sizeof(sa);
-
-	serv = container_of(u, struct listener, fd);
-	conf = serv->conf;
-
-	/* defer client if maximum number of requests is exceeded */
-	if (serv->n_clients >= conf->max_requests)
-		return;
-
-	/* handle new connections */
-	if ((new_fd = accept(u->fd, (struct sockaddr *)&sa, &sl)) != -1)
-	{
-		D("SRV: Server(%d) accept => Client(%d)\n", u->fd, new_fd);
-
-		/* add to global client list */
-		if ((cl = uh_client_add(new_fd, serv, &sa)) != NULL)
-		{
-			/* add client socket to global fdset */
-			uh_ufd_add(&cl->fd, uh_socket_cb, ULOOP_READ);
-			fd_cloexec(cl->fd.fd);
-
-#ifdef HAVE_TLS
-			/* setup client tls context */
-			if (conf->tls)
-			{
-				if (conf->tls_accept(cl) < 1)
-				{
-					D("SRV: Client(%d) SSL handshake failed, drop\n", new_fd);
-
-					/* remove from global client list */
-					uh_client_remove(cl);
-					return;
-				}
-			}
-#endif
-		}
-
-		/* insufficient resources */
-		else
-		{
-			fprintf(stderr, "uh_client_add(): Cannot allocate memory\n");
-			close(new_fd);
-		}
-	}
-}
-
-static void uh_client_cb(struct client *cl, unsigned int events);
-
-static void uh_rpipe_cb(struct uloop_fd *u, unsigned int events)
-{
-	struct client *cl = container_of(u, struct client, rpipe);
-
-	D("SRV: Client(%d) rpipe readable\n", cl->fd.fd);
-
-	uh_client_cb(cl, ULOOP_WRITE);
-}
-
-static void uh_socket_cb(struct uloop_fd *u, unsigned int events)
-{
-	struct client *cl = container_of(u, struct client, fd);
-
-	D("SRV: Client(%d) socket readable\n", cl->fd.fd);
-
-	uh_client_cb(cl, ULOOP_READ);
-}
-
-static void uh_child_cb(struct uloop_process *p, int rv)
-{
-	struct client *cl = container_of(p, struct client, proc);
-
-	D("SRV: Client(%d) child(%d) dead\n", cl->fd.fd, cl->proc.pid);
-
-	uh_client_cb(cl, ULOOP_READ | ULOOP_WRITE);
-}
-
-static void uh_kill9_cb(struct uloop_timeout *t)
-{
-	struct client *cl = container_of(t, struct client, timeout);
-
-	if (!kill(cl->proc.pid, 0))
-	{
-		D("SRV: Client(%d) child(%d) kill(SIGKILL)...\n",
-		  cl->fd.fd, cl->proc.pid);
-
-		kill(cl->proc.pid, SIGKILL);
-	}
-}
-
-static void uh_timeout_cb(struct uloop_timeout *t)
-{
-	struct client *cl = container_of(t, struct client, timeout);
-
-	D("SRV: Client(%d) child(%d) timed out\n", cl->fd.fd, cl->proc.pid);
-
-	if (!kill(cl->proc.pid, 0))
-	{
-		D("SRV: Client(%d) child(%d) kill(SIGTERM)...\n",
-		  cl->fd.fd, cl->proc.pid);
-
-		kill(cl->proc.pid, SIGTERM);
-
-		cl->timeout.cb = uh_kill9_cb;
-		uloop_timeout_set(&cl->timeout, 1000);
-	}
-}
-
-static void uh_client_cb(struct client *cl, unsigned int events)
-{
-	int i;
-	struct config *conf;
-	struct http_request *req;
-
-	conf = cl->server->conf;
-
-	D("SRV: Client(%d) enter callback\n", cl->fd.fd);
-
-	/* undispatched yet */
-	if (!cl->dispatched)
-	{
-		/* we have no headers yet and this was a write event, ignore... */
-		if (!(events & ULOOP_READ))
-		{
-			D("SRV: Client(%d) ignoring write event before headers\n", cl->fd.fd);
-			return;
-		}
-
-		/* attempt to receive and parse headers */
-		if (!(req = uh_http_header_recv(cl)))
-		{
-			D("SRV: Client(%d) failed to receive header\n", cl->fd.fd);
-			uh_client_shutdown(cl);
-			return;
-		}
-
-		/* process expect headers */
-		foreach_header(i, req->headers)
-		{
-			if (strcasecmp(req->headers[i], "Expect"))
-				continue;
-
-			if (strcasecmp(req->headers[i+1], "100-continue"))
-			{
-				D("SRV: Client(%d) unknown expect header (%s)\n",
-				  cl->fd.fd, req->headers[i+1]);
-
-				uh_http_response(cl, 417, "Precondition Failed");
-				uh_client_shutdown(cl);
-				return;
-			}
-			else
-			{
-				D("SRV: Client(%d) sending HTTP/1.1 100 Continue\n", cl->fd.fd);
-
-				uh_http_sendf(cl, NULL, "HTTP/1.1 100 Continue\r\n\r\n");
-				cl->httpbuf.len = 0; /* client will re-send the body */
-				break;
-			}
-		}
-
-		/* RFC1918 filtering */
-		if (conf->rfc1918_filter &&
-			sa_rfc1918(&cl->peeraddr) && !sa_rfc1918(&cl->servaddr))
-		{
-			uh_http_sendhf(cl, 403, "Forbidden",
-						   "Rejected request from RFC1918 IP "
-						   "to public server address");
-
-			uh_client_shutdown(cl);
-			return;
-		}
-
-		/* dispatch request */
-		if (!uh_dispatch_request(cl, req))
-		{
-			D("SRV: Client(%d) failed to dispach request\n", cl->fd.fd);
-			uh_client_shutdown(cl);
-			return;
-		}
-
-		/* request handler spawned a pipe, register handler */
-		if (cl->rpipe.fd > -1)
-		{
-			D("SRV: Client(%d) pipe(%d) spawned\n", cl->fd.fd, cl->rpipe.fd);
-
-			uh_ufd_add(&cl->rpipe, uh_rpipe_cb, ULOOP_READ);
-		}
-
-		/* request handler spawned a child, register handler */
-		if (cl->proc.pid)
-		{
-			D("SRV: Client(%d) child(%d) spawned\n", cl->fd.fd, cl->proc.pid);
-
-			cl->proc.cb = uh_child_cb;
-			uloop_process_add(&cl->proc);
-
-			cl->timeout.cb = uh_timeout_cb;
-			uloop_timeout_set(&cl->timeout, conf->script_timeout * 1000);
-		}
-
-		/* header processing complete */
-		D("SRV: Client(%d) dispatched\n", cl->fd.fd);
-		cl->dispatched = true;
-	}
-
-	if (!cl->cb(cl))
-	{
-		D("SRV: Client(%d) response callback signalized EOF\n", cl->fd.fd);
-		uh_client_shutdown(cl);
-		return;
-	}
-}
-
-#ifdef HAVE_TLS
-static inline int uh_inittls(struct config *conf)
-{
-	/* library handle */
-	void *lib;
-
-	/* already loaded */
-	if (conf->tls != NULL)
-		return 0;
-
-	/* load TLS plugin */
-	if (!(lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)))
-	{
-		fprintf(stderr,
-				"Notice: Unable to load TLS plugin - disabling SSL support! "
-				"(Reason: %s)\n", dlerror()
-		);
-
-		return 1;
-	}
-	else
-	{
-		/* resolve functions */
-		if (!(conf->tls_init   = dlsym(lib, "uh_tls_ctx_init"))      ||
-		    !(conf->tls_cert   = dlsym(lib, "uh_tls_ctx_cert"))      ||
-		    !(conf->tls_key    = dlsym(lib, "uh_tls_ctx_key"))       ||
-		    !(conf->tls_free   = dlsym(lib, "uh_tls_ctx_free"))      ||
-		    !(conf->tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
-		    !(conf->tls_close  = dlsym(lib, "uh_tls_client_close"))  ||
-		    !(conf->tls_recv   = dlsym(lib, "uh_tls_client_recv"))   ||
-		    !(conf->tls_send   = dlsym(lib, "uh_tls_client_send")))
-		{
-			fprintf(stderr,
-					"Error: Failed to lookup required symbols "
-					"in TLS plugin: %s\n", dlerror()
-			);
-			exit(1);
-		}
-
-		/* init SSL context */
-		if (!(conf->tls = conf->tls_init()))
-		{
-			fprintf(stderr, "Error: Failed to initalize SSL context\n");
-			exit(1);
-		}
-	}
-
-	return 0;
-}
-#endif
-
-int main (int argc, char **argv)
-{
-	/* working structs */
-	struct addrinfo hints;
-	struct sigaction sa;
-	struct config conf;
-
-	/* maximum file descriptor number */
-	int cur_fd = 0;
-
-#ifdef HAVE_TLS
-	int tls = 0;
-	int keys = 0;
-#endif
-
-	int bound = 0;
-	int nofork = 0;
-
-	/* args */
-	int opt;
-	char addr[128];
-	char *port = NULL;
-
-#if defined(HAVE_LUA) || defined(HAVE_TLS) || defined(HAVE_UBUS)
-	/* library handle */
-	void *lib;
-#endif
-
-	/* handle SIGPIPE, SIGINT, SIGTERM */
-	sa.sa_flags = 0;
-	sigemptyset(&sa.sa_mask);
-
-	sa.sa_handler = SIG_IGN;
-	sigaction(SIGPIPE, &sa, NULL);
-
-	sa.sa_handler = uh_sigterm;
-	sigaction(SIGINT,  &sa, NULL);
-	sigaction(SIGTERM, &sa, NULL);
-
-	/* prepare addrinfo hints */
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family   = AF_UNSPEC;
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_flags    = AI_PASSIVE;
-
-	/* parse args */
-	memset(&conf, 0, sizeof(conf));
-
-	uloop_init();
-
-	while ((opt = getopt(argc, argv,
-						 "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:n:x:i:t:T:A:u:U:")) > 0)
-	{
-		switch(opt)
-		{
-			/* [addr:]port */
-			case 'p':
-			case 's':
-				memset(addr, 0, sizeof(addr));
-
-				if ((port = strrchr(optarg, ':')) != NULL)
-				{
-					if ((optarg[0] == '[') && (port > optarg) && (port[-1] == ']'))
-						memcpy(addr, optarg + 1,
-							min(sizeof(addr), (int)(port - optarg) - 2));
-					else
-						memcpy(addr, optarg,
-							min(sizeof(addr), (int)(port - optarg)));
-
-					port++;
-				}
-				else
-				{
-					port = optarg;
-				}
-
-#ifdef HAVE_TLS
-				if (opt == 's')
-				{
-					if (uh_inittls(&conf))
-					{
-						fprintf(stderr,
-							"Notice: TLS support is disabled, "
-							"ignoring '-s %s'\n", optarg
-						);
-						continue;
-					}
-
-					tls = 1;
-				}
-#endif
-
-				/* bind sockets */
-				bound += uh_socket_bind(addr[0] ? addr : NULL, port, &hints,
-				                        (opt == 's'), &conf);
-				break;
-
-#ifdef HAVE_TLS
-			/* certificate */
-			case 'C':
-				if (!uh_inittls(&conf))
-				{
-					if (conf.tls_cert(conf.tls, optarg) < 1)
-					{
-						fprintf(stderr,
-								"Error: Invalid certificate file given\n");
-						exit(1);
-					}
-
-					keys++;
-				}
-
-				break;
-
-			/* key */
-			case 'K':
-				if (!uh_inittls(&conf))
-				{
-					if (conf.tls_key(conf.tls, optarg) < 1)
-					{
-						fprintf(stderr,
-								"Error: Invalid private key file given\n");
-						exit(1);
-					}
-
-					keys++;
-				}
-
-				break;
-#else
-			case 'C':
-			case 'K':
-				fprintf(stderr,
-				        "Notice: TLS support not compiled, ignoring -%c\n",
-				        opt);
-				break;
-#endif
-
-			/* docroot */
-			case 'h':
-				if (! realpath(optarg, conf.docroot))
-				{
-					fprintf(stderr, "Error: Invalid directory %s: %s\n",
-							optarg, strerror(errno));
-					exit(1);
-				}
-				break;
-
-			/* error handler */
-			case 'E':
-				if ((strlen(optarg) == 0) || (optarg[0] != '/'))
-				{
-					fprintf(stderr, "Error: Invalid error handler: %s\n",
-							optarg);
-					exit(1);
-				}
-				conf.error_handler = optarg;
-				break;
-
-			/* index file */
-			case 'I':
-				if ((strlen(optarg) == 0) || (optarg[0] == '/'))
-				{
-					fprintf(stderr, "Error: Invalid index page: %s\n",
-							optarg);
-					exit(1);
-				}
-				conf.index_file = optarg;
-				break;
-
-			/* don't follow symlinks */
-			case 'S':
-				conf.no_symlinks = 1;
-				break;
-
-			/* don't list directories */
-			case 'D':
-				conf.no_dirlists = 1;
-				break;
-
-			case 'R':
-				conf.rfc1918_filter = 1;
-				break;
-
-			case 'n':
-				conf.max_requests = atoi(optarg);
-				break;
-
-#ifdef HAVE_CGI
-			/* cgi prefix */
-			case 'x':
-				conf.cgi_prefix = optarg;
-				break;
-
-			/* interpreter */
-			case 'i':
-				if ((optarg[0] == '.') && (port = strchr(optarg, '=')))
-				{
-					*port++ = 0;
-					uh_interpreter_add(optarg, port);
-				}
-				else
-				{
-					fprintf(stderr, "Error: Invalid interpreter: %s\n",
-							optarg);
-					exit(1);
-				}
-				break;
-#else
-			case 'x':
-			case 'i':
-				fprintf(stderr,
-				        "Notice: CGI support not compiled, ignoring -%c\n",
-				        opt);
-				break;
-#endif
-
-#ifdef HAVE_LUA
-			/* lua prefix */
-			case 'l':
-				conf.lua_prefix = optarg;
-				break;
-
-			/* lua handler */
-			case 'L':
-				conf.lua_handler = optarg;
-				break;
-#else
-			case 'l':
-			case 'L':
-				fprintf(stderr,
-				        "Notice: Lua support not compiled, ignoring -%c\n",
-				        opt);
-				break;
-#endif
-
-#ifdef HAVE_UBUS
-			/* ubus prefix */
-			case 'u':
-				conf.ubus_prefix = optarg;
-				break;
-
-			/* ubus socket */
-			case 'U':
-				conf.ubus_socket = optarg;
-				break;
-#else
-			case 'u':
-			case 'U':
-				fprintf(stderr,
-				        "Notice: UBUS support not compiled, ignoring -%c\n",
-				        opt);
-				break;
-#endif
-
-#if defined(HAVE_CGI) || defined(HAVE_LUA)
-			/* script timeout */
-			case 't':
-				conf.script_timeout = atoi(optarg);
-				break;
-#endif
-
-			/* network timeout */
-			case 'T':
-				conf.network_timeout = atoi(optarg);
-				break;
-
-			/* tcp keep-alive */
-			case 'A':
-				conf.tcp_keepalive = atoi(optarg);
-				break;
-
-			/* no fork */
-			case 'f':
-				nofork = 1;
-				break;
-
-			/* urldecode */
-			case 'd':
-				if ((port = malloc(strlen(optarg)+1)) != NULL)
-				{
-					/* "decode" plus to space to retain compat */
-					for (opt = 0; optarg[opt]; opt++)
-						if (optarg[opt] == '+')
-							optarg[opt] = ' ';
-					/* opt now contains strlen(optarg) -- no need to re-scan */
-					memset(port, 0, opt+1);
-					if (uh_urldecode(port, opt, optarg, opt) < 0)
-					    fprintf(stderr, "uhttpd: invalid encoding\n");
-
-					printf("%s", port);
-					free(port);
-					exit(0);
-				}
-				break;
-
-			/* basic auth realm */
-			case 'r':
-				conf.realm = optarg;
-				break;
-
-			/* md5 crypt */
-			case 'm':
-				printf("%s\n", crypt(optarg, "$1$"));
-				exit(0);
-				break;
-
-			/* config file */
-			case 'c':
-				conf.file = optarg;
-				break;
-
-			default:
-				fprintf(stderr,
-					"Usage: %s -p [addr:]port [-h docroot]\n"
-					"	-f              Do not fork to background\n"
-					"	-c file         Configuration file, default is '/etc/httpd.conf'\n"
-					"	-p [addr:]port  Bind to specified address and port, multiple allowed\n"
-#ifdef HAVE_TLS
-					"	-s [addr:]port  Like -p but provide HTTPS on this port\n"
-					"	-C file         ASN.1 server certificate file\n"
-					"	-K file         ASN.1 server private key file\n"
-#endif
-					"	-h directory    Specify the document root, default is '.'\n"
-					"	-E string       Use given virtual URL as 404 error handler\n"
-					"	-I string       Use given filename as index page for directories\n"
-					"	-S              Do not follow symbolic links outside of the docroot\n"
-					"	-D              Do not allow directory listings, send 403 instead\n"
-					"	-R              Enable RFC1918 filter\n"
-					"	-n count        Maximum allowed number of concurrent requests\n"
-#ifdef HAVE_LUA
-					"	-l string       URL prefix for Lua handler, default is '/lua'\n"
-					"	-L file         Lua handler script, omit to disable Lua\n"
-#endif
-#ifdef HAVE_UBUS
-					"	-u string       URL prefix for HTTP/JSON handler\n"
-					"	-U file         Override ubus socket path\n"
-#endif
-#ifdef HAVE_CGI
-					"	-x string       URL prefix for CGI handler, default is '/cgi-bin'\n"
-					"	-i .ext=path    Use interpreter at path for files with the given extension\n"
-#endif
-#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS)
-					"	-t seconds      CGI, Lua and UBUS script timeout in seconds, default is 60\n"
-#endif
-					"	-T seconds      Network timeout in seconds, default is 30\n"
-					"	-d string       URL decode given string\n"
-					"	-r string       Specify basic auth realm\n"
-					"	-m string       MD5 crypt given string\n"
-					"\n", argv[0]
-				);
-
-				exit(1);
-		}
-	}
-
-#ifdef HAVE_TLS
-	if ((tls == 1) && (keys < 2))
-	{
-		fprintf(stderr, "Error: Missing private key or certificate file\n");
-		exit(1);
-	}
-#endif
-
-	if (bound < 1)
-	{
-		fprintf(stderr, "Error: No sockets bound, unable to continue\n");
-		exit(1);
-	}
-
-	/* default docroot */
-	if (!conf.docroot[0] && !realpath(".", conf.docroot))
-	{
-		fprintf(stderr, "Error: Can not determine default document root: %s\n",
-			strerror(errno));
-		exit(1);
-	}
-
-	/* default realm */
-	if (!conf.realm)
-		conf.realm = "Protected Area";
-
-	/* config file */
-	uh_config_parse(&conf);
-
-	/* default max requests */
-	if (conf.max_requests <= 0)
-		conf.max_requests = 3;
-
-	/* default network timeout */
-	if (conf.network_timeout <= 0)
-		conf.network_timeout = 30;
-
-#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS)
-	/* default script timeout */
-	if (conf.script_timeout <= 0)
-		conf.script_timeout = 60;
-#endif
-
-#ifdef HAVE_CGI
-	/* default cgi prefix */
-	if (!conf.cgi_prefix)
-		conf.cgi_prefix = "/cgi-bin";
-#endif
-
-#ifdef HAVE_LUA
-	/* load Lua plugin */
-	if (!(lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)))
-	{
-		fprintf(stderr,
-				"Notice: Unable to load Lua plugin - disabling Lua support! "
-				"(Reason: %s)\n", dlerror());
-	}
-	else
-	{
-		/* resolve functions */
-		if (!(conf.lua_init    = dlsym(lib, "uh_lua_init"))    ||
-		    !(conf.lua_close   = dlsym(lib, "uh_lua_close"))   ||
-		    !(conf.lua_request = dlsym(lib, "uh_lua_request")))
-		{
-			fprintf(stderr,
-					"Error: Failed to lookup required symbols "
-					"in Lua plugin: %s\n", dlerror()
-			);
-			exit(1);
-		}
-
-		/* init Lua runtime if handler is specified */
-		if (conf.lua_handler)
-		{
-			/* default lua prefix */
-			if (!conf.lua_prefix)
-				conf.lua_prefix = "/lua";
-
-			conf.lua_state = conf.lua_init(&conf);
-		}
-	}
-#endif
-
-#ifdef HAVE_UBUS
-	/* load ubus plugin */
-	if (!(lib = dlopen("uhttpd_ubus.so", RTLD_LAZY | RTLD_GLOBAL)))
-	{
-		fprintf(stderr,
-				"Notice: Unable to load ubus plugin - disabling ubus support! "
-				"(Reason: %s)\n", dlerror());
-	}
-	else if (conf.ubus_prefix)
-	{
-		/* resolve functions */
-		if (!(conf.ubus_init    = dlsym(lib, "uh_ubus_init"))    ||
-		    !(conf.ubus_close   = dlsym(lib, "uh_ubus_close"))   ||
-		    !(conf.ubus_request = dlsym(lib, "uh_ubus_request")))
-		{
-			fprintf(stderr,
-					"Error: Failed to lookup required symbols "
-					"in ubus plugin: %s\n", dlerror()
-			);
-			exit(1);
-		}
-
-		/* initialize ubus */
-		conf.ubus_state = conf.ubus_init(&conf);
-	}
-#endif
-
-	/* fork (if not disabled) */
-	if (!nofork)
-	{
-		switch (fork())
-		{
-			case -1:
-				perror("fork()");
-				exit(1);
-
-			case 0:
-				/* daemon setup */
-				if (chdir("/"))
-					perror("chdir()");
-
-				if ((cur_fd = open("/dev/null", O_WRONLY)) > -1)
-					dup2(cur_fd, 0);
-
-				if ((cur_fd = open("/dev/null", O_RDONLY)) > -1)
-					dup2(cur_fd, 1);
-
-				if ((cur_fd = open("/dev/null", O_RDONLY)) > -1)
-					dup2(cur_fd, 2);
-
-				break;
-
-			default:
-				exit(0);
-		}
-	}
-
-	/* server main loop */
-	uloop_run();
-
-#ifdef HAVE_LUA
-	/* destroy the Lua state */
-	if (conf.lua_state != NULL)
-		conf.lua_close(conf.lua_state);
-#endif
-
-#ifdef HAVE_UBUS
-	/* destroy the ubus state */
-	if (conf.ubus_state != NULL)
-		conf.ubus_close(conf.ubus_state);
-#endif
-
-	return 0;
-}

+ 0 - 214
package/network/services/uhttpd/src/uhttpd.h

@@ -1,214 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Main header
- *
- *   Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#ifndef _UHTTPD_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <linux/limits.h>
-#include <netdb.h>
-#include <ctype.h>
-#include <errno.h>
-#include <dlfcn.h>
-
-#include <libubox/list.h>
-#include <libubox/uloop.h>
-
-
-#ifdef HAVE_LUA
-#include <lua.h>
-#endif
-
-#ifdef HAVE_TLS
-#include <openssl/ssl.h>
-#endif
-
-/* uClibc... */
-#ifndef SOL_TCP
-#define SOL_TCP	6
-#endif
-
-#ifdef DEBUG
-#define D(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define D(...)
-#endif
-
-
-#define UH_LIMIT_MSGHEAD	4096
-#define UH_LIMIT_HEADERS	64
-#define UH_LIMIT_CLIENTS	64
-
-
-struct listener;
-struct client;
-struct interpreter;
-struct http_request;
-struct uh_ubus_state;
-
-struct config {
-	char docroot[PATH_MAX];
-	char *realm;
-	char *file;
-	char *index_file;
-	char *error_handler;
-	int no_symlinks;
-	int no_dirlists;
-	int network_timeout;
-	int rfc1918_filter;
-	int tcp_keepalive;
-	int max_requests;
-#ifdef HAVE_CGI
-	char *cgi_prefix;
-#endif
-#ifdef HAVE_LUA
-	char *lua_prefix;
-	char *lua_handler;
-	lua_State *lua_state;
-	lua_State * (*lua_init) (const struct config *conf);
-	void (*lua_close) (lua_State *L);
-	bool (*lua_request) (struct client *cl, lua_State *L);
-#endif
-#ifdef HAVE_UBUS
-	char *ubus_prefix;
-	char *ubus_socket;
-	void *ubus_state;
-	struct uh_ubus_state * (*ubus_init) (const struct config *conf);
-	void (*ubus_close) (struct uh_ubus_state *state);
-	bool (*ubus_request) (struct client *cl, struct uh_ubus_state *state);
-#endif
-#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS)
-	int script_timeout;
-#endif
-#ifdef HAVE_TLS
-	char *cert;
-	char *key;
-	SSL_CTX *tls;
-	SSL_CTX * (*tls_init) (void);
-	int (*tls_cert) (SSL_CTX *c, const char *file);
-	int (*tls_key) (SSL_CTX *c, const char *file);
-	void (*tls_free) (struct listener *l);
-	int (*tls_accept) (struct client *c);
-	void (*tls_close) (struct client *c);
-	int (*tls_recv) (struct client *c, char *buf, int len);
-	int (*tls_send) (struct client *c, const char *buf, int len);
-#endif
-};
-
-enum http_method {
-	UH_HTTP_MSG_GET,
-	UH_HTTP_MSG_POST,
-	UH_HTTP_MSG_HEAD,
-};
-
-extern const char *http_methods[];
-
-enum http_version {
-	UH_HTTP_VER_0_9,
-	UH_HTTP_VER_1_0,
-	UH_HTTP_VER_1_1,
-};
-
-extern const char *http_versions[];
-
-struct http_request {
-	enum http_method method;
-	enum http_version version;
-	int redirect_status;
-	char *url;
-	char *headers[UH_LIMIT_HEADERS];
-	struct auth_realm *realm;
-};
-
-struct http_response {
-	int statuscode;
-	char *statusmsg;
-	char *headers[UH_LIMIT_HEADERS];
-};
-
-struct listener {
-	struct uloop_fd fd;
-	int socket;
-	int n_clients;
-	struct sockaddr_in6 addr;
-	struct config *conf;
-#ifdef HAVE_TLS
-	SSL_CTX *tls;
-#endif
-	struct listener *next;
-};
-
-struct client {
-#ifdef HAVE_TLS
-	SSL *tls;
-#endif
-	struct uloop_fd fd;
-	struct uloop_fd rpipe;
-	struct uloop_fd wpipe;
-	struct uloop_process proc;
-	struct uloop_timeout timeout;
-	bool (*cb)(struct client *);
-	void *priv;
-	bool dispatched;
-	struct {
-		char buf[UH_LIMIT_MSGHEAD];
-		char *ptr;
-		int len;
-	} httpbuf;
-	struct listener *server;
-	struct http_request request;
-	struct http_response response;
-	struct sockaddr_in6 servaddr;
-	struct sockaddr_in6 peeraddr;
-	struct client *next;
-};
-
-struct client_light {
-#ifdef HAVE_TLS
-	SSL *tls;
-#endif
-	struct uloop_fd fd;
-};
-
-struct auth_realm {
-	char path[PATH_MAX];
-	char user[32];
-	char pass[128];
-	struct auth_realm *next;
-};
-
-#ifdef HAVE_CGI
-struct interpreter {
-	char path[PATH_MAX];
-	char extn[32];
-	struct interpreter *next;
-};
-#endif
-
-#endif