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
lede-17.01
Jo-Philipp Wich 2012-07-13 17:10:56 +00:00
parent abc3d9493b
commit 00f1b1d62a
8 changed files with 127 additions and 140 deletions

View File

@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=uhttpd PKG_NAME:=uhttpd
PKG_RELEASE:=39 PKG_RELEASE:=40
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PKG_CONFIG_DEPENDS := \ PKG_CONFIG_DEPENDS := \

View File

@ -201,9 +201,10 @@ static bool uh_cgi_socket_cb(struct client *cl)
{ {
/* write status */ /* write status */
ensure_out(uh_http_sendf(cl, NULL, ensure_out(uh_http_sendf(cl, NULL,
"HTTP/%.1f %03d %s\r\n" "%s %03d %s\r\n"
"Connection: close\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 */ /* add Content-Type if no Location or Content-Type */
if (!uh_cgi_header_lookup(res, "Location") && 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 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")) !uh_cgi_header_lookup(res, "Transfer-Encoding"))
{ {
ensure_out(uh_http_send(cl, NULL, 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, ensure_out(uh_http_sendf(cl, NULL,
"HTTP/%.1f 200 OK\r\n" "%s 200 OK\r\n"
"Content-Type: text/plain\r\n" "Content-Type: text/plain\r\n"
"%s\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" : "" ? "Transfer-Encoding: chunked\r\n" : ""
)); ));
@ -427,26 +429,10 @@ bool uh_cgi_request(struct client *cl, struct path_info *pi,
} }
/* http version */ /* http version */
if (req->version > 1.0) setenv("SERVER_PROTOCOL", http_versions[req->version], 1);
setenv("SERVER_PROTOCOL", "HTTP/1.1", 1);
else
setenv("SERVER_PROTOCOL", "HTTP/1.0", 1);
/* request method */ /* request method */
switch (req->method) setenv("REQUEST_METHOD", http_methods[req->method], 1);
{
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;
}
/* request url */ /* request url */
setenv("REQUEST_URI", req->url, 1); setenv("REQUEST_URI", req->url, 1);

View File

@ -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) 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", ensure_ret(uh_http_sendf(cl, NULL, "%s 200 OK\r\n",
cl->request.version)); http_versions[cl->request.version]));
return uh_file_response_ok_hdrs(cl, s); return uh_file_response_ok_hdrs(cl, s);
} }
static int uh_file_response_304(struct client *cl, struct stat *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", ensure_ret(uh_http_sendf(cl, NULL, "%s 304 Not Modified\r\n",
cl->request.version)); http_versions[cl->request.version]));
return uh_file_response_ok_hdrs(cl, s); 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) static int uh_file_response_412(struct client *cl)
{ {
return uh_http_sendf(cl, NULL, return uh_http_sendf(cl, NULL,
"HTTP/%.1f 412 Precondition Failed\r\n" "%s 412 Precondition Failed\r\n"
"Connection: close\r\n", cl->request.version); "Connection: close\r\n",
http_versions[cl->request.version]);
} }
static int uh_file_if_match(struct client *cl, struct stat *s, int *ok) static int uh_file_if_match(struct client *cl, struct stat *s, int *ok)

View File

