source: branches/backfire/package/uhttpd/src/uhttpd.c @ 22608

Last change on this file since 22608 was 22608, checked in by jow, 6 years ago

[backfire] merge r22602 & r22607

File size: 21.1 KB
Line 
1/*
2 * uhttpd - Tiny single-threaded httpd - Main component
3 *
4 *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 *  Licensed under the Apache License, Version 2.0 (the "License");
7 *  you may not use this file except in compliance with the License.
8 *  You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *  Unless required by applicable law or agreed to in writing, software
13 *  distributed under the License is distributed on an "AS IS" BASIS,
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 */
18
19#define _XOPEN_SOURCE 500       /* crypt() */
20
21#include "uhttpd.h"
22#include "uhttpd-utils.h"
23#include "uhttpd-file.h"
24
25#ifdef HAVE_CGI
26#include "uhttpd-cgi.h"
27#endif
28
29#ifdef HAVE_LUA
30#include "uhttpd-lua.h"
31#endif
32
33#ifdef HAVE_TLS
34#include "uhttpd-tls.h"
35#endif
36
37
38static int run = 1;
39
40static void uh_sigterm(int sig)
41{
42        run = 0;
43}
44
45static void uh_sigchld(int sig)
46{
47        while( waitpid(-1, NULL, WNOHANG) > 0 ) { }
48}
49
50static void uh_config_parse(struct config *conf)
51{
52        FILE *c;
53        char line[512];
54        char *user = NULL;
55        char *pass = NULL;
56        char *eol  = NULL;
57
58        const char *path = conf->file ? conf->file : "/etc/httpd.conf";
59
60
61        if( (c = fopen(path, "r")) != NULL )
62        {
63                memset(line, 0, sizeof(line));
64
65                while( fgets(line, sizeof(line) - 1, c) )
66                {
67                        if( (line[0] == '/') && (strchr(line, ':') != NULL) )
68                        {
69                                if( !(user = strchr(line, ':')) || (*user++ = 0) ||
70                                    !(pass = strchr(user, ':')) || (*pass++ = 0) ||
71                                        !(eol = strchr(pass, '\n')) || (*eol++  = 0) )
72                                                continue;
73
74                                if( !uh_auth_add(line, user, pass) )
75                                {
76                                        fprintf(stderr,
77                                                "Notice: No password set for user %s, ignoring "
78                                                "authentication on %s\n", user, line
79                                        );
80                                }
81                        }
82                        else if( !strncmp(line, "I:", 2) )
83                        {
84                                if( !(user = strchr(line, ':')) || (*user++ = 0) ||
85                                    !(eol = strchr(user, '\n')) || (*eol++  = 0) )
86                                        continue;
87
88                                conf->index_file = strdup(user);
89                        }
90                        else if( !strncmp(line, "E404:", 5) )
91                        {
92                                if( !(user = strchr(line, ':')) || (*user++ = 0) ||
93                                    !(eol = strchr(user, '\n')) || (*eol++  = 0) )
94                                                continue;
95
96                                conf->error_handler = strdup(user);
97                        }
98                }
99
100                fclose(c);
101        }
102}
103
104static int uh_socket_bind(
105        fd_set *serv_fds, int *max_fd, const char *host, const char *port,
106        struct addrinfo *hints, int do_tls, struct config *conf
107) {
108        int sock = -1;
109        int yes = 1;
110        int status;
111        int bound = 0;
112
113        struct listener *l = NULL;
114        struct addrinfo *addrs = NULL, *p = NULL;
115
116        if( (status = getaddrinfo(host, port, hints, &addrs)) != 0 )
117        {
118                fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
119        }
120
121        /* try to bind a new socket to each found address */
122        for( p = addrs; p; p = p->ai_next )
123        {
124                /* get the socket */
125                if( (sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1 )
126                {
127                        perror("socket()");
128                        goto error;
129                }
130
131                /* "address already in use" */
132                if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1 )
133                {
134                        perror("setsockopt()");
135                        goto error;
136                }
137
138                /* required to get parallel v4 + v6 working */
139                if( p->ai_family == AF_INET6 )
140                {
141                        if( setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1 )
142                        {
143                                perror("setsockopt()");
144                                goto error;
145                        }
146                }
147
148                /* bind */
149                if( bind(sock, p->ai_addr, p->ai_addrlen) == -1 )
150                {
151                        perror("bind()");
152                        goto error;
153                }
154
155                /* listen */
156                if( listen(sock, UH_LIMIT_CLIENTS) == -1 )
157                {
158                        perror("listen()");
159                        goto error;
160                }
161
162                /* add listener to global list */
163                if( ! (l = uh_listener_add(sock, conf)) )
164                {
165                        fprintf(stderr,
166                                "uh_listener_add(): Can not create more than "
167                                "%i listen sockets\n", UH_LIMIT_LISTENERS
168                        );
169
170                        goto error;
171                }
172
173#ifdef HAVE_TLS
174                /* init TLS */
175                l->tls = do_tls ? conf->tls : NULL;
176#endif
177
178                /* add socket to server fd set */
179                FD_SET(sock, serv_fds);
180                fd_cloexec(sock);
181                *max_fd = max(*max_fd, sock);
182
183                bound++;
184                continue;
185
186                error:
187                if( sock > 0 )
188                        close(sock);
189        }
190
191        freeaddrinfo(addrs);
192
193        return bound;
194}
195
196static struct http_request * uh_http_header_parse(struct client *cl, char *buffer, int buflen)
197{
198        char *method  = &buffer[0];
199        char *path    = NULL;
200        char *version = NULL;
201
202        char *headers = NULL;
203        char *hdrname = NULL;
204        char *hdrdata = NULL;
205
206        int i;
207        int hdrcount = 0;
208
209        static struct http_request req;
210
211        memset(&req, 0, sizeof(req));
212
213
214        /* terminate initial header line */
215        if( (headers = strfind(buffer, buflen, "\r\n", 2)) != NULL )
216        {
217                buffer[buflen-1] = 0;
218
219                *headers++ = 0;
220                *headers++ = 0;
221
222                /* find request path */
223                if( (path = strchr(buffer, ' ')) != NULL )
224                        *path++ = 0;
225
226                /* find http version */
227                if( (path != NULL) && ((version = strchr(path, ' ')) != NULL) )
228                        *version++ = 0;
229
230
231                /* check method */
232                if( strcmp(method, "GET") && strcmp(method, "HEAD") && strcmp(method, "POST") )
233                {
234                        /* invalid method */
235                        uh_http_response(cl, 405, "Method Not Allowed");
236                        return NULL;
237                }
238                else
239                {
240                        switch(method[0])
241                        {
242                                case 'G':
243                                        req.method = UH_HTTP_MSG_GET;
244                                        break;
245
246                                case 'H':
247                                        req.method = UH_HTTP_MSG_HEAD;
248                                        break;
249
250                                case 'P':
251                                        req.method = UH_HTTP_MSG_POST;
252                                        break;
253                        }
254                }
255
256                /* check path */
257                if( !path || !strlen(path) )
258                {
259                        /* malformed request */
260                        uh_http_response(cl, 400, "Bad Request");
261                        return NULL;
262                }
263                else
264                {
265                        req.url = path;
266                }
267
268                /* check version */
269                if( (version == NULL) || (strcmp(version, "HTTP/0.9") &&
270                    strcmp(version, "HTTP/1.0") && strcmp(version, "HTTP/1.1")) )
271                {
272                        /* unsupported version */
273                        uh_http_response(cl, 400, "Bad Request");
274                        return NULL;
275                }
276                else
277                {
278                        req.version = strtof(&version[5], NULL);
279                }
280
281
282                /* process header fields */
283                for( i = (int)(headers - buffer); i < buflen; i++ )
284                {
285                        /* found eol and have name + value, push out header tuple */
286                        if( hdrname && hdrdata && (buffer[i] == '\r' || buffer[i] == '\n') )
287                        {
288                                buffer[i] = 0;
289
290                                /* store */
291                                if( (hdrcount + 1) < array_size(req.headers) )
292                                {
293                                        req.headers[hdrcount++] = hdrname;
294                                        req.headers[hdrcount++] = hdrdata;
295
296                                        hdrname = hdrdata = NULL;
297                                }
298
299                                /* too large */
300                                else
301                                {
302                                        uh_http_response(cl, 413, "Request Entity Too Large");
303                                        return NULL;
304                                }
305                        }
306
307                        /* have name but no value and found a colon, start of value */
308                        else if( hdrname && !hdrdata && ((i+2) < buflen) &&
309                                (buffer[i] == ':') && (buffer[i+1] == ' ')
310                        ) {
311                                buffer[i] = 0;
312                                hdrdata = &buffer[i+2];
313                        }
314
315                        /* have no name and found [A-Z], start of name */
316                        else if( !hdrname && isalpha(buffer[i]) && isupper(buffer[i]) )
317                        {
318                                hdrname = &buffer[i];
319                        }
320                }
321
322                /* valid enough */
323                req.redirect_status = 200;
324                return &req;
325        }
326
327        /* Malformed request */
328        uh_http_response(cl, 400, "Bad Request");
329        return NULL;
330}
331
332
333static struct http_request * uh_http_header_recv(struct client *cl)
334{
335        static char buffer[UH_LIMIT_MSGHEAD];
336        char *bufptr = &buffer[0];
337        char *idxptr = NULL;
338
339        struct timeval timeout;
340
341        fd_set reader;
342
343        ssize_t blen = sizeof(buffer)-1;
344        ssize_t rlen = 0;
345
346
347        memset(buffer, 0, sizeof(buffer));
348
349        while( blen > 0 )
350        {
351                FD_ZERO(&reader);
352                FD_SET(cl->socket, &reader);
353
354                /* fail after 0.1s */
355                timeout.tv_sec  = 0;
356                timeout.tv_usec = 100000;
357
358                /* check whether fd is readable */
359                if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
360                {
361                        /* receive data */
362                        rlen = uh_tcp_peek(cl, bufptr, blen);
363
364                        if( rlen > 0 )
365                        {
366                                if( (idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)) )
367                                {
368                                        blen -= uh_tcp_recv(cl, bufptr, (int)(idxptr - bufptr) + 4);
369
370                                        /* header read complete ... */
371                                        return uh_http_header_parse(cl, buffer, sizeof(buffer) - blen - 1);
372                                }
373                                else
374                                {
375                                        rlen = uh_tcp_recv(cl, bufptr, rlen);
376                                        blen -= rlen;
377                                        bufptr += rlen;
378                                }
379                        }
380                        else
381                        {
382                                /* invalid request (unexpected eof/timeout) */
383                                uh_http_response(cl, 408, "Request Timeout");
384                                return NULL;
385                        }
386                }
387                else
388                {
389                        /* invalid request (unexpected eof/timeout) */
390                        uh_http_response(cl, 408, "Request Timeout");
391                        return NULL;
392                }
393        }
394
395        /* request entity too large */
396        uh_http_response(cl, 413, "Request Entity Too Large");
397        return NULL;
398}
399
400static int uh_path_match(const char *prefix, const char *url)
401{
402        if( (strstr(url, prefix) == url) &&
403            ((prefix[strlen(prefix)-1] == '/') ||
404                 (strlen(url) == strlen(prefix))   ||
405                 (url[strlen(prefix)] == '/'))
406        ) {
407                return 1;
408        }
409
410        return 0;
411}
412
413
414int main (int argc, char **argv)
415{
416#ifdef HAVE_LUA
417        /* Lua runtime */
418        lua_State *L = NULL;
419#endif
420
421        /* master file descriptor list */
422        fd_set used_fds, serv_fds, read_fds;
423
424        /* working structs */
425        struct addrinfo hints;
426        struct http_request *req;
427        struct path_info *pin;
428        struct client *cl;
429        struct sigaction sa;
430        struct config conf;
431
432        /* signal mask */
433        sigset_t ss;
434
435        /* maximum file descriptor number */
436        int new_fd, cur_fd, max_fd = 0;
437
438#ifdef HAVE_TLS
439        int tls = 0;
440        int keys = 0;
441#endif
442
443        int bound = 0;
444        int nofork = 0;
445
446        /* args */
447        int opt;
448        char bind[128];
449        char *port = NULL;
450
451#if defined(HAVE_TLS) || defined(HAVE_LUA)
452        /* library handle */
453        void *lib;
454#endif
455
456        /* clear the master and temp sets */
457        FD_ZERO(&used_fds);
458        FD_ZERO(&serv_fds);
459        FD_ZERO(&read_fds);
460
461        /* handle SIGPIPE, SIGINT, SIGTERM, SIGCHLD */
462        sa.sa_flags = 0;
463        sigemptyset(&sa.sa_mask);
464
465        sa.sa_handler = SIG_IGN;
466        sigaction(SIGPIPE, &sa, NULL);
467
468        sa.sa_handler = uh_sigchld;
469        sigaction(SIGCHLD, &sa, NULL);
470
471        sa.sa_handler = uh_sigterm;
472        sigaction(SIGINT,  &sa, NULL);
473        sigaction(SIGTERM, &sa, NULL);
474
475        /* defer SIGCHLD */
476        sigemptyset(&ss);
477        sigaddset(&ss, SIGCHLD);
478        sigprocmask(SIG_BLOCK, &ss, NULL);
479
480        /* prepare addrinfo hints */
481        memset(&hints, 0, sizeof(hints));
482        hints.ai_family   = AF_UNSPEC;
483        hints.ai_socktype = SOCK_STREAM;
484        hints.ai_flags    = AI_PASSIVE;
485
486        /* parse args */
487        memset(&conf, 0, sizeof(conf));
488        memset(bind, 0, sizeof(bind));
489
490#ifdef HAVE_TLS
491        /* load TLS plugin */
492        if( ! (lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
493        {
494                fprintf(stderr,
495                        "Notice: Unable to load TLS plugin - disabling SSL support! "
496                        "(Reason: %s)\n", dlerror()
497                );
498        }
499        else
500        {
501                /* resolve functions */
502                if( !(conf.tls_init   = dlsym(lib, "uh_tls_ctx_init"))      ||
503                    !(conf.tls_cert   = dlsym(lib, "uh_tls_ctx_cert"))      ||
504                    !(conf.tls_key    = dlsym(lib, "uh_tls_ctx_key"))       ||
505                    !(conf.tls_free   = dlsym(lib, "uh_tls_ctx_free"))      ||
506                        !(conf.tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
507                        !(conf.tls_close  = dlsym(lib, "uh_tls_client_close"))  ||
508                        !(conf.tls_recv   = dlsym(lib, "uh_tls_client_recv"))   ||
509                        !(conf.tls_send   = dlsym(lib, "uh_tls_client_send"))
510                ) {
511                        fprintf(stderr,
512                                "Error: Failed to lookup required symbols "
513                                "in TLS plugin: %s\n", dlerror()
514                        );
515                        exit(1);
516                }
517
518                /* init SSL context */
519                if( ! (conf.tls = conf.tls_init()) )
520                {
521                        fprintf(stderr, "Error: Failed to initalize SSL context\n");
522                        exit(1);
523                }
524        }
525#endif
526
527        while( (opt = getopt(argc, argv,
528                "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0
529        ) {
530                switch(opt)
531                {
532                        /* [addr:]port */
533                        case 'p':
534                        case 's':
535                                if( (port = strrchr(optarg, ':')) != NULL )
536                                {
537                                        if( (optarg[0] == '[') && (port > optarg) && (port[-1] == ']') )
538                                                memcpy(bind, optarg + 1,
539                                                        min(sizeof(bind), (int)(port - optarg) - 2));
540                                        else
541                                                memcpy(bind, optarg,
542                                                        min(sizeof(bind), (int)(port - optarg)));
543
544                                        port++;
545                                }
546                                else
547                                {
548                                        port = optarg;
549                                }
550
551#ifdef HAVE_TLS
552                                if( opt == 's' )
553                                {
554                                        if( !conf.tls )
555                                        {
556                                                fprintf(stderr,
557                                                        "Notice: TLS support is disabled, "
558                                                        "ignoring '-s %s'\n", optarg
559                                                );
560                                                continue;
561                                        }
562
563                                        tls = 1;
564                                }
565#endif
566
567                                /* bind sockets */
568                                bound += uh_socket_bind(
569                                        &serv_fds, &max_fd, bind[0] ? bind : NULL, port,
570                                        &hints, (opt == 's'), &conf
571                                );
572
573                                memset(bind, 0, sizeof(bind));
574                                break;
575
576#ifdef HAVE_TLS
577                        /* certificate */
578                        case 'C':
579                                if( conf.tls )
580                                {
581                                        if( conf.tls_cert(conf.tls, optarg) < 1 )
582                                        {
583                                                fprintf(stderr,
584                                                        "Error: Invalid certificate file given\n");
585                                                exit(1);
586                                        }
587
588                                        keys++;
589                                }
590
591                                break;
592
593                        /* key */
594                        case 'K':
595                                if( conf.tls )
596                                {
597                                        if( conf.tls_key(conf.tls, optarg) < 1 )
598                                        {
599                                                fprintf(stderr,
600                                                        "Error: Invalid private key file given\n");
601                                                exit(1);
602                                        }
603
604                                        keys++;
605                                }
606
607                                break;
608#endif
609
610                        /* docroot */
611                        case 'h':
612                                if( ! realpath(optarg, conf.docroot) )
613                                {
614                                        fprintf(stderr, "Error: Invalid directory %s: %s\n",
615                                                optarg, strerror(errno));
616                                        exit(1);
617                                }
618                                break;
619
620                        /* error handler */
621                        case 'E':
622                                if( (strlen(optarg) == 0) || (optarg[0] != '/') )
623                                {
624                                        fprintf(stderr, "Error: Invalid error handler: %s\n",
625                                                optarg);
626                                        exit(1);
627                                }
628                                conf.error_handler = optarg;
629                                break;
630
631                        /* index file */
632                        case 'I':
633                                if( (strlen(optarg) == 0) || (optarg[0] == '/') )
634                                {
635                                        fprintf(stderr, "Error: Invalid index page: %s\n",
636                                                optarg);
637                                        exit(1);
638                                }
639                                conf.index_file = optarg;
640                                break;
641
642                        /* don't follow symlinks */
643                        case 'S':
644                                conf.no_symlinks = 1;
645                                break;
646
647                        /* don't list directories */
648                        case 'D':
649                                conf.no_dirlists = 1;
650                                break;
651
652                        case 'R':
653                                conf.rfc1918_filter = 1;
654                                break;
655
656#ifdef HAVE_CGI
657                        /* cgi prefix */
658                        case 'x':
659                                conf.cgi_prefix = optarg;
660                                break;
661#endif
662
663#ifdef HAVE_LUA
664                        /* lua prefix */
665                        case 'l':
666                                conf.lua_prefix = optarg;
667                                break;
668
669                        /* lua handler */
670                        case 'L':
671                                conf.lua_handler = optarg;
672                                break;
673#endif
674
675#if defined(HAVE_CGI) || defined(HAVE_LUA)
676                        /* script timeout */
677                        case 't':
678                                conf.script_timeout = atoi(optarg);
679                                break;
680#endif
681
682                        /* network timeout */
683                        case 'T':
684                                conf.network_timeout = atoi(optarg);
685                                break;
686
687                        /* no fork */
688                        case 'f':
689                                nofork = 1;
690                                break;
691
692                        /* urldecode */
693                        case 'd':
694                                if( (port = malloc(strlen(optarg)+1)) != NULL )
695                                {
696                                        memset(port, 0, strlen(optarg)+1);
697                                        uh_urldecode(port, strlen(optarg), optarg, strlen(optarg));
698                                        printf("%s", port);
699                                        free(port);
700                                        exit(0);
701                                }
702                                break;
703
704                        /* basic auth realm */
705                        case 'r':
706                                conf.realm = optarg;
707                                break;
708
709                        /* md5 crypt */
710                        case 'm':
711                                printf("%s\n", crypt(optarg, "$1$"));
712                                exit(0);
713                                break;
714
715                        /* config file */
716                        case 'c':
717                                conf.file = optarg;
718                                break;
719
720                        default:
721                                fprintf(stderr,
722                                        "Usage: %s -p [addr:]port [-h docroot]\n"
723                                        "       -f              Do not fork to background\n"
724                                        "       -c file         Configuration file, default is '/etc/httpd.conf'\n"
725                                        "       -p [addr:]port  Bind to specified address and port, multiple allowed\n"
726#ifdef HAVE_TLS
727                                        "       -s [addr:]port  Like -p but provide HTTPS on this port\n"
728                                        "       -C file         ASN.1 server certificate file\n"
729                                        "       -K file         ASN.1 server private key file\n"
730#endif
731                                        "       -h directory    Specify the document root, default is '.'\n"
732                                        "       -E string       Use given virtual URL as 404 error handler\n"
733                                        "       -I string       Use given filename as index page for directories\n"
734                                        "       -S              Do not follow symbolic links outside of the docroot\n"
735                                        "       -D              Do not allow directory listings, send 403 instead\n"
736                                        "       -R              Enable RFC1918 filter\n"
737#ifdef HAVE_LUA
738                                        "       -l string       URL prefix for Lua handler, default is '/lua'\n"
739                                        "       -L file         Lua handler script, omit to disable Lua\n"
740#endif
741#ifdef HAVE_CGI
742                                        "       -x string       URL prefix for CGI handler, default is '/cgi-bin'\n"
743#endif
744#if defined(HAVE_CGI) || defined(HAVE_LUA)
745                                        "       -t seconds      CGI and Lua script timeout in seconds, default is 60\n"
746#endif
747                                        "       -T seconds      Network timeout in seconds, default is 30\n"
748                                        "       -d string       URL decode given string\n"
749                                        "       -r string       Specify basic auth realm\n"
750                                        "       -m string       MD5 crypt given string\n"
751                                        "\n", argv[0]
752                                );
753
754                                exit(1);
755                }
756        }
757
758#ifdef HAVE_TLS
759        if( (tls == 1) && (keys < 2) )
760        {
761                fprintf(stderr, "Error: Missing private key or certificate file\n");
762                exit(1);
763        }
764#endif
765
766        if( bound < 1 )
767        {
768                fprintf(stderr, "Error: No sockets bound, unable to continue\n");
769                exit(1);
770        }
771
772        /* default docroot */
773        if( !conf.docroot[0] && !realpath(".", conf.docroot) )
774        {
775                fprintf(stderr, "Error: Can not determine default document root: %s\n",
776                        strerror(errno));
777                exit(1);
778        }
779
780        /* default realm */
781        if( ! conf.realm )
782                conf.realm = "Protected Area";
783
784        /* config file */
785        uh_config_parse(&conf);
786
787        /* default network timeout */
788        if( conf.network_timeout <= 0 )
789                conf.network_timeout = 30;
790
791#if defined(HAVE_CGI) || defined(HAVE_LUA)
792        /* default script timeout */
793        if( conf.script_timeout <= 0 )
794                conf.script_timeout = 60;
795#endif
796
797#ifdef HAVE_CGI
798        /* default cgi prefix */
799        if( ! conf.cgi_prefix )
800                conf.cgi_prefix = "/cgi-bin";
801#endif
802
803#ifdef HAVE_LUA
804        /* load Lua plugin */
805        if( ! (lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
806        {
807                fprintf(stderr,
808                        "Notice: Unable to load Lua plugin - disabling Lua support! "
809                        "(Reason: %s)\n", dlerror()
810                );
811        }
812        else
813        {
814                /* resolve functions */
815                if( !(conf.lua_init    = dlsym(lib, "uh_lua_init"))    ||
816                    !(conf.lua_close   = dlsym(lib, "uh_lua_close"))   ||
817                    !(conf.lua_request = dlsym(lib, "uh_lua_request"))
818                ) {
819                        fprintf(stderr,
820                                "Error: Failed to lookup required symbols "
821                                "in Lua plugin: %s\n", dlerror()
822                        );
823                        exit(1);
824                }
825
826                /* init Lua runtime if handler is specified */
827                if( conf.lua_handler )
828                {
829                        /* default lua prefix */
830                        if( ! conf.lua_prefix )
831                                conf.lua_prefix = "/lua";
832
833                        L = conf.lua_init(conf.lua_handler);
834                }
835        }
836#endif
837
838        /* fork (if not disabled) */
839        if( ! nofork )
840        {
841                switch( fork() )
842                {
843                        case -1:
844                                perror("fork()");
845                                exit(1);
846
847                        case 0:
848                                /* daemon setup */
849                                if( chdir("/") )
850                                        perror("chdir()");
851
852                                if( (cur_fd = open("/dev/null", O_WRONLY)) > -1 )
853                                        dup2(cur_fd, 0);
854
855                                if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 )
856                                        dup2(cur_fd, 1);
857
858                                if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 )
859                                        dup2(cur_fd, 2);
860
861                                break;
862
863                        default:
864                                exit(0);
865                }
866        }
867
868        /* backup server descriptor set */
869        used_fds = serv_fds;
870
871        /* loop */
872        while(run)
873        {
874                /* create a working copy of the used fd set */
875                read_fds = used_fds;
876
877                /* sleep until socket activity */
878                if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 )
879                {
880                        perror("select()");
881                        exit(1);
882                }
883
884                /* run through the existing connections looking for data to be read */
885                for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ )
886                {
887                        /* is a socket managed by us */
888                        if( FD_ISSET(cur_fd, &read_fds) )
889                        {
890                                /* is one of our listen sockets */
891                                if( FD_ISSET(cur_fd, &serv_fds) )
892                                {
893                                        /* handle new connections */
894                                        if( (new_fd = accept(cur_fd, NULL, 0)) != -1 )
895                                        {
896                                                /* add to global client list */
897                                                if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL )
898                                                {
899#ifdef HAVE_TLS
900                                                        /* setup client tls context */
901                                                        if( conf.tls )
902                                                                conf.tls_accept(cl);
903#endif
904
905                                                        /* add client socket to global fdset */
906                                                        FD_SET(new_fd, &used_fds);
907                                                        fd_cloexec(new_fd);
908                                                        max_fd = max(max_fd, new_fd);
909                                                }
910
911                                                /* insufficient resources */
912                                                else
913                                                {
914                                                        fprintf(stderr,
915                                                                "uh_client_add(): Can not manage more than "
916                                                                "%i client sockets, connection dropped\n",
917                                                                UH_LIMIT_CLIENTS
918                                                        );
919
920                                                        close(new_fd);
921                                                }
922                                        }
923                                }
924
925                                /* is a client socket */
926                                else
927                                {
928                                        if( ! (cl = uh_client_lookup(cur_fd)) )
929                                        {
930                                                /* this should not happen! */
931                                                fprintf(stderr,
932                                                        "uh_client_lookup(): No entry for fd %i!\n",
933                                                        cur_fd);
934
935                                                goto cleanup;
936                                        }
937
938                                        /* parse message header */
939                                        if( (req = uh_http_header_recv(cl)) != NULL )
940                                        {
941                                                /* RFC1918 filtering required? */
942                                                if( conf.rfc1918_filter && sa_rfc1918(&cl->peeraddr) &&
943                                                    !sa_rfc1918(&cl->servaddr) )
944                                                {
945                                                        uh_http_sendhf(cl, 403, "Forbidden",
946                                                                "Rejected request from RFC1918 IP to public server address");
947                                                }
948                                                else
949#ifdef HAVE_LUA
950                                                /* Lua request? */
951                                                if( L && uh_path_match(conf.lua_prefix, req->url) )
952                                                {
953                                                        conf.lua_request(cl, req, L);
954                                                }
955                                                else
956#endif
957                                                /* dispatch request */
958                                                if( (pin = uh_path_lookup(cl, req->url)) != NULL )
959                                                {
960                                                        /* auth ok? */
961                                                        if( uh_auth_check(cl, req, pin) )
962                                                        {
963#ifdef HAVE_CGI
964                                                                if( uh_path_match(conf.cgi_prefix, pin->name) )
965                                                                {
966                                                                        uh_cgi_request(cl, req, pin);
967                                                                }
968                                                                else
969#endif
970                                                                {
971                                                                        uh_file_request(cl, req, pin);
972                                                                }
973                                                        }
974                                                }
975
976                                                /* 404 */
977                                                else
978                                                {
979                                                        /* Try to invoke an error handler */
980                                                        pin = uh_path_lookup(cl, conf.error_handler);
981
982                                                        if( pin && uh_auth_check(cl, req, pin) )
983                                                        {
984                                                                req->redirect_status = 404;
985
986#ifdef HAVE_CGI
987                                                                if( uh_path_match(conf.cgi_prefix, pin->name) )
988                                                                {
989                                                                        uh_cgi_request(cl, req, pin);
990                                                                }
991                                                                else
992#endif
993                                                                {
994                                                                        uh_file_request(cl, req, pin);
995                                                                }
996                                                        }
997                                                        else
998                                                        {
999                                                                uh_http_sendhf(cl, 404, "Not Found",
1000                                                                        "No such file or directory");
1001                                                        }
1002                                                }
1003                                        }
1004
1005#ifdef HAVE_TLS
1006                                        /* free client tls context */
1007                                        if( conf.tls )
1008                                                conf.tls_close(cl);
1009#endif
1010
1011                                        cleanup:
1012
1013                                        /* close client socket */
1014                                        close(cur_fd);
1015                                        FD_CLR(cur_fd, &used_fds);
1016
1017                                        /* remove from global client list */
1018                                        uh_client_remove(cur_fd);
1019                                }
1020                        }
1021                }
1022        }
1023
1024#ifdef HAVE_LUA
1025        /* destroy the Lua state */
1026        if( L != NULL )
1027                conf.lua_close(L);
1028#endif
1029
1030        return 0;
1031}
1032
Note: See TracBrowser for help on using the repository browser.