mirror of https://github.com/hak5/openwrt-owl.git
uhttpd: various fixes
- avoid closing descriptors before removing them from uloop (#11755, #11830) - do not auto-initialize ubus if no prefix is set (#11832) - remove extraneous client context pointer from cgi and lua states - code cleanups and debug message changes SVN-Revision: 32651owl
parent
1f1cf1990b
commit
86de034767
|
@ -8,7 +8,7 @@
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=uhttpd
|
PKG_NAME:=uhttpd
|
||||||
PKG_RELEASE:=37
|
PKG_RELEASE:=38
|
||||||
|
|
||||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||||
PKG_CONFIG_DEPENDS := \
|
PKG_CONFIG_DEPENDS := \
|
||||||
|
|
|
@ -128,8 +128,6 @@ static char * uh_cgi_header_lookup(struct http_response *res,
|
||||||
|
|
||||||
static void uh_cgi_shutdown(struct uh_cgi_state *state)
|
static void uh_cgi_shutdown(struct uh_cgi_state *state)
|
||||||
{
|
{
|
||||||
close(state->rfd);
|
|
||||||
close(state->wfd);
|
|
||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,38 +137,36 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
char buf[UH_LIMIT_MSGHEAD];
|
char buf[UH_LIMIT_MSGHEAD];
|
||||||
|
|
||||||
struct uh_cgi_state *state = (struct uh_cgi_state *)cl->priv;
|
struct uh_cgi_state *state = (struct uh_cgi_state *)cl->priv;
|
||||||
struct http_response *res = &state->cl->response;
|
struct http_response *res = &cl->response;
|
||||||
struct http_request *req = &state->cl->request;
|
struct http_request *req = &cl->request;
|
||||||
|
|
||||||
/* there is unread post data waiting */
|
/* there is unread post data waiting */
|
||||||
while (state->content_length > 0)
|
while (state->content_length > 0)
|
||||||
{
|
{
|
||||||
/* remaining data in http head buffer ... */
|
/* remaining data in http head buffer ... */
|
||||||
if (state->cl->httpbuf.len > 0)
|
if (cl->httpbuf.len > 0)
|
||||||
{
|
{
|
||||||
len = min(state->content_length, state->cl->httpbuf.len);
|
len = min(state->content_length, cl->httpbuf.len);
|
||||||
|
|
||||||
D("CGI: Child(%d) feed %d HTTP buffer bytes\n",
|
D("CGI: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
|
||||||
state->cl->proc.pid, len);
|
|
||||||
|
|
||||||
memcpy(buf, state->cl->httpbuf.ptr, len);
|
memcpy(buf, cl->httpbuf.ptr, len);
|
||||||
|
|
||||||
state->cl->httpbuf.len -= len;
|
cl->httpbuf.len -= len;
|
||||||
state->cl->httpbuf.ptr +=len;
|
cl->httpbuf.ptr +=len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read it from socket ... */
|
/* read it from socket ... */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = uh_tcp_recv(state->cl, buf,
|
len = uh_tcp_recv(cl, buf,
|
||||||
min(state->content_length, sizeof(buf)));
|
min(state->content_length, sizeof(buf)));
|
||||||
|
|
||||||
if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
|
if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
D("CGI: Child(%d) feed %d/%d TCP socket bytes\n",
|
D("CGI: Child(%d) feed %d/%d TCP socket bytes\n",
|
||||||
state->cl->proc.pid, len,
|
cl->proc.pid, len, min(state->content_length, sizeof(buf)));
|
||||||
min(state->content_length, sizeof(buf)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len)
|
if (len)
|
||||||
|
@ -179,16 +175,16 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
state->content_length = 0;
|
state->content_length = 0;
|
||||||
|
|
||||||
/* ... write to CGI process */
|
/* ... write to CGI process */
|
||||||
len = uh_raw_send(state->wfd, buf, len,
|
len = uh_raw_send(cl->wpipe.fd, buf, len,
|
||||||
cl->server->conf->script_timeout);
|
cl->server->conf->script_timeout);
|
||||||
|
|
||||||
/* explicit EOF notification for the child */
|
/* explicit EOF notification for the child */
|
||||||
if (state->content_length <= 0)
|
if (state->content_length <= 0)
|
||||||
close(state->wfd);
|
uh_ufd_remove(&cl->wpipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to read data from child */
|
/* try to read data from child */
|
||||||
while ((len = uh_raw_recv(state->rfd, buf, sizeof(buf), -1)) > 0)
|
while ((len = uh_raw_recv(cl->rpipe.fd, buf, sizeof(buf), -1)) > 0)
|
||||||
{
|
{
|
||||||
/* we have not pushed out headers yet, parse input */
|
/* we have not pushed out headers yet, parse input */
|
||||||
if (!state->header_sent)
|
if (!state->header_sent)
|
||||||
|
@ -199,7 +195,7 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
if (uh_cgi_header_parse(res, state->httpbuf, len, &hdroff))
|
if (uh_cgi_header_parse(res, state->httpbuf, len, &hdroff))
|
||||||
{
|
{
|
||||||
/* write status */
|
/* write status */
|
||||||
ensure_out(uh_http_sendf(state->cl, NULL,
|
ensure_out(uh_http_sendf(cl, NULL,
|
||||||
"HTTP/%.1f %03d %s\r\n"
|
"HTTP/%.1f %03d %s\r\n"
|
||||||
"Connection: close\r\n",
|
"Connection: close\r\n",
|
||||||
req->version, res->statuscode, res->statusmsg));
|
req->version, res->statuscode, res->statusmsg));
|
||||||
|
@ -208,7 +204,7 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
if (!uh_cgi_header_lookup(res, "Location") &&
|
if (!uh_cgi_header_lookup(res, "Location") &&
|
||||||
!uh_cgi_header_lookup(res, "Content-Type"))
|
!uh_cgi_header_lookup(res, "Content-Type"))
|
||||||
{
|
{
|
||||||
ensure_out(uh_http_send(state->cl, NULL,
|
ensure_out(uh_http_send(cl, NULL,
|
||||||
"Content-Type: text/plain\r\n", -1));
|
"Content-Type: text/plain\r\n", -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,19 +212,19 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
if ((req->version > 1.0) &&
|
if ((req->version > 1.0) &&
|
||||||
!uh_cgi_header_lookup(res, "Transfer-Encoding"))
|
!uh_cgi_header_lookup(res, "Transfer-Encoding"))
|
||||||
{
|
{
|
||||||
ensure_out(uh_http_send(state->cl, NULL,
|
ensure_out(uh_http_send(cl, NULL,
|
||||||
"Transfer-Encoding: chunked\r\n", -1));
|
"Transfer-Encoding: chunked\r\n", -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write headers from CGI program */
|
/* write headers from CGI program */
|
||||||
foreach_header(i, res->headers)
|
foreach_header(i, res->headers)
|
||||||
{
|
{
|
||||||
ensure_out(uh_http_sendf(state->cl, NULL, "%s: %s\r\n",
|
ensure_out(uh_http_sendf(cl, NULL, "%s: %s\r\n",
|
||||||
res->headers[i], res->headers[i+1]));
|
res->headers[i], res->headers[i+1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* terminate header */
|
/* terminate header */
|
||||||
ensure_out(uh_http_send(state->cl, NULL, "\r\n", -1));
|
ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
|
||||||
|
|
||||||
state->header_sent = true;
|
state->header_sent = true;
|
||||||
|
|
||||||
|
@ -236,9 +232,9 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
if (hdroff < len)
|
if (hdroff < len)
|
||||||
{
|
{
|
||||||
D("CGI: Child(%d) relaying %d rest bytes\n",
|
D("CGI: Child(%d) relaying %d rest bytes\n",
|
||||||
state->cl->proc.pid, len - hdroff);
|
cl->proc.pid, len - hdroff);
|
||||||
|
|
||||||
ensure_out(uh_http_send(state->cl, req,
|
ensure_out(uh_http_send(cl, req,
|
||||||
&buf[hdroff], len - hdroff));
|
&buf[hdroff], len - hdroff));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,7 +253,7 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
* build the required headers here.
|
* build the required headers here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ensure_out(uh_http_sendf(state->cl, NULL,
|
ensure_out(uh_http_sendf(cl, NULL,
|
||||||
"HTTP/%.1f 200 OK\r\n"
|
"HTTP/%.1f 200 OK\r\n"
|
||||||
"Content-Type: text/plain\r\n"
|
"Content-Type: text/plain\r\n"
|
||||||
"%s\r\n",
|
"%s\r\n",
|
||||||
|
@ -268,18 +264,16 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
state->header_sent = true;
|
state->header_sent = true;
|
||||||
|
|
||||||
D("CGI: Child(%d) relaying %d invalid bytes\n",
|
D("CGI: Child(%d) relaying %d invalid bytes\n",
|
||||||
state->cl->proc.pid, len);
|
cl->proc.pid, len);
|
||||||
|
|
||||||
ensure_out(uh_http_send(state->cl, req, buf, len));
|
ensure_out(uh_http_send(cl, req, buf, len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* headers complete, pass through buffer to socket */
|
/* headers complete, pass through buffer to socket */
|
||||||
D("CGI: Child(%d) relaying %d normal bytes\n",
|
D("CGI: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
|
||||||
state->cl->proc.pid, len);
|
ensure_out(uh_http_send(cl, req, buf, len));
|
||||||
|
|
||||||
ensure_out(uh_http_send(state->cl, req, buf, len));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,8 +281,7 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
if ((len == 0) ||
|
if ((len == 0) ||
|
||||||
((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
|
((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
|
||||||
{
|
{
|
||||||
D("CGI: Child(%d) presumed dead [%s]\n",
|
D("CGI: Child(%d) presumed dead [%s]\n", cl->proc.pid, strerror(errno));
|
||||||
state->cl->proc.pid, strerror(errno));
|
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -298,17 +291,17 @@ static bool uh_cgi_socket_cb(struct client *cl)
|
||||||
out:
|
out:
|
||||||
if (!state->header_sent)
|
if (!state->header_sent)
|
||||||
{
|
{
|
||||||
if (state->cl->timeout.pending)
|
if (cl->timeout.pending)
|
||||||
uh_http_sendhf(state->cl, 502, "Bad Gateway",
|
uh_http_sendhf(cl, 502, "Bad Gateway",
|
||||||
"The CGI process did not produce any response\n");
|
"The CGI process did not produce any response\n");
|
||||||
else
|
else
|
||||||
uh_http_sendhf(state->cl, 504, "Gateway Timeout",
|
uh_http_sendhf(cl, 504, "Gateway Timeout",
|
||||||
"The CGI process took too long to produce a "
|
"The CGI process took too long to produce a "
|
||||||
"response\n");
|
"response\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uh_http_send(state->cl, req, "", 0);
|
uh_http_send(cl, req, "", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uh_cgi_shutdown(state);
|
uh_cgi_shutdown(state);
|
||||||
|
@ -529,9 +522,13 @@ bool uh_cgi_request(struct client *cl, struct path_info *pi,
|
||||||
default:
|
default:
|
||||||
memset(state, 0, sizeof(*state));
|
memset(state, 0, sizeof(*state));
|
||||||
|
|
||||||
state->cl = cl;
|
cl->rpipe.fd = rfd[0];
|
||||||
state->cl->pipe.fd = rfd[0];
|
cl->wpipe.fd = wfd[1];
|
||||||
state->cl->proc.pid = child;
|
cl->proc.pid = child;
|
||||||
|
|
||||||
|
/* make pipe non-blocking */
|
||||||
|
fd_nonblock(cl->rpipe.fd);
|
||||||
|
fd_nonblock(cl->wpipe.fd);
|
||||||
|
|
||||||
/* close unneeded pipe ends */
|
/* close unneeded pipe ends */
|
||||||
close(rfd[1]);
|
close(rfd[1]);
|
||||||
|
@ -554,12 +551,6 @@ bool uh_cgi_request(struct client *cl, struct path_info *pi,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state->rfd = rfd[0];
|
|
||||||
fd_nonblock(state->rfd);
|
|
||||||
|
|
||||||
state->wfd = wfd[1];
|
|
||||||
fd_nonblock(state->wfd);
|
|
||||||
|
|
||||||
cl->cb = uh_cgi_socket_cb;
|
cl->cb = uh_cgi_socket_cb;
|
||||||
cl->priv = state;
|
cl->priv = state;
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
|
|
||||||
|
|
||||||
struct uh_cgi_state {
|
struct uh_cgi_state {
|
||||||
int rfd;
|
|
||||||
int wfd;
|
|
||||||
struct client *cl;
|
|
||||||
char httpbuf[UH_LIMIT_MSGHEAD];
|
char httpbuf[UH_LIMIT_MSGHEAD];
|
||||||
int content_length;
|
int content_length;
|
||||||
bool header_sent;
|
bool header_sent;
|
||||||
|
|
|
@ -250,8 +250,6 @@ lua_State * uh_lua_init(const struct config *conf)
|
||||||
|
|
||||||
static void uh_lua_shutdown(struct uh_lua_state *state)
|
static void uh_lua_shutdown(struct uh_lua_state *state)
|
||||||
{
|
{
|
||||||
close(state->rfd);
|
|
||||||
close(state->wfd);
|
|
||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,31 +264,28 @@ static bool uh_lua_socket_cb(struct client *cl)
|
||||||
while (state->content_length > 0)
|
while (state->content_length > 0)
|
||||||
{
|
{
|
||||||
/* remaining data in http head buffer ... */
|
/* remaining data in http head buffer ... */
|
||||||
if (state->cl->httpbuf.len > 0)
|
if (cl->httpbuf.len > 0)
|
||||||
{
|
{
|
||||||
len = min(state->content_length, state->cl->httpbuf.len);
|
len = min(state->content_length, cl->httpbuf.len);
|
||||||
|
|
||||||
D("Lua: Child(%d) feed %d HTTP buffer bytes\n",
|
D("Lua: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
|
||||||
state->cl->proc.pid, len);
|
|
||||||
|
|
||||||
memcpy(buf, state->cl->httpbuf.ptr, len);
|
memcpy(buf, cl->httpbuf.ptr, len);
|
||||||
|
|
||||||
state->cl->httpbuf.len -= len;
|
cl->httpbuf.len -= len;
|
||||||
state->cl->httpbuf.ptr += len;
|
cl->httpbuf.ptr += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read it from socket ... */
|
/* read it from socket ... */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = uh_tcp_recv(state->cl, buf,
|
len = uh_tcp_recv(cl, buf, min(state->content_length, sizeof(buf)));
|
||||||
min(state->content_length, sizeof(buf)));
|
|
||||||
|
|
||||||
if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
|
if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
D("Lua: Child(%d) feed %d/%d TCP socket bytes\n",
|
D("Lua: Child(%d) feed %d/%d TCP socket bytes\n",
|
||||||
state->cl->proc.pid, len,
|
cl->proc.pid, len, min(state->content_length, sizeof(buf)));
|
||||||
min(state->content_length, sizeof(buf)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len)
|
if (len)
|
||||||
|
@ -299,20 +294,20 @@ static bool uh_lua_socket_cb(struct client *cl)
|
||||||
state->content_length = 0;
|
state->content_length = 0;
|
||||||
|
|
||||||
/* ... write to Lua process */
|
/* ... write to Lua process */
|
||||||
len = uh_raw_send(state->wfd, buf, len,
|
len = uh_raw_send(cl->wpipe.fd, buf, len,
|
||||||
cl->server->conf->script_timeout);
|
cl->server->conf->script_timeout);
|
||||||
|
|
||||||
/* explicit EOF notification for the child */
|
/* explicit EOF notification for the child */
|
||||||
if (state->content_length <= 0)
|
if (state->content_length <= 0)
|
||||||
close(state->wfd);
|
uh_ufd_remove(&cl->wpipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to read data from child */
|
/* try to read data from child */
|
||||||
while ((len = uh_raw_recv(state->rfd, buf, sizeof(buf), -1)) > 0)
|
while ((len = uh_raw_recv(cl->rpipe.fd, buf, sizeof(buf), -1)) > 0)
|
||||||
{
|
{
|
||||||
/* pass through buffer to socket */
|
/* pass through buffer to socket */
|
||||||
D("Lua: Child(%d) relaying %d normal bytes\n", state->cl->proc.pid, len);
|
D("Lua: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
|
||||||
ensure_out(uh_tcp_send(state->cl, buf, len));
|
ensure_out(uh_tcp_send(cl, buf, len));
|
||||||
state->data_sent = true;
|
state->data_sent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +316,7 @@ static bool uh_lua_socket_cb(struct client *cl)
|
||||||
((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
|
((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
|
||||||
{
|
{
|
||||||
D("Lua: Child(%d) presumed dead [%s]\n",
|
D("Lua: Child(%d) presumed dead [%s]\n",
|
||||||
state->cl->proc.pid, strerror(errno));
|
cl->proc.pid, strerror(errno));
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -331,11 +326,11 @@ static bool uh_lua_socket_cb(struct client *cl)
|
||||||
out:
|
out:
|
||||||
if (!state->data_sent)
|
if (!state->data_sent)
|
||||||
{
|
{
|
||||||
if (state->cl->timeout.pending)
|
if (cl->timeout.pending)
|
||||||
uh_http_sendhf(state->cl, 502, "Bad Gateway",
|
uh_http_sendhf(cl, 502, "Bad Gateway",
|
||||||
"The Lua process did not produce any response\n");
|
"The Lua process did not produce any response\n");
|
||||||
else
|
else
|
||||||
uh_http_sendhf(state->cl, 504, "Gateway Timeout",
|
uh_http_sendhf(cl, 504, "Gateway Timeout",
|
||||||
"The Lua process took too long to produce a "
|
"The Lua process took too long to produce a "
|
||||||
"response\n");
|
"response\n");
|
||||||
}
|
}
|
||||||
|
@ -557,9 +552,13 @@ bool uh_lua_request(struct client *cl, lua_State *L)
|
||||||
default:
|
default:
|
||||||
memset(state, 0, sizeof(*state));
|
memset(state, 0, sizeof(*state));
|
||||||
|
|
||||||
state->cl = cl;
|
cl->rpipe.fd = rfd[0];
|
||||||
state->cl->pipe.fd = rfd[0];
|
cl->wpipe.fd = wfd[1];
|
||||||
state->cl->proc.pid = child;
|
cl->proc.pid = child;
|
||||||
|
|
||||||
|
/* make pipe non-blocking */
|
||||||
|
fd_nonblock(cl->rpipe.fd);
|
||||||
|
fd_nonblock(cl->wpipe.fd);
|
||||||
|
|
||||||
/* close unneeded pipe ends */
|
/* close unneeded pipe ends */
|
||||||
close(rfd[1]);
|
close(rfd[1]);
|
||||||
|
@ -582,12 +581,6 @@ bool uh_lua_request(struct client *cl, lua_State *L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state->rfd = rfd[0];
|
|
||||||
fd_nonblock(state->rfd);
|
|
||||||
|
|
||||||
state->wfd = wfd[1];
|
|
||||||
fd_nonblock(state->wfd);
|
|
||||||
|
|
||||||
cl->cb = uh_lua_socket_cb;
|
cl->cb = uh_lua_socket_cb;
|
||||||
cl->priv = state;
|
cl->priv = state;
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,6 @@
|
||||||
|
|
||||||
|
|
||||||
struct uh_lua_state {
|
struct uh_lua_state {
|
||||||
int rfd;
|
|
||||||
int wfd;
|
|
||||||
struct client *cl;
|
|
||||||
char httpbuf[UH_LIMIT_MSGHEAD];
|
char httpbuf[UH_LIMIT_MSGHEAD];
|
||||||
int content_length;
|
int content_length;
|
||||||
bool data_sent;
|
bool data_sent;
|
||||||
|
|
|
@ -119,7 +119,7 @@ bool uh_socket_wait(int fd, int sec, bool write)
|
||||||
while (((rv = select(fd+1, write ? NULL : &fds, write ? &fds : NULL,
|
while (((rv = select(fd+1, write ? NULL : &fds, write ? &fds : NULL,
|
||||||
NULL, &timeout)) < 0) && (errno == EINTR))
|
NULL, &timeout)) < 0) && (errno == EINTR))
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) select interrupted: %s\n",
|
D("IO: FD(%d) select interrupted: %s\n",
|
||||||
fd, strerror(errno));
|
fd, strerror(errno));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -127,7 +127,7 @@ bool uh_socket_wait(int fd, int sec, bool write)
|
||||||
|
|
||||||
if (rv <= 0)
|
if (rv <= 0)
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) appears dead (rv=%d)\n", fd, rv);
|
D("IO: FD(%d) appears dead (rv=%d)\n", fd, rv);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec,
|
||||||
{
|
{
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) interrupted\n", cl->fd.fd);
|
D("IO: FD(%d) interrupted\n", cl->fd.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
|
else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||||
|
@ -156,7 +156,7 @@ static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) write error: %s\n", fd, strerror(errno));
|
D("IO: FD(%d) write error: %s\n", fd, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,19 +168,19 @@ static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec,
|
||||||
*/
|
*/
|
||||||
else if (rv == 0)
|
else if (rv == 0)
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) closed\n", fd);
|
D("IO: FD(%d) appears closed\n", fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (rv < len)
|
else if (rv < len)
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) short write %d/%d bytes\n", fd, rv, len);
|
D("IO: FD(%d) short write %d/%d bytes\n", fd, rv, len);
|
||||||
len -= rv;
|
len -= rv;
|
||||||
buf += rv;
|
buf += rv;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) sent %d/%d bytes\n", fd, rv, len);
|
D("IO: FD(%d) sent %d/%d bytes\n", fd, rv, len);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,18 +230,18 @@ static int __uh_raw_recv(struct client *cl, char *buf, int len, int sec,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) read error: %s\n", fd, strerror(errno));
|
D("IO: FD(%d) read error: %s\n", fd, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rv == 0)
|
else if (rv == 0)
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) closed\n", fd);
|
D("IO: FD(%d) appears closed\n", fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D("IO: Socket(%d) read %d bytes\n", fd, rv);
|
D("IO: FD(%d) read %d bytes\n", fd, rv);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -934,6 +934,9 @@ struct client * uh_client_add(int sock, struct listener *serv)
|
||||||
new->fd.fd = sock;
|
new->fd.fd = sock;
|
||||||
new->server = serv;
|
new->server = serv;
|
||||||
|
|
||||||
|
new->rpipe.fd = -1;
|
||||||
|
new->wpipe.fd = -1;
|
||||||
|
|
||||||
/* get remote endpoint addr */
|
/* get remote endpoint addr */
|
||||||
sl = sizeof(struct sockaddr_in6);
|
sl = sizeof(struct sockaddr_in6);
|
||||||
memset(&(new->peeraddr), 0, sl);
|
memset(&(new->peeraddr), 0, sl);
|
||||||
|
@ -948,6 +951,8 @@ struct client * uh_client_add(int sock, struct listener *serv)
|
||||||
uh_clients = new;
|
uh_clients = new;
|
||||||
|
|
||||||
serv->n_clients++;
|
serv->n_clients++;
|
||||||
|
|
||||||
|
D("IO: Client(%d) allocated\n", new->fd.fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
|
@ -996,13 +1001,12 @@ void uh_client_remove(struct client *cl)
|
||||||
if (cur->proc.pid)
|
if (cur->proc.pid)
|
||||||
uloop_process_delete(&cur->proc);
|
uloop_process_delete(&cur->proc);
|
||||||
|
|
||||||
if (cur->pipe.fd)
|
D("IO: Client(%d) freeing\n", cur->fd.fd);
|
||||||
uloop_fd_delete(&cur->pipe);
|
|
||||||
|
|
||||||
uloop_fd_delete(&cur->fd);
|
uh_ufd_remove(&cur->rpipe);
|
||||||
close(cur->fd.fd);
|
uh_ufd_remove(&cur->wpipe);
|
||||||
|
uh_ufd_remove(&cur->fd);
|
||||||
|
|
||||||
D("IO: Socket(%d) closing\n", cur->fd.fd);
|
|
||||||
cur->server->n_clients--;
|
cur->server->n_clients--;
|
||||||
|
|
||||||
free(cur);
|
free(cur);
|
||||||
|
@ -1012,6 +1016,34 @@ void uh_client_remove(struct client *cl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
#ifdef HAVE_CGI
|
||||||
static struct interpreter *uh_interpreters = NULL;
|
static struct interpreter *uh_interpreters = NULL;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <libubox/uloop.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_SHADOW
|
#ifdef HAVE_SHADOW
|
||||||
#include <shadow.h>
|
#include <shadow.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -123,7 +126,8 @@ struct client * uh_client_lookup(int sock);
|
||||||
void uh_client_shutdown(struct client *cl);
|
void uh_client_shutdown(struct client *cl);
|
||||||
void uh_client_remove(struct client *cl);
|
void uh_client_remove(struct client *cl);
|
||||||
|
|
||||||
#define uh_client_gc() uh_client_remove(NULL)
|
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
|
#ifdef HAVE_CGI
|
||||||
|
|
|
@ -218,8 +218,7 @@ static int uh_socket_bind(fd_set *serv_fds, int *max_fd,
|
||||||
fd_cloexec(sock);
|
fd_cloexec(sock);
|
||||||
*max_fd = max(*max_fd, sock);
|
*max_fd = max(*max_fd, sock);
|
||||||
|
|
||||||
l->fd.cb = uh_listener_cb;
|
uh_ufd_add(&l->fd, uh_listener_cb, ULOOP_READ);
|
||||||
uloop_fd_add(&l->fd, ULOOP_READ);
|
|
||||||
|
|
||||||
bound++;
|
bound++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -514,7 +513,7 @@ static bool uh_dispatch_request(struct client *cl, struct http_request *req)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uh_client_cb(struct uloop_fd *u, unsigned int events);
|
static void uh_socket_cb(struct uloop_fd *u, unsigned int events);
|
||||||
|
|
||||||
static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
|
static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
|
||||||
{
|
{
|
||||||
|
@ -539,7 +538,8 @@ static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
|
||||||
if ((cl = uh_client_add(new_fd, serv)) != NULL)
|
if ((cl = uh_client_add(new_fd, serv)) != NULL)
|
||||||
{
|
{
|
||||||
/* add client socket to global fdset */
|
/* add client socket to global fdset */
|
||||||
uloop_fd_add(&cl->fd, ULOOP_READ);
|
uh_ufd_add(&cl->fd, uh_socket_cb, ULOOP_READ);
|
||||||
|
fd_cloexec(cl->fd.fd);
|
||||||
|
|
||||||
#ifdef HAVE_TLS
|
#ifdef HAVE_TLS
|
||||||
/* setup client tls context */
|
/* setup client tls context */
|
||||||
|
@ -555,9 +555,6 @@ static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cl->fd.cb = uh_client_cb;
|
|
||||||
fd_cloexec(new_fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* insufficient resources */
|
/* insufficient resources */
|
||||||
|
@ -569,28 +566,33 @@ static void uh_listener_cb(struct uloop_fd *u, unsigned int events)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uh_pipe_cb(struct uloop_fd *u, unsigned int events)
|
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, pipe);
|
struct client *cl = container_of(u, struct client, rpipe);
|
||||||
|
|
||||||
if (!u->error)
|
D("SRV: Client(%d) rpipe readable\n", cl->fd.fd);
|
||||||
{
|
|
||||||
D("SRV: Client(%d) pipe(%d) readable\n",
|
|
||||||
cl->fd.fd, cl->pipe.fd);
|
|
||||||
|
|
||||||
uh_client_cb(&cl->fd, ULOOP_WRITE);
|
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)
|
static void uh_child_cb(struct uloop_process *p, int rv)
|
||||||
{
|
{
|
||||||
struct client *cl = container_of(p, struct client, proc);
|
struct client *cl = container_of(p, struct client, proc);
|
||||||
|
|
||||||
D("SRV: Client(%d) child(%d) is dead\n", cl->fd.fd, cl->proc.pid);
|
D("SRV: Client(%d) child(%d) dead\n", cl->fd.fd, cl->proc.pid);
|
||||||
|
|
||||||
cl->dead = true;
|
uh_client_cb(cl, ULOOP_READ | ULOOP_WRITE);
|
||||||
cl->fd.eof = true;
|
|
||||||
uh_client_cb(&cl->fd, ULOOP_READ | ULOOP_WRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uh_kill9_cb(struct uloop_timeout *t)
|
static void uh_kill9_cb(struct uloop_timeout *t)
|
||||||
|
@ -624,17 +626,15 @@ static void uh_timeout_cb(struct uloop_timeout *t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uh_client_cb(struct uloop_fd *u, unsigned int events)
|
static void uh_client_cb(struct client *cl, unsigned int events)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct client *cl;
|
|
||||||
struct config *conf;
|
struct config *conf;
|
||||||
struct http_request *req;
|
struct http_request *req;
|
||||||
|
|
||||||
cl = container_of(u, struct client, fd);
|
|
||||||
conf = cl->server->conf;
|
conf = cl->server->conf;
|
||||||
|
|
||||||
D("SRV: Client(%d) enter callback\n", u->fd);
|
D("SRV: Client(%d) enter callback\n", cl->fd.fd);
|
||||||
|
|
||||||
/* undispatched yet */
|
/* undispatched yet */
|
||||||
if (!cl->dispatched)
|
if (!cl->dispatched)
|
||||||
|
@ -642,14 +642,14 @@ static void uh_client_cb(struct uloop_fd *u, unsigned int events)
|
||||||
/* we have no headers yet and this was a write event, ignore... */
|
/* we have no headers yet and this was a write event, ignore... */
|
||||||
if (!(events & ULOOP_READ))
|
if (!(events & ULOOP_READ))
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) ignoring write event before headers\n", u->fd);
|
D("SRV: Client(%d) ignoring write event before headers\n", cl->fd.fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* attempt to receive and parse headers */
|
/* attempt to receive and parse headers */
|
||||||
if (!(req = uh_http_header_recv(cl)))
|
if (!(req = uh_http_header_recv(cl)))
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) failed to receive header\n", u->fd);
|
D("SRV: Client(%d) failed to receive header\n", cl->fd.fd);
|
||||||
uh_client_shutdown(cl);
|
uh_client_shutdown(cl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -663,7 +663,7 @@ static void uh_client_cb(struct uloop_fd *u, unsigned int events)
|
||||||
if (strcasecmp(req->headers[i+1], "100-continue"))
|
if (strcasecmp(req->headers[i+1], "100-continue"))
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) unknown expect header (%s)\n",
|
D("SRV: Client(%d) unknown expect header (%s)\n",
|
||||||
u->fd, req->headers[i+1]);
|
cl->fd.fd, req->headers[i+1]);
|
||||||
|
|
||||||
uh_http_response(cl, 417, "Precondition Failed");
|
uh_http_response(cl, 417, "Precondition Failed");
|
||||||
uh_client_shutdown(cl);
|
uh_client_shutdown(cl);
|
||||||
|
@ -671,7 +671,7 @@ static void uh_client_cb(struct uloop_fd *u, unsigned int events)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) sending HTTP/1.1 100 Continue\n", u->fd);
|
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");
|
uh_http_sendf(cl, NULL, "HTTP/1.1 100 Continue\r\n\r\n");
|
||||||
cl->httpbuf.len = 0; /* client will re-send the body */
|
cl->httpbuf.len = 0; /* client will re-send the body */
|
||||||
|
@ -694,24 +694,23 @@ static void uh_client_cb(struct uloop_fd *u, unsigned int events)
|
||||||
/* dispatch request */
|
/* dispatch request */
|
||||||
if (!uh_dispatch_request(cl, req))
|
if (!uh_dispatch_request(cl, req))
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) failed to dispach request\n", u->fd);
|
D("SRV: Client(%d) failed to dispach request\n", cl->fd.fd);
|
||||||
uh_client_shutdown(cl);
|
uh_client_shutdown(cl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* request handler spawned a pipe, register handler */
|
/* request handler spawned a pipe, register handler */
|
||||||
if (cl->pipe.fd)
|
if (cl->rpipe.fd > -1)
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) pipe(%d) spawned\n", u->fd, cl->pipe.fd);
|
D("SRV: Client(%d) pipe(%d) spawned\n", cl->fd.fd, cl->rpipe.fd);
|
||||||
|
|
||||||
cl->pipe.cb = uh_pipe_cb;
|
uh_ufd_add(&cl->rpipe, uh_rpipe_cb, ULOOP_READ);
|
||||||
uloop_fd_add(&cl->pipe, ULOOP_READ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* request handler spawned a child, register handler */
|
/* request handler spawned a child, register handler */
|
||||||
if (cl->proc.pid)
|
if (cl->proc.pid)
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) child(%d) spawned\n", u->fd, cl->proc.pid);
|
D("SRV: Client(%d) child(%d) spawned\n", cl->fd.fd, cl->proc.pid);
|
||||||
|
|
||||||
cl->proc.cb = uh_child_cb;
|
cl->proc.cb = uh_child_cb;
|
||||||
uloop_process_add(&cl->proc);
|
uloop_process_add(&cl->proc);
|
||||||
|
@ -721,13 +720,13 @@ static void uh_client_cb(struct uloop_fd *u, unsigned int events)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* header processing complete */
|
/* header processing complete */
|
||||||
D("SRV: Client(%d) dispatched\n", u->fd);
|
D("SRV: Client(%d) dispatched\n", cl->fd.fd);
|
||||||
cl->dispatched = true;
|
cl->dispatched = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cl->cb(cl))
|
if (!cl->cb(cl))
|
||||||
{
|
{
|
||||||
D("SRV: Client(%d) response callback signalized EOF\n", u->fd);
|
D("SRV: Client(%d) response callback signalized EOF\n", cl->fd.fd);
|
||||||
uh_client_shutdown(cl);
|
uh_client_shutdown(cl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1098,7 +1097,7 @@ int main (int argc, char **argv)
|
||||||
" -L file Lua handler script, omit to disable Lua\n"
|
" -L file Lua handler script, omit to disable Lua\n"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UBUS
|
#ifdef HAVE_UBUS
|
||||||
" -u string URL prefix for HTTP/JSON handler, default is '/ubus'\n"
|
" -u string URL prefix for HTTP/JSON handler\n"
|
||||||
" -U file Override ubus socket path\n"
|
" -U file Override ubus socket path\n"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_CGI
|
#ifdef HAVE_CGI
|
||||||
|
@ -1210,7 +1209,7 @@ int main (int argc, char **argv)
|
||||||
"Notice: Unable to load ubus plugin - disabling ubus support! "
|
"Notice: Unable to load ubus plugin - disabling ubus support! "
|
||||||
"(Reason: %s)\n", dlerror());
|
"(Reason: %s)\n", dlerror());
|
||||||
}
|
}
|
||||||
else
|
else if (conf.ubus_prefix)
|
||||||
{
|
{
|
||||||
/* resolve functions */
|
/* resolve functions */
|
||||||
if (!(conf.ubus_init = dlsym(lib, "uh_ubus_init")) ||
|
if (!(conf.ubus_init = dlsym(lib, "uh_ubus_init")) ||
|
||||||
|
@ -1224,10 +1223,7 @@ int main (int argc, char **argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default ubus prefix */
|
/* initialize ubus */
|
||||||
if (!conf.ubus_prefix)
|
|
||||||
conf.ubus_prefix = "/ubus";
|
|
||||||
|
|
||||||
conf.ubus_state = conf.ubus_init(&conf);
|
conf.ubus_state = conf.ubus_init(&conf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -160,7 +160,8 @@ struct client {
|
||||||
SSL *tls;
|
SSL *tls;
|
||||||
#endif
|
#endif
|
||||||
struct uloop_fd fd;
|
struct uloop_fd fd;
|
||||||
struct uloop_fd pipe;
|
struct uloop_fd rpipe;
|
||||||
|
struct uloop_fd wpipe;
|
||||||
struct uloop_process proc;
|
struct uloop_process proc;
|
||||||
struct uloop_timeout timeout;
|
struct uloop_timeout timeout;
|
||||||
bool (*cb)(struct client *);
|
bool (*cb)(struct client *);
|
||||||
|
|
Loading…
Reference in New Issue