summaryrefslogtreecommitdiff
path: root/package/uhttpd/src
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-10-10 12:32:29 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-10-10 12:32:29 +0000
commit9c8997d54dc9df184bfcedeabf0b3c85cf5e6753 (patch)
tree46b83031a0da1b4458317413c00d13c252c72afa /package/uhttpd/src
parenteecf5b17520f6b3b6ffb45ac7dca298d93b27501 (diff)
packages: sort network related packages into package/network/
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33688 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/uhttpd/src')
-rw-r--r--package/uhttpd/src/Makefile89
-rw-r--r--package/uhttpd/src/uhttpd-cgi.c556
-rw-r--r--package/uhttpd/src/uhttpd-cgi.h43
-rw-r--r--package/uhttpd/src/uhttpd-file.c438
-rw-r--r--package/uhttpd/src/uhttpd-file.h36
-rw-r--r--package/uhttpd/src/uhttpd-lua.c579
-rw-r--r--package/uhttpd/src/uhttpd-lua.h44
-rw-r--r--package/uhttpd/src/uhttpd-mimetypes.h86
-rw-r--r--package/uhttpd/src/uhttpd-tls.c170
-rw-r--r--package/uhttpd/src/uhttpd-tls.h36
-rw-r--r--package/uhttpd/src/uhttpd-ubus.c957
-rw-r--r--package/uhttpd/src/uhttpd-ubus.h70
-rw-r--r--package/uhttpd/src/uhttpd-utils.c1081
-rw-r--r--package/uhttpd/src/uhttpd-utils.h140
-rw-r--r--package/uhttpd/src/uhttpd.c1288
-rw-r--r--package/uhttpd/src/uhttpd.h214
16 files changed, 0 insertions, 5827 deletions
diff --git a/package/uhttpd/src/Makefile b/package/uhttpd/src/Makefile
deleted file mode 100644
index 98226ed206..0000000000
--- a/package/uhttpd/src/Makefile
+++ /dev/null
@@ -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
diff --git a/package/uhttpd/src/uhttpd-cgi.c b/package/uhttpd/src/uhttpd-cgi.c
deleted file mode 100644
index 69af90db45..0000000000
--- a/package/uhttpd/src/uhttpd-cgi.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - CGI handler
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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;
-}
diff --git a/package/uhttpd/src/uhttpd-cgi.h b/package/uhttpd/src/uhttpd-cgi.h
deleted file mode 100644
index c7094da424..0000000000
--- a/package/uhttpd/src/uhttpd-cgi.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - CGI header
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c
deleted file mode 100644
index 0bafc2b38c..0000000000
--- a/package/uhttpd/src/uhttpd-file.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Static file handler
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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;
-}
diff --git a/package/uhttpd/src/uhttpd-file.h b/package/uhttpd/src/uhttpd-file.h
deleted file mode 100644
index 08dbe2cf9a..0000000000
--- a/package/uhttpd/src/uhttpd-file.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Static file header
- *
- * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd-lua.c b/package/uhttpd/src/uhttpd-lua.c
deleted file mode 100644
index e113937399..0000000000
--- a/package/uhttpd/src/uhttpd-lua.c
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Lua handler
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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);
-}
diff --git a/package/uhttpd/src/uhttpd-lua.h b/package/uhttpd/src/uhttpd-lua.h
deleted file mode 100644
index 780d845d87..0000000000
--- a/package/uhttpd/src/uhttpd-lua.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Lua header
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd-mimetypes.h b/package/uhttpd/src/uhttpd-mimetypes.h
deleted file mode 100644
index 21717c0003..0000000000
--- a/package/uhttpd/src/uhttpd-mimetypes.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - MIME type definitions
- *
- * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
-
diff --git a/package/uhttpd/src/uhttpd-tls.c b/package/uhttpd/src/uhttpd-tls.c
deleted file mode 100644
index 9c6eb81db3..0000000000
--- a/package/uhttpd/src/uhttpd-tls.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - TLS helper
- *
- * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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;
- }
-}
diff --git a/package/uhttpd/src/uhttpd-tls.h b/package/uhttpd/src/uhttpd-tls.h
deleted file mode 100644
index 8644c2ac5d..0000000000
--- a/package/uhttpd/src/uhttpd-tls.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - TLS header
- *
- * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd-ubus.c b/package/uhttpd/src/uhttpd-ubus.c
deleted file mode 100644
index 20781629ba..0000000000
--- a/package/uhttpd/src/uhttpd-ubus.c
+++ /dev/null
@@ -1,957 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - ubus handler
- *
- * Copyright (C) 2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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);
-}
diff --git a/package/uhttpd/src/uhttpd-ubus.h b/package/uhttpd/src/uhttpd-ubus.h
deleted file mode 100644
index 777ce27fd3..0000000000
--- a/package/uhttpd/src/uhttpd-ubus.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - ubus header
- *
- * Copyright (C) 2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c
deleted file mode 100644
index c8d3bb40f4..0000000000
--- a/package/uhttpd/src/uhttpd-utils.c
+++ /dev/null
@@ -1,1081 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Utility functions
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h
deleted file mode 100644
index 9de9191948..0000000000
--- a/package/uhttpd/src/uhttpd-utils.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Utility header
- *
- * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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
diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c
deleted file mode 100644
index 1efcbf0f51..0000000000
--- a/package/uhttpd/src/uhttpd.c
+++ /dev/null
@@ -1,1288 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Main component
- *
- * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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;
-}
diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h
deleted file mode 100644
index f6982db323..0000000000
--- a/package/uhttpd/src/uhttpd.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * uhttpd - Tiny single-threaded httpd - Main header
- *
- * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
- *
- * 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