From 00f1b1d62abc566e394d8b4dbf1d7580ffe3321f Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 13 Jul 2012 17:10:56 +0000 Subject: [PATCH] uhttpd: various changes - remove unused variables - simply ignore command line args which belong to not enabled features - resolve peer address at accept() time, should solve (#11850) - remove floating point operations where possible SVN-Revision: 32704 --- package/uhttpd/Makefile | 2 +- package/uhttpd/src/uhttpd-cgi.c | 32 +++----- package/uhttpd/src/uhttpd-file.c | 13 ++-- package/uhttpd/src/uhttpd-lua.c | 35 +++------ package/uhttpd/src/uhttpd-utils.c | 30 ++++---- package/uhttpd/src/uhttpd-utils.h | 4 +- package/uhttpd/src/uhttpd.c | 123 ++++++++++++++++-------------- package/uhttpd/src/uhttpd.h | 28 ++++--- 8 files changed, 127 insertions(+), 140 deletions(-) diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile index cefd30bb8c..245426b4e2 100644 --- a/package/uhttpd/Makefile +++ b/package/uhttpd/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uhttpd -PKG_RELEASE:=39 +PKG_RELEASE:=40 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_CONFIG_DEPENDS := \ diff --git a/package/uhttpd/src/uhttpd-cgi.c b/package/uhttpd/src/uhttpd-cgi.c index b46ebf2bdd..69af90db45 100644 --- a/package/uhttpd/src/uhttpd-cgi.c +++ b/package/uhttpd/src/uhttpd-cgi.c @@ -201,9 +201,10 @@ static bool uh_cgi_socket_cb(struct client *cl) { /* write status */ ensure_out(uh_http_sendf(cl, NULL, - "HTTP/%.1f %03d %s\r\n" + "%s %03d %s\r\n" "Connection: close\r\n", - req->version, res->statuscode, res->statusmsg)); + http_versions[req->version], + res->statuscode, res->statusmsg)); /* add Content-Type if no Location or Content-Type */ if (!uh_cgi_header_lookup(res, "Location") && @@ -214,7 +215,7 @@ static bool uh_cgi_socket_cb(struct client *cl) } /* if request was HTTP 1.1 we'll respond chunked */ - if ((req->version > 1.0) && + if ((req->version > UH_HTTP_VER_1_0) && !uh_cgi_header_lookup(res, "Transfer-Encoding")) { ensure_out(uh_http_send(cl, NULL, @@ -260,10 +261,11 @@ static bool uh_cgi_socket_cb(struct client *cl) */ ensure_out(uh_http_sendf(cl, NULL, - "HTTP/%.1f 200 OK\r\n" + "%s 200 OK\r\n" "Content-Type: text/plain\r\n" "%s\r\n", - req->version, (req->version > 1.0) + http_versions[req->version], + (req->version > UH_HTTP_VER_1_0) ? "Transfer-Encoding: chunked\r\n" : "" )); @@ -427,26 +429,10 @@ bool uh_cgi_request(struct client *cl, struct path_info *pi, } /* http version */ - if (req->version > 1.0) - setenv("SERVER_PROTOCOL", "HTTP/1.1", 1); - else - setenv("SERVER_PROTOCOL", "HTTP/1.0", 1); + setenv("SERVER_PROTOCOL", http_versions[req->version], 1); /* request method */ - switch (req->method) - { - case UH_HTTP_MSG_GET: - setenv("REQUEST_METHOD", "GET", 1); - break; - - case UH_HTTP_MSG_HEAD: - setenv("REQUEST_METHOD", "HEAD", 1); - break; - - case UH_HTTP_MSG_POST: - setenv("REQUEST_METHOD", "POST", 1); - break; - } + setenv("REQUEST_METHOD", http_methods[req->method], 1); /* request url */ setenv("REQUEST_URI", req->url, 1); diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c index 2e5914a3c0..0bafc2b38c 100644 --- a/package/uhttpd/src/uhttpd-file.c +++ b/package/uhttpd/src/uhttpd-file.c @@ -113,16 +113,16 @@ static int uh_file_response_ok_hdrs(struct client *cl, struct stat *s) static int uh_file_response_200(struct client *cl, struct stat *s) { - ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", - cl->request.version)); + 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, "HTTP/%.1f 304 Not Modified\r\n", - cl->request.version)); + 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); } @@ -130,8 +130,9 @@ static int uh_file_response_304(struct client *cl, struct stat *s) static int uh_file_response_412(struct client *cl) { return uh_http_sendf(cl, NULL, - "HTTP/%.1f 412 Precondition Failed\r\n" - "Connection: close\r\n", cl->request.version); + "%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) diff --git a/package/uhttpd/src/uhttpd-lua.c b/package/uhttpd/src/uhttpd-lua.c index 94626bb56b..e113937399 100644 --- a/package/uhttpd/src/uhttpd-lua.c +++ b/package/uhttpd/src/uhttpd-lua.c @@ -66,7 +66,7 @@ static int uh_lua_recv(lua_State *L) return 1; } -static int uh_lua_send_common(lua_State *L, int chunked) +static int uh_lua_send_common(lua_State *L, bool chunked) { size_t length; @@ -112,12 +112,12 @@ out: static int uh_lua_send(lua_State *L) { - return uh_lua_send_common(L, 0); + return uh_lua_send_common(L, false); } static int uh_lua_sendc(lua_State *L) { - return uh_lua_send_common(L, 1); + return uh_lua_send_common(L, true); } static int uh_lua_str2str(lua_State *L, int (*xlate_func) (char *, int, const char *, int)) @@ -414,21 +414,7 @@ bool uh_lua_request(struct client *cl, lua_State *L) lua_newtable(L); /* request method */ - switch(req->method) - { - case UH_HTTP_MSG_GET: - lua_pushstring(L, "GET"); - break; - - case UH_HTTP_MSG_HEAD: - lua_pushstring(L, "HEAD"); - break; - - case UH_HTTP_MSG_POST: - lua_pushstring(L, "POST"); - break; - } - + lua_pushstring(L, http_methods[req->method]); lua_setfield(L, -2, "REQUEST_METHOD"); /* request url */ @@ -462,14 +448,10 @@ bool uh_lua_request(struct client *cl, lua_State *L) } /* http protcol version */ - lua_pushnumber(L, floor(req->version * 10) / 10); + lua_pushnumber(L, 0.9 + (req->version / 10.0)); lua_setfield(L, -2, "HTTP_VERSION"); - if (req->version > 1.0) - lua_pushstring(L, "HTTP/1.1"); - else - lua_pushstring(L, "HTTP/1.0"); - + lua_pushstring(L, http_versions[req->version]); lua_setfield(L, -2, "SERVER_PROTOCOL"); @@ -529,12 +511,13 @@ bool uh_lua_request(struct client *cl, lua_State *L) if (! err_str) err_str = "Unknown error"; - printf("HTTP/%.1f 500 Internal Server Error\r\n" + 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", - req->version, 31 + strlen(err_str), err_str); + http_versions[req->version], + 31 + strlen(err_str), err_str); break; diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c index 50b10e6050..c8d3bb40f4 100644 --- a/package/uhttpd/src/uhttpd-utils.c +++ b/package/uhttpd/src/uhttpd-utils.c @@ -334,7 +334,7 @@ int uh_http_sendf(struct client *cl, struct http_request *req, len = vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); - if ((req != NULL) && (req->version > 1.0)) + 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)); @@ -348,7 +348,7 @@ int uh_http_send(struct client *cl, struct http_request *req, if (len < 0) len = strlen(buf); - if ((req != NULL) && (req->version > 1.0)) + 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)); @@ -865,13 +865,13 @@ int uh_auth_check(struct client *cl, struct http_request *req, /* 401 */ uh_http_sendf(cl, NULL, - "HTTP/%.1f 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", - req->version, cl->server->conf->realm - ); + "%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; } @@ -922,7 +922,8 @@ struct listener * uh_listener_lookup(int sock) } -struct client * uh_client_add(int sock, struct listener *serv) +struct client * uh_client_add(int sock, struct listener *serv, + struct sockaddr_in6 *peer) { struct client *new = NULL; socklen_t sl; @@ -930,6 +931,7 @@ struct client * uh_client_add(int sock, struct listener *serv) 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; @@ -937,14 +939,8 @@ struct client * uh_client_add(int sock, struct listener *serv) new->rpipe.fd = -1; new->wpipe.fd = -1; - /* get remote endpoint addr */ - sl = sizeof(struct sockaddr_in6); - memset(&(new->peeraddr), 0, sl); - getpeername(sock, (struct sockaddr *) &(new->peeraddr), &sl); - /* get local endpoint addr */ sl = sizeof(struct sockaddr_in6); - memset(&(new->servaddr), 0, sl); getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl); new->next = uh_clients; @@ -988,7 +984,7 @@ void uh_client_remove(struct client *cl) for (cur = uh_clients; cur; prv = cur, cur = cur->next) { - if ((cur == cl) || (!cl && cur->dead)) + if (cur == cl) { if (prv) prv->next = cur->next; diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h index 31047f5554..9de9191948 100644 --- a/package/uhttpd/src/uhttpd-utils.h +++ b/package/uhttpd/src/uhttpd-utils.h @@ -115,7 +115,9 @@ 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 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 { \ diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c index 9e5a574263..1efcbf0f51 100644 --- a/package/uhttpd/src/uhttpd.c +++ b/package/uhttpd/src/uhttpd.c @@ -35,6 +35,9 @@ #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) @@ -123,10 +126,9 @@ static void uh_config_parse(struct config *conf) static void uh_listener_cb(struct uloop_fd *u, unsigned int events); -static int uh_socket_bind(fd_set *serv_fds, int *max_fd, - const char *host, const char *port, - struct addrinfo *hints, int do_tls, - struct config *conf) +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; @@ -213,11 +215,8 @@ static int uh_socket_bind(fd_set *serv_fds, int *max_fd, l->tls = do_tls ? conf->tls : NULL; #endif - /* add socket to server fd set */ - FD_SET(sock, serv_fds); + /* add socket to uloop */ fd_cloexec(sock); - *max_fd = max(*max_fd, sock); - uh_ufd_add(&l->fd, uh_listener_cb, ULOOP_READ); bound++; @@ -268,29 +267,18 @@ static struct http_request * uh_http_header_parse(struct client *cl, /* check method */ - if (strcmp(method, "GET") && strcmp(method, "HEAD") && strcmp(method, "POST")) + 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; } - else - { - switch(method[0]) - { - case 'G': - req->method = UH_HTTP_MSG_GET; - break; - - case 'H': - req->method = UH_HTTP_MSG_HEAD; - break; - - case 'P': - req->method = UH_HTTP_MSG_POST; - break; - } - } /* check path */ if (!path || !strlen(path)) @@ -305,22 +293,21 @@ static struct http_request * uh_http_header_parse(struct client *cl, } /* check version */ - if ((version == NULL) || (strcmp(version, "HTTP/0.9") && - strcmp(version, "HTTP/1.0") && strcmp(version, "HTTP/1.1"))) + 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; } - else - { - req->version = strtof(&version[5], NULL); - } - D("SRV: %s %s HTTP/%.1f\n", - (req->method == UH_HTTP_MSG_POST) ? "POST" : - (req->method == UH_HTTP_MSG_GET) ? "GET" : "HEAD", - req->url, req->version); + 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++) @@ -522,6 +509,9 @@ static void uh_listener_cb(struct uloop_fd *u, unsigned int events) 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; @@ -530,12 +520,12 @@ static void uh_listener_cb(struct uloop_fd *u, unsigned int events) return; /* handle new connections */ - if ((new_fd = accept(u->fd, NULL, 0)) != -1) + 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)) != NULL) + 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); @@ -785,16 +775,13 @@ static inline int uh_inittls(struct config *conf) int main (int argc, char **argv) { - /* master file descriptor list */ - fd_set serv_fds; - /* working structs */ struct addrinfo hints; struct sigaction sa; struct config conf; /* maximum file descriptor number */ - int cur_fd, max_fd = 0; + int cur_fd = 0; #ifdef HAVE_TLS int tls = 0; @@ -806,16 +793,14 @@ int main (int argc, char **argv) /* args */ int opt; - char bind[128]; + char addr[128]; char *port = NULL; -#ifdef HAVE_LUA +#if defined(HAVE_LUA) || defined(HAVE_TLS) || defined(HAVE_UBUS) /* library handle */ void *lib; #endif - FD_ZERO(&serv_fds); - /* handle SIGPIPE, SIGINT, SIGTERM */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); @@ -835,7 +820,6 @@ int main (int argc, char **argv) /* parse args */ memset(&conf, 0, sizeof(conf)); - memset(bind, 0, sizeof(bind)); uloop_init(); @@ -847,14 +831,16 @@ int main (int argc, char **argv) /* [addr:]port */ case 'p': case 's': + memset(addr, 0, sizeof(addr)); + if ((port = strrchr(optarg, ':')) != NULL) { if ((optarg[0] == '[') && (port > optarg) && (port[-1] == ']')) - memcpy(bind, optarg + 1, - min(sizeof(bind), (int)(port - optarg) - 2)); + memcpy(addr, optarg + 1, + min(sizeof(addr), (int)(port - optarg) - 2)); else - memcpy(bind, optarg, - min(sizeof(bind), (int)(port - optarg))); + memcpy(addr, optarg, + min(sizeof(addr), (int)(port - optarg))); port++; } @@ -880,11 +866,8 @@ int main (int argc, char **argv) #endif /* bind sockets */ - bound += uh_socket_bind(&serv_fds, &max_fd, - bind[0] ? bind : NULL, - port, &hints, (opt == 's'), &conf); - - memset(bind, 0, sizeof(bind)); + bound += uh_socket_bind(addr[0] ? addr : NULL, port, &hints, + (opt == 's'), &conf); break; #ifdef HAVE_TLS @@ -919,6 +902,13 @@ int main (int argc, char **argv) } break; +#else + case 'C': + case 'K': + fprintf(stderr, + "Notice: TLS support not compiled, ignoring -%c\n", + opt); + break; #endif /* docroot */ @@ -991,6 +981,13 @@ int main (int argc, char **argv) exit(1); } break; +#else + case 'x': + case 'i': + fprintf(stderr, + "Notice: CGI support not compiled, ignoring -%c\n", + opt); + break; #endif #ifdef HAVE_LUA @@ -1003,6 +1000,13 @@ int main (int argc, char **argv) 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 @@ -1015,6 +1019,13 @@ int main (int argc, char **argv) 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) diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h index fe86b01d40..f6982db323 100644 --- a/package/uhttpd/src/uhttpd.h +++ b/package/uhttpd/src/uhttpd.h @@ -63,15 +63,8 @@ #define UH_LIMIT_MSGHEAD 4096 #define UH_LIMIT_HEADERS 64 - #define UH_LIMIT_CLIENTS 64 -#define UH_HTTP_MSG_GET 0 -#define UH_HTTP_MSG_HEAD 1 -#define UH_HTTP_MSG_POST 2 - -#define UH_SOCK_CLIENT 0 -#define UH_SOCK_SERVER 1 struct listener; struct client; @@ -128,9 +121,25 @@ struct config { #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 { - int method; - float version; + enum http_method method; + enum http_version version; int redirect_status; char *url; char *headers[UH_LIMIT_HEADERS]; @@ -167,7 +176,6 @@ struct client { bool (*cb)(struct client *); void *priv; bool dispatched; - bool dead; struct { char buf[UH_LIMIT_MSGHEAD]; char *ptr;