Date:2010-08-18 02:04:52 (2 years 9 months ago)
Author:jow
Commit:8618e98eabec2b5677698daa631f195cae92c30b
Message:[package] uhttpd:

- fix parsing of interpreter entries in the config file, fixes serving of static files as .cgi with X-Wrt
- better cope with connection aborts, especially during header transfer
- fix return value checking of TLS reads and writes, solves some blocking issues


git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22692 3c298f89-4303-0410-b956-a3cf2f4a3e73
Files: package/uhttpd/Makefile (1 diff)
package/uhttpd/src/uhttpd-cgi.c (12 diffs)
package/uhttpd/src/uhttpd-file.c (6 diffs)
package/uhttpd/src/uhttpd-tls.c (1 diff)
package/uhttpd/src/uhttpd-utils.c (7 diffs)
package/uhttpd/src/uhttpd-utils.h (1 diff)
package/uhttpd/src/uhttpd.c (5 diffs)
package/uhttpd/src/uhttpd.h (2 diffs)

Change Details

package/uhttpd/Makefile
88include $(TOPDIR)/rules.mk
99
1010PKG_NAME:=uhttpd
11PKG_RELEASE:=15
11PKG_RELEASE:=16
1212
1313PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
1414PKG_BUILD_DEPENDS := libcyassl liblua
package/uhttpd/src/uhttpd-cgi.c
139139    struct client *cl, struct http_request *req,
140140    struct path_info *pi, struct interpreter *ip
141141) {
142    int i, hdroff, bufoff;
142    int i, hdroff, bufoff, rv;
143143    int hdrlen = 0;
144144    int buflen = 0;
145145    int fd_max = 0;
...... 
376376
377377            memset(hdr, 0, sizeof(hdr));
378378
379            timeout.tv_sec = cl->server->conf->script_timeout;
380            timeout.tv_usec = 0;
381
382#define ensure(x) \
383    do { if( x < 0 ) goto out; } while(0)
384
385379            /* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */
386380            while( 1 )
387381            {
...... 
391385                FD_SET(rfd[0], &reader);
392386                FD_SET(wfd[1], &writer);
393387
388                timeout.tv_sec = (header_sent < 1) ? cl->server->conf->script_timeout : 3;
389                timeout.tv_usec = 0;
390
391                ensure_out(rv = select_intr(fd_max, &reader,
392                    (content_length > -1) ? &writer : NULL, NULL, &timeout));
393
394                /* timeout */
395                if( rv == 0 )
396                {
397                    ensure_out(kill(child, 0));
398                }
399
394400                /* wait until we can read or write or both */
395                if( select_intr(fd_max, &reader,
396                    (content_length > -1) ? &writer : NULL, NULL,
397                    (header_sent < 1) ? &timeout : NULL) > 0
398                ) {
401                else if( rv > 0 )
402                {
399403                    /* ready to write to cgi program */
400404                    if( FD_ISSET(wfd[1], &writer) )
401405                    {
...... 
403407                        if( content_length > 0 )
404408                        {
405409                            /* read it from socket ... */
406                            if( (buflen = uh_tcp_recv(cl, buf, min(content_length, sizeof(buf)))) > 0 )
410                            ensure_out(buflen = uh_tcp_recv(cl, buf,
411                                min(content_length, sizeof(buf))));
412
413                            if( buflen > 0 )
407414                            {
408415                                /* ... and write it to child's stdin */
409416                                if( write(wfd[1], buf, buflen) < 0 )
...... 
456463                                if( (res = uh_cgi_header_parse(hdr, hdrlen, &hdroff)) != NULL )
457464                                {
458465                                    /* write status */
459                                    ensure(uh_http_sendf(cl, NULL,
466                                    ensure_out(uh_http_sendf(cl, NULL,
460467                                        "HTTP/%.1f %03d %s\r\n"
461468                                        "Connection: close\r\n",
462469                                        req->version, res->statuscode,
...... 
466473                                    if( !uh_cgi_header_lookup(res, "Location") &&
467474                                        !uh_cgi_header_lookup(res, "Content-Type")
468475                                    ) {
469                                        ensure(uh_http_send(cl, NULL,
476                                        ensure_out(uh_http_send(cl, NULL,
470477                                            "Content-Type: text/plain\r\n", -1));
471478                                    }
472479
...... 
474481                                    if( (req->version > 1.0) &&
475482                                        !uh_cgi_header_lookup(res, "Transfer-Encoding")
476483                                    ) {
477                                        ensure(uh_http_send(cl, NULL,
484                                        ensure_out(uh_http_send(cl, NULL,
478485                                            "Transfer-Encoding: chunked\r\n", -1));
479486                                    }
480487
481488                                    /* write headers from CGI program */
482489                                    foreach_header(i, res->headers)
483490                                    {
484                                        ensure(uh_http_sendf(cl, NULL, "%s: %s\r\n",
491                                        ensure_out(uh_http_sendf(cl, NULL, "%s: %s\r\n",
485492                                            res->headers[i], res->headers[i+1]));
486493                                    }
487494
488495                                    /* terminate header */
489                                    ensure(uh_http_send(cl, NULL, "\r\n", -1));
496                                    ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
490497
491498                                    /* push out remaining head buffer */
492499                                    if( hdroff < hdrlen )
493                                        ensure(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff));
500                                        ensure_out(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff));
494501                                }
495502
496503                                /* ... failed and head buffer exceeded */
497504                                else if( hdrlen >= sizeof(hdr) )
498505                                {
499                                    ensure(uh_cgi_error_500(cl, req,
506                                    ensure_out(uh_cgi_error_500(cl, req,
500507                                        "The CGI program generated an invalid response:\n\n"));
501508
502                                    ensure(uh_http_send(cl, req, hdr, hdrlen));
509                                    ensure_out(uh_http_send(cl, req, hdr, hdrlen));
503510                                }
504511
505512                                /* ... failed but free buffer space, try again */
...... 
510517
511518                                /* push out remaining read buffer */
512519                                if( bufoff < buflen )
513                                    ensure(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff));
520                                    ensure_out(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff));
514521
515522                                header_sent = 1;
516523                                continue;
...... 
518525
519526
520527                            /* headers complete, pass through buffer to socket */
521                            ensure(uh_http_send(cl, req, buf, buflen));
528                            ensure_out(uh_http_send(cl, req, buf, buflen));
522529                        }
523530
524531                        /* looks like eof from child */
...... 
538545                                 * build the required headers here.
539546                                 */
540547
541                                ensure(uh_http_sendf(cl, NULL,
548                                ensure_out(uh_http_sendf(cl, NULL,
542549                                    "HTTP/%.1f 200 OK\r\n"
543550                                    "Content-Type: text/plain\r\n"
544551                                    "%s\r\n",
...... 
546553                                            ? "Transfer-Encoding: chunked\r\n" : ""
547554                                ));
548555
549                                ensure(uh_http_send(cl, req, hdr, hdrlen));
556                                ensure_out(uh_http_send(cl, req, hdr, hdrlen));
550557                            }
551558
552559                            /* send final chunk if we're in chunked transfer mode */
553                            ensure(uh_http_send(cl, req, "", 0));
560                            ensure_out(uh_http_send(cl, req, "", 0));
554561                            break;
555562                        }
556563                    }
...... 
561568                {
562569                    if( (errno != EINTR) && ! header_sent )
563570                    {
564                        ensure(uh_http_sendhf(cl, 504, "Gateway Timeout",
571                        ensure_out(uh_http_sendhf(cl, 504, "Gateway Timeout",
565572                            "The CGI script took too long to produce "
566573                            "a response"));
567574                    }
568575
569576                    /* send final chunk if we're in chunked transfer mode */
570                    ensure(uh_http_send(cl, req, "", 0));
577                    ensure_out(uh_http_send(cl, req, "", 0));
571578
572579                    break;
573580                }
package/uhttpd/src/uhttpd-file.c
9797    return NULL;
9898}
9999
100#define ensure_ret(x) \
101    do { if( x < 0 ) return -1; } while(0)
102100
103101static int uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s)
104102{
...... 
132130        "Connection: close\r\n", req->version);
133131}
134132
135static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s)
133static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s, int *ok)
136134{
137135    const char *tag = uh_file_mktag(s);
138136    char *hdr = uh_file_header_lookup(req, "If-Match");
...... 
152150            }
153151            else if( !strcmp(p, "*") || !strcmp(p, tag) )
154152            {
155                return 1;
153                *ok = 1;
154                return *ok;
156155            }
157156        }
158157
159        uh_file_response_412(cl, req);
160        return 0;
158        *ok = 0;
159        ensure_ret(uh_file_response_412(cl, req));
160        return *ok;
161161    }
162162
163    return 1;
163    *ok = 1;
164    return *ok;
164165}
165166
166static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s)
167static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok)
167168{
168169    char *hdr = uh_file_header_lookup(req, "If-Modified-Since");
170    *ok = 1;
169171
170172    if( hdr )
171173    {
172        if( uh_file_date2unix(hdr) < s->st_mtime )
174        if( uh_file_date2unix(hdr) >= s->st_mtime )
173175        {
174            return 1;
175        }
176        else
177        {
178            uh_file_response_304(cl, req, s);
179            return 0;
176            *ok = 0;
177            ensure_ret(uh_file_response_304(cl, req, s));
180178        }
181179    }
182180
183    return 1;
181    return *ok;
184182}
185183
186static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s)
184static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s, int *ok)
187185{
188186    const char *tag = uh_file_mktag(s);
189187    char *hdr = uh_file_header_lookup(req, "If-None-Match");
190188    char *p;
191189    int i;
190    *ok = 1;
192191
193192    if( hdr )
194193    {
...... 
203202            }
204203            else if( !strcmp(p, "*") || !strcmp(p, tag) )
205204            {
205                *ok = 0;
206
206207                if( (req->method == UH_HTTP_MSG_GET) ||
207208                    (req->method == UH_HTTP_MSG_HEAD) )
208                    uh_file_response_304(cl, req, s);
209                    ensure_ret(uh_file_response_304(cl, req, s));
209210                else
210                    uh_file_response_412(cl, req);
211                    ensure_ret(uh_file_response_412(cl, req));
211212
212                return 0;
213                break;
213214            }
214215        }
215216    }
216217
217    return 1;
218    return *ok;
218219}
219220
220static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s)
221static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s, int *ok)
221222{
222223    char *hdr = uh_file_header_lookup(req, "If-Range");
224    *ok = 1;
223225
224226    if( hdr )
225227    {
226        uh_file_response_412(cl, req);
227        return 0;
228        *ok = 0;
229        ensure_ret(uh_file_response_412(cl, req));
228230    }
229231
230    return 1;
232    return *ok;
231233}
232234
233static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s)
235static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok)
234236{
235237    char *hdr = uh_file_header_lookup(req, "If-Unmodified-Since");
238    *ok = 1;
236239
237240    if( hdr )
238241    {
239242        if( uh_file_date2unix(hdr) <= s->st_mtime )
240243        {
241            uh_file_response_412(cl, req);
242            return 0;
244            *ok = 0;
245            ensure_ret(uh_file_response_412(cl, req));
243246        }
244247    }
245248
246    return 1;
249    return *ok;
247250}
248251
249252
250#define ensure_out(x) \
251    do { if( x < 0 ) goto out; } while(0)
252
253253static int uh_file_scandir_filter_dir(const struct dirent *e)
254254{
255255    return strcmp(e->d_name, ".") ? 1 : 0;
...... 
335335void uh_file_request(struct client *cl, struct http_request *req, struct path_info *pi)
336336{
337337    int rlen;
338    int ok = 1;
338339    int fd = -1;
339340    char buf[UH_LIMIT_MSGHEAD];
340341
...... 
342343    if( (pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0) )
343344    {
344345        /* test preconditions */
345        if(
346            uh_file_if_modified_since(cl, req, &pi->stat) &&
347            uh_file_if_match(cl, req, &pi->stat) &&
348            uh_file_if_range(cl, req, &pi->stat) &&
349            uh_file_if_unmodified_since(cl, req, &pi->stat) &&
350            uh_file_if_none_match(cl, req, &pi->stat)
351        ) {
346        if(ok) ensure_out(uh_file_if_modified_since(cl, req, &pi->stat, &ok));
347        if(ok) ensure_out(uh_file_if_match(cl, req, &pi->stat, &ok));
348        if(ok) ensure_out(uh_file_if_range(cl, req, &pi->stat, &ok));
349        if(ok) ensure_out(uh_file_if_unmodified_since(cl, req, &pi->stat, &ok));
350        if(ok) ensure_out(uh_file_if_none_match(cl, req, &pi->stat, &ok));
351
352        if( ok > 0 )
353        {
352354            /* write status */
353355            ensure_out(uh_file_response_200(cl, req, &pi->stat));
354356
package/uhttpd/src/uhttpd-tls.c
7070
7171int uh_tls_client_recv(struct client *c, void *buf, int len)
7272{
73    return SSL_read(c->tls, buf, len);
73    int rv = SSL_read(c->tls, buf, len);
74    return (rv > 0) ? rv : -1;
7475}
7576
7677int uh_tls_client_send(struct client *c, void *buf, int len)
7778{
78    return SSL_write(c->tls, buf, len);
79    int rv = SSL_write(c->tls, buf, len);
80    return (rv > 0) ? rv : -1;
7981}
8082
8183void uh_tls_client_close(struct client *c)
package/uhttpd/src/uhttpd-utils.c
112112    /* unblock SIGCHLD */
113113    sigemptyset(&ssn);
114114    sigaddset(&ssn, SIGCHLD);
115    sigaddset(&ssn, SIGPIPE);
115116    sigprocmask(SIG_UNBLOCK, &ssn, &sso);
116117
117118    rv = select(n, r, w, e, t);
...... 
193194    return sz;
194195}
195196
196#define ensure(x) \
197    do { if( x < 0 ) return -1; } while(0)
198197
199198int uh_http_sendhf(struct client *cl, int code, const char *summary, const char *fmt, ...)
200199{
...... 
211210            code, summary
212211    );
213212
214    ensure(uh_tcp_send(cl, buffer, len));
213    ensure_ret(uh_tcp_send(cl, buffer, len));
215214
216215    va_start(ap, fmt);
217216    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
218217    va_end(ap);
219218
220    ensure(uh_http_sendc(cl, buffer, len));
221    ensure(uh_http_sendc(cl, NULL, 0));
219    ensure_ret(uh_http_sendc(cl, buffer, len));
220    ensure_ret(uh_http_sendc(cl, NULL, 0));
222221
223222    return 0;
224223}
...... 
235234    if( len > 0 )
236235    {
237236         clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
238        ensure(uh_tcp_send(cl, chunk, clen));
239        ensure(uh_tcp_send(cl, data, len));
240        ensure(uh_tcp_send(cl, "\r\n", 2));
237        ensure_ret(uh_tcp_send(cl, chunk, clen));
238        ensure_ret(uh_tcp_send(cl, data, len));
239        ensure_ret(uh_tcp_send(cl, "\r\n", 2));
241240    }
242241    else
243242    {
244        ensure(uh_tcp_send(cl, "0\r\n\r\n", 5));
243        ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5));
245244    }
246245
247246    return 0;
...... 
259258    va_end(ap);
260259
261260    if( (req != NULL) && (req->version > 1.0) )
262        ensure(uh_http_sendc(cl, buffer, len));
261        ensure_ret(uh_http_sendc(cl, buffer, len));
263262    else if( len > 0 )
264        ensure(uh_tcp_send(cl, buffer, len));
263        ensure_ret(uh_tcp_send(cl, buffer, len));
265264
266265    return 0;
267266}
...... 
273272        len = strlen(buf);
274273
275274    if( (req != NULL) && (req->version > 1.0) )
276        ensure(uh_http_sendc(cl, buf, len));
275        ensure_ret(uh_http_sendc(cl, buf, len));
277276    else if( len > 0 )
278        ensure(uh_tcp_send(cl, buf, len));
277        ensure_ret(uh_tcp_send(cl, buf, len));
279278
280279    return 0;
281280}
...... 
639638            ) {
640639                memcpy(new->pass, pwd->pw_passwd,
641640                    min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
642            }
641            }
643642        }
644643
645644        /* ordinary pwd */
package/uhttpd/src/uhttpd-utils.h
3636#define fd_cloexec(fd) \
3737    fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)
3838
39#define ensure_out(x) \
40    do { if((x) < 0) goto out; } while(0)
41
42#define ensure_ret(x) \
43    do { if((x) < 0) return -1; } while(0)
44
45
3946struct path_info {
4047    char *root;
4148    char *phys;
package/uhttpd/src/uhttpd.c
9696                conf->error_handler = strdup(col1);
9797            }
9898#ifdef HAVE_CGI
99            else if( (line[0] == '.') && (strchr(line, ':') != NULL) )
99            else if( (line[0] == '*') && (strchr(line, ':') != NULL) )
100100            {
101                if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
102                    !(eol = strchr(col1, '\n')) || (*eol++ = 0) )
101                if( !(col1 = strchr(line, '*')) || (*col1++ = 0) ||
102                    !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
103                    !(eol = strchr(col2, '\n')) || (*eol++ = 0) )
103104                        continue;
104105
105                if( !uh_interpreter_add(line, col1) )
106                if( !uh_interpreter_add(col1, col2) )
106107                {
107108                    fprintf(stderr,
108109                        "Unable to add interpreter %s for extension %s: "
109                        "Out of memory\n", col1, line
110                        "Out of memory\n", col2, col1
110111                    );
111112                }
112113            }
...... 
126127    int status;
127128    int bound = 0;
128129
130    int tcp_ka_idl = 1;
131    int tcp_ka_int = 1;
132    int tcp_ka_cnt = 3;
133
129134    struct listener *l = NULL;
130135    struct addrinfo *addrs = NULL, *p = NULL;
131136
...... 
145150        }
146151
147152        /* "address already in use" */
148        if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1 )
153        if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) )
149154        {
150155            perror("setsockopt()");
151156            goto error;
152157        }
153158
159        /* TCP keep-alive */
160        if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
161            setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
162            setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
163            setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)) )
164        {
165            fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
166                strerror(errno));
167        }
168
154169        /* required to get parallel v4 + v6 working */
155170        if( p->ai_family == AF_INET6 )
156171        {
...... 
355370    ssize_t blen = sizeof(buffer)-1;
356371    ssize_t rlen = 0;
357372
358
359373    memset(buffer, 0, sizeof(buffer));
360374
361375    while( blen > 0 )
...... 
371385        if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
372386        {
373387            /* receive data */
374            rlen = uh_tcp_peek(cl, bufptr, blen);
388            ensure_out(rlen = uh_tcp_peek(cl, bufptr, blen));
375389
376            if( rlen > 0 )
390            if( (idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)) )
377391            {
378                if( (idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)) )
379                {
380                    blen -= uh_tcp_recv(cl, bufptr, (int)(idxptr - bufptr) + 4);
392                ensure_out(rlen = uh_tcp_recv(cl, bufptr,
393                    (int)(idxptr - bufptr) + 4));
381394
382                    /* header read complete ... */
383                    return uh_http_header_parse(cl, buffer, sizeof(buffer) - blen - 1);
384                }
385                else
386                {
387                    rlen = uh_tcp_recv(cl, bufptr, rlen);
388                    blen -= rlen;
389                    bufptr += rlen;
390                }
395                /* header read complete ... */
396                blen -= rlen;
397                return uh_http_header_parse(cl, buffer,
398                    sizeof(buffer) - blen - 1);
391399            }
392400            else
393401            {
394                /* invalid request (unexpected eof/timeout) */
395                uh_http_response(cl, 408, "Request Timeout");
396                return NULL;
402                ensure_out(rlen = uh_tcp_recv(cl, bufptr, rlen));
403
404                blen -= rlen;
405                bufptr += rlen;
397406            }
398407        }
399408        else
400409        {
401410            /* invalid request (unexpected eof/timeout) */
402            uh_http_response(cl, 408, "Request Timeout");
403411            return NULL;
404412        }
405413    }
406414
407415    /* request entity too large */
408416    uh_http_response(cl, 413, "Request Entity Too Large");
417
418out:
409419    return NULL;
410420}
411421
package/uhttpd/src/uhttpd.h
2828#include <sys/select.h>
2929#include <sys/wait.h>
3030#include <netinet/in.h>
31#include <netinet/tcp.h>
3132#include <arpa/inet.h>
3233#include <linux/limits.h>
3334#include <netdb.h>
...... 
4445#include <openssl/ssl.h>
4546#endif
4647
48/* uClibc... */
49#ifndef SOL_TCP
50#define SOL_TCP 6
51#endif
52
4753
4854#define UH_LIMIT_MSGHEAD 4096
4955#define UH_LIMIT_HEADERS 64

Archive Download the corresponding diff file



interactive