[package] uhttpd: various fixes
[openwrt.git] / package / uhttpd / src / uhttpd-cgi.c
index aa79478..e527922 100644 (file)
@@ -128,8 +128,6 @@ static char * uh_cgi_header_lookup(struct http_response *res,
 
 static void uh_cgi_shutdown(struct uh_cgi_state *state)
 {
-       close(state->rfd);
-       close(state->wfd);
        free(state);
 }
 
@@ -139,38 +137,36 @@ static bool uh_cgi_socket_cb(struct client *cl)
        char buf[UH_LIMIT_MSGHEAD];
 
        struct uh_cgi_state *state = (struct uh_cgi_state *)cl->priv;
-       struct http_response *res = &state->cl->response;
-       struct http_request *req = &state->cl->request;
+       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 (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",
-                         state->cl->proc.pid, len);
+                       D("CGI: Child(%d) feed %d HTTP buffer bytes\n", cl->proc.pid, len);
 
-                       memcpy(buf, state->cl->httpbuf.ptr, len);
+                       memcpy(buf, cl->httpbuf.ptr, len);
 
-                       state->cl->httpbuf.len -= len;
-                       state->cl->httpbuf.ptr +=len;
+                       cl->httpbuf.len -= len;
+                       cl->httpbuf.ptr +=len;
                }
 
                /* read it from socket ... */
                else
                {
-                       len = uh_tcp_recv(state->cl, buf,
+                       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",
-                         state->cl->proc.pid, len,
-                         min(state->content_length, sizeof(buf)));
+                         cl->proc.pid, len, min(state->content_length, sizeof(buf)));
                }
 
                if (len)
@@ -179,16 +175,16 @@ static bool uh_cgi_socket_cb(struct client *cl)
                        state->content_length = 0;
 
                /* ... 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);
 
                /* explicit EOF notification for the child */
                if (state->content_length <= 0)
-                       close(state->wfd);
+                       uh_ufd_remove(&cl->wpipe);
        }
 
        /* 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 */
                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))
                        {
                                /* write status */
-                               ensure_out(uh_http_sendf(state->cl, NULL,
+                               ensure_out(uh_http_sendf(cl, NULL,
                                        "HTTP/%.1f %03d %s\r\n"
                                        "Connection: close\r\n",
                                        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") &&
                                        !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));
                                }
 
@@ -216,19 +212,19 @@ static bool uh_cgi_socket_cb(struct client *cl)
                                if ((req->version > 1.0) &&
                                        !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));
                                }
 
                                /* write headers from CGI program */
                                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]));
                                }
 
                                /* 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;
 
@@ -236,9 +232,9 @@ static bool uh_cgi_socket_cb(struct client *cl)
                                if (hdroff < len)
                                {
                                        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));
                                }
                        }
@@ -257,7 +253,7 @@ static bool uh_cgi_socket_cb(struct client *cl)
                                 * 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"
                                                                                 "Content-Type: text/plain\r\n"
                                                                                 "%s\r\n",
@@ -268,18 +264,16 @@ static bool uh_cgi_socket_cb(struct client *cl)
                                state->header_sent = true;
 
                                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
                {
                        /* headers complete, pass through buffer to socket */
-                       D("CGI: Child(%d) relaying %d normal bytes\n",
-                         state->cl->proc.pid, len);
-
-                       ensure_out(uh_http_send(state->cl, req, buf, len));
+                       D("CGI: Child(%d) relaying %d normal bytes\n", cl->proc.pid, len);
+                       ensure_out(uh_http_send(cl, req, buf, len));
                }
        }
 
@@ -287,8 +281,7 @@ static bool uh_cgi_socket_cb(struct client *cl)
        if ((len == 0) ||
                ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1)))
        {
-               D("CGI: Child(%d) presumed dead [%s]\n",
-                 state->cl->proc.pid, strerror(errno));
+               D("CGI: Child(%d) presumed dead [%s]\n", cl->proc.pid, strerror(errno));
 
                goto out;
        }
@@ -298,17 +291,17 @@ static bool uh_cgi_socket_cb(struct client *cl)
 out:
        if (!state->header_sent)
        {
-               if (state->cl->timeout.pending)
-                       uh_http_sendhf(state->cl, 502, "Bad Gateway",
+               if (cl->timeout.pending)
+                       uh_http_sendhf(cl, 502, "Bad Gateway",
                                                   "The CGI process did not produce any response\n");
                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 "
                                                   "response\n");
        }
        else
        {
-               uh_http_send(state->cl, req, "", 0);
+               uh_http_send(cl, req, "", 0);
        }
 
        uh_cgi_shutdown(state);
@@ -529,9 +522,13 @@ bool uh_cgi_request(struct client *cl, struct path_info *pi,
        default:
                memset(state, 0, sizeof(*state));
 
-               state->cl = cl;
-               state->cl->pipe.fd = rfd[0];
-               state->cl->proc.pid = child;
+               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]);
@@ -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->priv = state;