@ -66,7 +66,7 @@ static int uh_lua_recv(lua_State *L)
return 1; 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; size_t length;
@ -112,12 +112,12 @@ out:
static int uh_lua_send(lua_State *L) 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) 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)) 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); lua_newtable(L);
/* request method */ /* request method */
switch(req->method) lua_pushstring(L, http_methods[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_setfield(L, -2, "REQUEST_METHOD"); lua_setfield(L, -2, "REQUEST_METHOD");
/* request url */ /* request url */
@ -462,14 +448,10 @@ bool uh_lua_request(struct client *cl, lua_State *L)
} }
/* http protcol version */ /* 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"); lua_setfield(L, -2, "HTTP_VERSION");
if (req->version > 1.0) lua_pushstring(L, http_versions[req->version]);
lua_pushstring(L, "HTTP/1.1");
else
lua_pushstring(L, "HTTP/1.0");
lua_setfield(L, -2, "SERVER_PROTOCOL"); lua_setfield(L, -2, "SERVER_PROTOCOL");
@ -529,12 +511,13 @@ bool uh_lua_request(struct client *cl, lua_State *L)
if (! err_str) if (! err_str)
err_str = "Unknown error"; 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" "Connection: close\r\n"
"Content-Type: text/plain\r\n" "Content-Type: text/plain\r\n"
"Content-Length: %i\r\n\r\n" "Content-Length: %i\r\n\r\n"
"Lua raised a runtime error:\n %s\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; break;

View File

@ -334,7 +334,7 @@ int uh_http_sendf(struct client *cl, struct http_request *req,
len = vsnprintf(buffer, sizeof(buffer), fmt, ap); len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(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)); ensure_ret(uh_http_sendc(cl, buffer, len));
else if (len > 0) else if (len > 0)
ensure_ret(uh_tcp_send(cl, buffer, len)); 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) if (len < 0)
len = strlen(buf); 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)); ensure_ret(uh_http_sendc(cl, buf, len));
else if (len > 0) else if (len > 0)
ensure_ret(uh_tcp_send(cl, buf, len)); ensure_ret(uh_tcp_send(cl, buf, len));
@ -865,13 +865,13 @@ int uh_auth_check(struct client *cl, struct http_request *req,
/* 401 */ /* 401 */
uh_http_sendf(cl, NULL, uh_http_sendf(cl, NULL,
"HTTP/%.1f 401 Authorization Required\r\n" "%s 401 Authorization Required\r\n"
"WWW-Authenticate: Basic realm=\"%s\"\r\n" "WWW-Authenticate: Basic realm=\"%s\"\r\n"
"Content-Type: text/plain\r\n" "Content-Type: text/plain\r\n"
"Content-Length: 23\r\n\r\n" "Content-Length: 23\r\n\r\n"
"Authorization Required\n", "Authorization Required\n",
req->version, cl->server->conf->realm http_versions[req->version],
); cl->server->conf->realm);
return 0; 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; struct client *new = NULL;
socklen_t sl; 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) if ((new = (struct client *)malloc(sizeof(struct client))) != NULL)
{ {
memset(new, 0, sizeof(struct client)); memset(new, 0, sizeof(struct client));
memcpy(&new->peeraddr, peer, sizeof(new->peeraddr));
new->fd.fd = sock; new->fd.fd = sock;
new->server = serv; new->server = serv;
@ -937,14 +939,8 @@ struct client * uh_client_add(int sock, struct listener *serv)
new->rpipe.fd = -1; new->rpipe.fd = -1;
new->wpipe.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 */ /* get local endpoint addr */
sl = sizeof(struct sockaddr_in6); sl = sizeof(struct sockaddr_in6);
memset(&(new->servaddr), 0, sl);
getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl); getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
new->next = uh_clients; 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) for (cur = uh_clients; cur; prv = cur, cur = cur->next)
{ {
if ((cur == cl) || (!cl && cur->dead)) if (cur == cl)
{ {
if (prv) if (prv)
prv->next = cur->next; prv->next = cur->next;

View File

@ -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_add(int sock, struct config *conf);
struct listener * uh_listener_lookup(int sock); 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); struct client * uh_client_lookup(int sock);
#define uh_client_error(cl, code, status, ...) do { \ #define uh_client_error(cl, code, status, ...) do { \

View File

@ -35,6 +35,9 @@
#endif #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 int run = 1;
static void uh_sigterm(int sig) static void uh_sigterm(int sig)
@ -123,8 +126,7 @@ static void uh_config_parse(struct config *conf)
static void uh_listener_cb(struct uloop_fd *u, unsigned int events); static void uh_listener_cb(struct uloop_fd *u, unsigned int events);
static int uh_socket_bind(fd_set *serv_fds, int *max_fd, static int uh_socket_bind(const char *host, const char *port,
const char *host, const char *port,
struct addrinfo *hints, int do_tls, struct addrinfo *hints, int do_tls,
struct config *conf) struct config *conf)
{ {
@ -213,11 +215,8 @@ static int uh_socket_bind(fd_set *serv_fds, int *max_fd,
l->tls = do_tls ? conf->tls : NULL; l->tls = do_tls ? conf->tls : NULL;
#endif #endif
/* add socket to server fd set */ /* add socket to uloop */
FD_SET(sock, serv_fds);
fd_cloexec(sock); fd_cloexec(sock);
*max_fd = max(*max_fd, sock);
uh_ufd_add(&l->fd, uh_listener_cb, ULOOP_READ); uh_ufd_add(&l->fd, uh_listener_cb, ULOOP_READ);
bound++; bound++;
@ -268,29 +267,18 @@ static struct http_request * uh_http_header_parse(struct client *cl,
/* check method */ /* 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 */ /* invalid method */
uh_http_response(cl, 405, "Method Not Allowed"); uh_http_response(cl, 405, "Method Not Allowed");
return NULL; 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 */ /* check path */
if (!path || !strlen(path)) if (!path || !strlen(path))
@ -305,22 +293,21 @@ static struct http_request * uh_http_header_parse(struct client *cl,
} }
/* check version */ /* check version */
if ((version == NULL) || (strcmp(version, "HTTP/0.9") && if (version && !strcmp(version, "HTTP/0.9"))
strcmp(version, "HTTP/1.0") && strcmp(version, "HTTP/1.1"))) 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 */ /* unsupported version */
uh_http_response(cl, 400, "Bad Request"); uh_http_response(cl, 400, "Bad Request");
return NULL; return NULL;
} }
else
{
req->version = strtof(&version[5], NULL);
}
D("SRV: %s %s HTTP/%.1f\n", D("SRV: %s %s %s\n",
(req->method == UH_HTTP_MSG_POST) ? "POST" : http_methods[req->method], req->url, http_versions[req->version]);
(req->method == UH_HTTP_MSG_GET) ? "GET" : "HEAD",
req->url, req->version);
/* process header fields */ /* process header fields */
for (i = (int)(headers - buffer); i < buflen; i++) 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 client *cl;
struct config *conf; struct config *conf;
struct sockaddr_in6 sa;
socklen_t sl = sizeof(sa);
serv = container_of(u, struct listener, fd); serv = container_of(u, struct listener, fd);
conf = serv->conf; conf = serv->conf;
@ -530,12 +520,12 @@ static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
return; return;
/* handle new connections */ /* 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); D("SRV: Server(%d) accept => Client(%d)\n", u->fd, new_fd);
/* add to global client list */ /* 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 */ /* add client socket to global fdset */
uh_ufd_add(&cl->fd, uh_socket_cb, ULOOP_READ); 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) int main (int argc, char **argv)
{ {
/* master file descriptor list */
fd_set serv_fds;
/* working structs */ /* working structs */
struct addrinfo hints; struct addrinfo hints;
struct sigaction sa; struct sigaction sa;
struct config conf; struct config conf;
/* maximum file descriptor number */ /* maximum file descriptor number */
int cur_fd, max_fd = 0; int cur_fd = 0;
#ifdef HAVE_TLS #ifdef HAVE_TLS
int tls = 0; int tls = 0;
@ -806,16 +793,14 @@ int main (int argc, char **argv)
/* args */ /* args */
int opt; int opt;
char bind[128]; char addr[128];
char *port = NULL; char *port = NULL;
#ifdef HAVE_LUA #if defined(HAVE_LUA) || defined(HAVE_TLS) || defined(HAVE_UBUS)
/* library handle */ /* library handle */
void *lib; void *lib;
#endif #endif
FD_ZERO(&serv_fds);
/* handle SIGPIPE, SIGINT, SIGTERM */ /* handle SIGPIPE, SIGINT, SIGTERM */
sa.sa_flags = 0; sa.sa_flags = 0;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -835,7 +820,6 @@ int main (int argc, char **argv)
/* parse args */ /* parse args */
memset(&conf, 0, sizeof(conf)); memset(&conf, 0, sizeof(conf));
memset(bind, 0, sizeof(bind));
uloop_init(); uloop_init();
@ -847,14 +831,16 @@ int main (int argc, char **argv)
/* [addr:]port */ /* [addr:]port */
case 'p': case 'p':
case 's': case 's':
memset(addr, 0, sizeof(addr));
if ((port = strrchr(optarg, ':')) != NULL) if ((port = strrchr(optarg, ':')) != NULL)
{ {
if ((optarg[0] == '[') && (port > optarg) && (port[-1] == ']')) if ((optarg[0] == '[') && (port > optarg) && (port[-1] == ']'))
memcpy(bind, optarg + 1, memcpy(addr, optarg + 1,
min(sizeof(bind), (int)(port - optarg) - 2)); min(sizeof(addr), (int)(port - optarg) - 2));
else else
memcpy(bind, optarg, memcpy(addr, optarg,
min(sizeof(bind), (int)(port - optarg))); min(sizeof(addr), (int)(port - optarg)));
port++; port++;
} }
@ -880,11 +866,8 @@ int main (int argc, char **argv)
#endif #endif
/* bind sockets */ /* bind sockets */
bound += uh_socket_bind(&serv_fds, &max_fd, bound += uh_socket_bind(addr[0] ? addr : NULL, port, &hints,
bind[0] ? bind : NULL, (opt == 's'), &conf);
port, &hints, (opt == 's'), &conf);
memset(bind, 0, sizeof(bind));
break; break;
#ifdef HAVE_TLS #ifdef HAVE_TLS
@ -919,6 +902,13 @@ int main (int argc, char **argv)
} }
break; break;
#else
case 'C':
case 'K':
fprintf(stderr,
"Notice: TLS support not compiled, ignoring -%c\n",
opt);
break;
#endif #endif
/* docroot */ /* docroot */
@ -991,6 +981,13 @@ int main (int argc, char **argv)
exit(1); exit(1);
} }
break; break;
#else
case 'x':
case 'i':
fprintf(stderr,
"Notice: CGI support not compiled, ignoring -%c\n",
opt);
break;
#endif #endif
#ifdef HAVE_LUA #ifdef HAVE_LUA
@ -1003,6 +1000,13 @@ int main (int argc, char **argv)
case 'L': case 'L':
conf.lua_handler = optarg; conf.lua_handler = optarg;
break; break;
#else
case 'l':
case 'L':
fprintf(stderr,
"Notice: Lua support not compiled, ignoring -%c\n",
opt);
break;
#endif #endif
#ifdef HAVE_UBUS #ifdef HAVE_UBUS
@ -1015,6 +1019,13 @@ int main (int argc, char **argv)
case 'U': case 'U':
conf.ubus_socket = optarg; conf.ubus_socket = optarg;
break; break;
#else
case 'u':
case 'U':
fprintf(stderr,
"Notice: UBUS support not compiled, ignoring -%c\n",
opt);
break;
#endif #endif
#if defined(HAVE_CGI) || defined(HAVE_LUA) #if defined(HAVE_CGI) || defined(HAVE_LUA)

View File

@ -63,15 +63,8 @@
#define UH_LIMIT_MSGHEAD 4096 #define UH_LIMIT_MSGHEAD 4096
#define UH_LIMIT_HEADERS 64 #define UH_LIMIT_HEADERS 64
#define UH_LIMIT_CLIENTS 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 listener;
struct client; struct client;
@ -128,9 +121,25 @@ struct config {
#endif #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 { struct http_request {
int method; enum http_method method;
float version; enum http_version version;
int redirect_status; int redirect_status;
char *url; char *url;
char *headers[UH_LIMIT_HEADERS]; char *headers[UH_LIMIT_HEADERS];
@ -167,7 +176,6 @@ struct client {
bool (*cb)(struct client *); bool (*cb)(struct client *);
void *priv; void *priv;
bool dispatched; bool dispatched;
bool dead;
struct { struct {
char buf[UH_LIMIT_MSGHEAD]; char buf[UH_LIMIT_MSGHEAD];
char *ptr; char *ptr;