source: trunk/package/uhttpd/src/uhttpd.c @ 21121

Last change on this file since 21121 was 21121, checked in by jow, 7 years ago

[package] uhttpd:

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