source: trunk/package/uhttpd/src/uhttpd-utils.c @ 22692

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

[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
File size: 17.9 KB
Line 
1/*
2 * uhttpd - Tiny single-threaded httpd - Utility functions
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#define _BSD_SOURCE                     /* strcasecmp(), strncasecmp() */
21
22#include "uhttpd.h"
23#include "uhttpd-utils.h"
24
25#ifdef HAVE_TLS
26#include "uhttpd-tls.h"
27#endif
28
29
30static char *uh_index_files[] = {
31        "index.html",
32        "index.htm",
33        "default.html",
34        "default.htm"
35};
36
37
38const char * sa_straddr(void *sa)
39{
40        static char str[INET6_ADDRSTRLEN];
41        struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
42        struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)sa;
43
44        if( v4->sin_family == AF_INET )
45                return inet_ntop(AF_INET, &(v4->sin_addr), str, sizeof(str));
46        else
47                return inet_ntop(AF_INET6, &(v6->sin6_addr), str, sizeof(str));
48}
49
50const char * sa_strport(void *sa)
51{
52        static char str[6];
53        snprintf(str, sizeof(str), "%i", sa_port(sa));
54        return str;
55}
56
57int sa_port(void *sa)
58{
59        return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
60}
61
62int sa_rfc1918(void *sa)
63{
64        struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
65        unsigned long a = htonl(v4->sin_addr.s_addr);
66
67        if( v4->sin_family == AF_INET )
68        {
69                return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
70                       ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
71                       ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
72        }
73
74        return 0;
75}
76
77/* Simple strstr() like function that takes len arguments for both haystack and needle. */
78char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
79{
80        int match = 0;
81        int i, j;
82
83        for( i = 0; i < hslen; i++ )
84        {
85                if( haystack[i] == needle[0] )
86                {
87                        match = ((ndlen == 1) || ((i + ndlen) <= hslen));
88
89                        for( j = 1; (j < ndlen) && ((i + j) < hslen); j++ )
90                        {
91                                if( haystack[i+j] != needle[j] )
92                                {
93                                        match = 0;
94                                        break;
95                                }
96                        }
97
98                        if( match )
99                                return &haystack[i];
100                }
101        }
102
103        return NULL;
104}
105
106/* interruptable select() */
107int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t)
108{
109        int rv;
110        sigset_t ssn, sso;
111
112        /* unblock SIGCHLD */
113        sigemptyset(&ssn);
114        sigaddset(&ssn, SIGCHLD);
115        sigaddset(&ssn, SIGPIPE);
116        sigprocmask(SIG_UNBLOCK, &ssn, &sso);
117
118        rv = select(n, r, w, e, t);
119
120        /* restore signal mask */
121        sigprocmask(SIG_SETMASK, &sso, NULL);
122
123        return rv;
124}
125
126
127int uh_tcp_send(struct client *cl, const char *buf, int len)
128{
129        fd_set writer;
130        struct timeval timeout;
131
132        FD_ZERO(&writer);
133        FD_SET(cl->socket, &writer);
134
135        timeout.tv_sec = cl->server->conf->network_timeout;
136        timeout.tv_usec = 0;
137
138        if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 )
139        {
140#ifdef HAVE_TLS
141                if( cl->tls )
142                        return cl->server->conf->tls_send(cl, (void *)buf, len);
143                else
144#endif
145                        return send(cl->socket, buf, len, 0);
146        }
147
148        return -1;
149}
150
151int uh_tcp_peek(struct client *cl, char *buf, int len)
152{
153        int sz = uh_tcp_recv(cl, buf, len);
154
155        /* store received data in peek buffer */
156        if( sz > 0 )
157        {
158                cl->peeklen = sz;
159                memcpy(cl->peekbuf, buf, sz);
160        }
161
162        return sz;
163}
164
165int uh_tcp_recv(struct client *cl, char *buf, int len)
166{
167        int sz = 0;
168        int rsz = 0;
169
170        /* first serve data from peek buffer */
171        if( cl->peeklen > 0 )
172        {
173                sz = min(cl->peeklen, len);
174                len -= sz; cl->peeklen -= sz;
175
176                memcpy(buf, cl->peekbuf, sz);
177                memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
178        }
179
180        /* caller wants more */
181        if( len > 0 )
182        {
183#ifdef HAVE_TLS
184                if( cl->tls )
185                        rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
186                else
187#endif
188                        rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
189
190                if( (sz == 0) || (rsz > 0) )
191                        sz += rsz;
192        }
193
194        return sz;
195}
196
197
198int uh_http_sendhf(struct client *cl, int code, const char *summary, const char *fmt, ...)
199{
200        va_list ap;
201
202        char buffer[UH_LIMIT_MSGHEAD];
203        int len;
204
205        len = snprintf(buffer, sizeof(buffer),
206                "HTTP/1.1 %03i %s\r\n"
207                "Connection: close\r\n"
208                "Content-Type: text/plain\r\n"
209                "Transfer-Encoding: chunked\r\n\r\n",
210                        code, summary
211        );
212
213        ensure_ret(uh_tcp_send(cl, buffer, len));
214
215        va_start(ap, fmt);
216        len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
217        va_end(ap);
218
219        ensure_ret(uh_http_sendc(cl, buffer, len));
220        ensure_ret(uh_http_sendc(cl, NULL, 0));
221
222        return 0;
223}
224
225
226int uh_http_sendc(struct client *cl, const char *data, int len)
227{
228        char chunk[8];
229        int clen;
230
231        if( len == -1 )
232                len = strlen(data);
233
234        if( len > 0 )
235        {
236                clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
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));
240        }
241        else
242        {
243                ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5));
244        }
245
246        return 0;
247}
248
249int uh_http_sendf(
250        struct client *cl, struct http_request *req, const char *fmt, ...
251) {
252        va_list ap;
253        char buffer[UH_LIMIT_MSGHEAD];
254        int len;
255
256        va_start(ap, fmt);
257        len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
258        va_end(ap);
259
260        if( (req != NULL) && (req->version > 1.0) )
261                ensure_ret(uh_http_sendc(cl, buffer, len));
262        else if( len > 0 )
263                ensure_ret(uh_tcp_send(cl, buffer, len));
264
265        return 0;
266}
267
268int uh_http_send(
269        struct client *cl, struct http_request *req, const char *buf, int len
270) {
271        if( len < 0 )
272                len = strlen(buf);
273
274        if( (req != NULL) && (req->version > 1.0) )
275                ensure_ret(uh_http_sendc(cl, buf, len));
276        else if( len > 0 )
277                ensure_ret(uh_tcp_send(cl, buf, len));
278
279        return 0;
280}
281
282
283int uh_urldecode(char *buf, int blen, const char *src, int slen)
284{
285        int i;
286        int len = 0;
287
288#define hex(x) \
289        (((x) <= '9') ? ((x) - '0') : \
290                (((x) <= 'F') ? ((x) - 'A' + 10) : \
291                        ((x) - 'a' + 10)))
292
293        for( i = 0; (i <= slen) && (i <= blen); i++ )
294        {
295                if( src[i] == '%' )
296                {
297                        if( ((i+2) <= slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]) )
298                        {
299                                buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
300                                i += 2;
301                        }
302                        else
303                        {
304                                buf[len++] = '%';
305                        }
306                }
307                else
308                {
309                        buf[len++] = src[i];
310                }
311        }
312
313        return len;
314}
315
316int uh_urlencode(char *buf, int blen, const char *src, int slen)
317{
318        int i;
319        int len = 0;
320        const char hex[] = "0123456789abcdef";
321
322        for( i = 0; (i <= slen) && (i <= blen); i++ )
323        {
324                if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
325                    (src[i] == '.') || (src[i] == '~') )
326                {
327                        buf[len++] = src[i];
328                }
329                else if( (len+3) <= blen )
330                {
331                        buf[len++] = '%';
332                        buf[len++] = hex[(src[i] >> 4) & 15];
333                        buf[len++] = hex[(src[i] & 15) & 15];
334                }
335                else
336                {
337                        break;
338                }
339        }
340
341        return len;
342}
343
344int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
345{
346        int i = 0;
347        int len = 0;
348
349        unsigned int cin  = 0;
350        unsigned int cout = 0;
351
352
353        for( i = 0; (i <= slen) && (src[i] != 0); i++ )
354        {
355                cin = src[i];
356
357                if( (cin >= '0') && (cin <= '9') )
358                        cin = cin - '0' + 52;
359                else if( (cin >= 'A') && (cin <= 'Z') )
360                        cin = cin - 'A';
361                else if( (cin >= 'a') && (cin <= 'z') )
362                        cin = cin - 'a' + 26;
363                else if( cin == '+' )
364                        cin = 62;
365                else if( cin == '/' )
366                        cin = 63;
367                else if( cin == '=' )
368                        cin = 0;
369                else
370                        continue;
371
372                cout = (cout << 6) | cin;
373
374                if( (i % 4) == 3 )
375                {
376                        if( (len + 3) < blen )
377                        {
378                                buf[len++] = (char)(cout >> 16);
379                                buf[len++] = (char)(cout >> 8);
380                                buf[len++] = (char)(cout);
381                        }
382                        else
383                        {
384                                break;
385                        }
386                }
387        }
388
389        buf[len++] = 0;
390        return len;
391}
392
393static char * canonpath(const char *path, char *path_resolved)
394{
395        char path_copy[PATH_MAX];
396        char *path_cpy = path_copy;
397        char *path_res = path_resolved;
398
399        struct stat s;
400
401
402        /* relative -> absolute */
403        if( *path != '/' )
404        {
405                getcwd(path_copy, PATH_MAX);
406                strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
407                strncat(path_copy, path, PATH_MAX - strlen(path_copy));
408        }
409        else
410        {
411                strncpy(path_copy, path, PATH_MAX);
412        }
413
414        /* normalize */
415        while( (*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)) )
416        {
417                if( *path_cpy == '/' )
418                {
419                        /* skip repeating / */
420                        if( path_cpy[1] == '/' )
421                        {
422                                path_cpy++;
423                                continue;
424                        }
425
426                        /* /./ or /../ */
427                        else if( path_cpy[1] == '.' )
428                        {
429                                /* skip /./ */
430                                if( (path_cpy[2] == '/') || (path_cpy[2] == '\0') )
431                                {
432                                        path_cpy += 2;
433                                        continue;
434                                }
435
436                                /* collapse /x/../ */
437                                else if( (path_cpy[2] == '.') &&
438                                         ((path_cpy[3] == '/') || (path_cpy[3] == '\0'))
439                                ) {
440                                        while( (path_res > path_resolved) && (*--path_res != '/') )
441                                                ;
442
443                                        path_cpy += 3;
444                                        continue;
445                                }
446                        }
447                }
448
449                *path_res++ = *path_cpy++;
450        }
451
452        /* remove trailing slash if not root / */
453        if( (path_res > (path_resolved+1)) && (path_res[-1] == '/') )
454                path_res--;
455        else if( path_res == path_resolved )
456                *path_res++ = '/';
457
458        *path_res = '\0';
459
460        /* test access */
461        if( !stat(path_resolved, &s) && (s.st_mode & S_IROTH) )
462                return path_resolved;
463
464        return NULL;
465}
466
467struct path_info * uh_path_lookup(struct client *cl, const char *url)
468{
469        static char path_phys[PATH_MAX];
470        static char path_info[PATH_MAX];
471        static struct path_info p;
472
473        char buffer[UH_LIMIT_MSGHEAD];
474        char *docroot = cl->server->conf->docroot;
475        char *pathptr = NULL;
476
477        int no_sym = cl->server->conf->no_symlinks;
478        int i = 0;
479        struct stat s;
480
481        /* back out early if url is undefined */
482        if ( url == NULL )
483                return NULL;
484
485        memset(path_phys, 0, sizeof(path_phys));
486        memset(path_info, 0, sizeof(path_info));
487        memset(buffer, 0, sizeof(buffer));
488        memset(&p, 0, sizeof(p));
489
490        /* copy docroot */
491        memcpy(buffer, docroot,
492                min(strlen(docroot), sizeof(buffer) - 1));
493
494        /* separate query string from url */
495        if( (pathptr = strchr(url, '?')) != NULL )
496        {
497                p.query = pathptr[1] ? pathptr + 1 : NULL;
498
499                /* urldecode component w/o query */
500                if( pathptr > url )
501                        uh_urldecode(
502                                &buffer[strlen(docroot)],
503                                sizeof(buffer) - strlen(docroot) - 1,
504                                url, (int)(pathptr - url) - 1
505                        );
506        }
507
508        /* no query string, decode all of url */
509        else
510        {
511                uh_urldecode(
512                        &buffer[strlen(docroot)],
513                        sizeof(buffer) - strlen(docroot) - 1,
514                        url, strlen(url)
515                );
516        }
517
518        /* create canon path */
519        for( i = strlen(buffer); i >= 0; i-- )
520        {
521                if( (buffer[i] == 0) || (buffer[i] == '/') )
522                {
523                        memset(path_info, 0, sizeof(path_info));
524                        memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
525
526                        if( no_sym ? realpath(path_info, path_phys)
527                                   : canonpath(path_info, path_phys)
528                        ) {
529                                memset(path_info, 0, sizeof(path_info));
530                                memcpy(path_info, &buffer[i],
531                                        min(strlen(buffer) - i, sizeof(path_info) - 1));
532
533                                break;
534                        }
535                }
536        }
537
538        /* check whether found path is within docroot */
539        if( strncmp(path_phys, docroot, strlen(docroot)) ||
540            ((path_phys[strlen(docroot)] != 0) &&
541                 (path_phys[strlen(docroot)] != '/'))
542        ) {
543                return NULL;
544        }
545
546        /* test current path */
547        if( ! stat(path_phys, &p.stat) )
548        {
549                /* is a regular file */
550                if( p.stat.st_mode & S_IFREG )
551                {
552                        p.root = docroot;
553                        p.phys = path_phys;
554                        p.name = &path_phys[strlen(docroot)];
555                        p.info = path_info[0] ? path_info : NULL;
556                }
557
558                /* is a directory */
559                else if( (p.stat.st_mode & S_IFDIR) && !strlen(path_info) )
560                {
561                        /* ensure trailing slash */
562                        if( path_phys[strlen(path_phys)-1] != '/' )
563                                path_phys[strlen(path_phys)] = '/';
564
565                        /* try to locate index file */
566                        memset(buffer, 0, sizeof(buffer));
567                        memcpy(buffer, path_phys, sizeof(buffer));
568                        pathptr = &buffer[strlen(buffer)];
569
570                        if( cl->server->conf->index_file )
571                        {
572                                strncat(buffer, cl->server->conf->index_file, sizeof(buffer));
573
574                                if( !stat(buffer, &s) && (s.st_mode & S_IFREG) )
575                                {
576                                        memcpy(path_phys, buffer, sizeof(path_phys));
577                                        memcpy(&p.stat, &s, sizeof(p.stat));
578                                }
579                        }
580                        else
581                        {
582                                for( i = 0; i < array_size(uh_index_files); i++ )
583                                {
584                                        strncat(buffer, uh_index_files[i], sizeof(buffer));
585
586                                        if( !stat(buffer, &s) && (s.st_mode & S_IFREG) )
587                                        {
588                                                memcpy(path_phys, buffer, sizeof(path_phys));
589                                                memcpy(&p.stat, &s, sizeof(p.stat));
590                                                break;
591                                        }
592
593                                        *pathptr = 0;
594                                }
595                        }
596
597                        p.root = docroot;
598                        p.phys = path_phys;
599                        p.name = &path_phys[strlen(docroot)];
600                }
601        }
602
603        return p.phys ? &p : NULL;
604}
605
606
607static struct auth_realm *uh_realms = NULL;
608
609struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
610{
611        struct auth_realm *new = NULL;
612        struct passwd *pwd;
613        struct spwd *spwd;
614
615        if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)
616        {
617                memset(new, 0, sizeof(struct auth_realm));
618
619                memcpy(new->path, path,
620                        min(strlen(path), sizeof(new->path) - 1));
621
622                memcpy(new->user, user,
623                        min(strlen(user), sizeof(new->user) - 1));
624
625                /* given password refers to a passwd entry */
626                if( (strlen(pass) > 3) && !strncmp(pass, "$p$", 3) )
627                {
628                        /* try to resolve shadow entry */
629                        if( ((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp )
630                        {
631                                memcpy(new->pass, spwd->sp_pwdp,
632                                        min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1));
633                        }
634
635                        /* try to resolve passwd entry */
636                        else if( ((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd &&
637                                (pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0)
638                        ) {
639                                memcpy(new->pass, pwd->pw_passwd,
640                                        min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
641                        }
642                }
643
644                /* ordinary pwd */
645                else
646                {
647                        memcpy(new->pass, pass,
648                                min(strlen(pass), sizeof(new->pass) - 1));
649                }
650
651                if( new->pass[0] )
652                {
653                        new->next = uh_realms;
654                        uh_realms = new;
655
656                        return new;
657                }
658
659                free(new);
660        }
661
662        return NULL;
663}
664
665int uh_auth_check(
666        struct client *cl, struct http_request *req, struct path_info *pi
667) {
668        int i, plen, rlen, protected;
669        char buffer[UH_LIMIT_MSGHEAD];
670        char *user = NULL;
671        char *pass = NULL;
672
673        struct auth_realm *realm = NULL;
674
675        plen = strlen(pi->name);
676        protected = 0;
677
678        /* check whether at least one realm covers the requested url */
679        for( realm = uh_realms; realm; realm = realm->next )
680        {
681                rlen = strlen(realm->path);
682
683                if( (plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen) )
684                {
685                        req->realm = realm;
686                        protected = 1;
687                        break;
688                }
689        }
690
691        /* requested resource is covered by a realm */
692        if( protected )
693        {
694                /* try to get client auth info */
695                foreach_header(i, req->headers)
696                {
697                        if( !strcasecmp(req->headers[i], "Authorization") &&
698                                (strlen(req->headers[i+1]) > 6) &&
699                                !strncasecmp(req->headers[i+1], "Basic ", 6)
700                        ) {
701                                memset(buffer, 0, sizeof(buffer));
702                                uh_b64decode(buffer, sizeof(buffer) - 1,
703                                        (unsigned char *) &req->headers[i+1][6],
704                                        strlen(req->headers[i+1]) - 6);
705
706                                if( (pass = strchr(buffer, ':')) != NULL )
707                                {
708                                        user = buffer;
709                                        *pass++ = 0;
710                                }
711
712                                break;
713                        }
714                }
715
716                /* have client auth */
717                if( user && pass )
718                {
719                        /* find matching realm */
720                        for( realm = uh_realms; realm; realm = realm->next )
721                        {
722                                rlen = strlen(realm->path);
723
724                                if( (plen >= rlen) &&
725                                    !strncasecmp(pi->name, realm->path, rlen) &&
726                                    !strcmp(user, realm->user)
727                                ) {
728                                        req->realm = realm;
729                                        break;
730                                }
731
732                                realm = NULL;
733                        }
734
735                        /* found a realm matching the username */
736                        if( realm )
737                        {
738                                /* is a crypt passwd */
739                                if( realm->pass[0] == '$' )
740                                        pass = crypt(pass, realm->pass);
741
742                                /* check user pass */
743                                if( !strcmp(pass, realm->pass) )
744                                        return 1;
745                        }
746                }
747
748                /* 401 */
749                uh_http_sendf(cl, NULL,
750                        "HTTP/%.1f 401 Authorization Required\r\n"
751                        "WWW-Authenticate: Basic realm=\"%s\"\r\n"
752                        "Content-Type: text/plain\r\n"
753                        "Content-Length: 23\r\n\r\n"
754                        "Authorization Required\n",
755                                req->version, cl->server->conf->realm
756                );
757
758                return 0;
759        }
760
761        return 1;
762}
763
764
765static struct listener *uh_listeners = NULL;
766static struct client *uh_clients = NULL;
767
768struct listener * uh_listener_add(int sock, struct config *conf)
769{
770        struct listener *new = NULL;
771        socklen_t sl;
772
773        if( (new = (struct listener *)malloc(sizeof(struct listener))) != NULL )
774        {
775                memset(new, 0, sizeof(struct listener));
776
777                new->socket = sock;
778                new->conf   = conf;
779
780                /* get local endpoint addr */
781                sl = sizeof(struct sockaddr_in6);
782                memset(&(new->addr), 0, sl);
783                getsockname(sock, (struct sockaddr *) &(new->addr), &sl);
784
785                new->next = uh_listeners;
786                uh_listeners = new;
787
788                return new;
789        }
790
791        return NULL;
792}
793
794struct listener * uh_listener_lookup(int sock)
795{
796        struct listener *cur = NULL;
797
798        for( cur = uh_listeners; cur; cur = cur->next )
799                if( cur->socket == sock )
800                        return cur;
801
802        return NULL;
803}
804
805
806struct client * uh_client_add(int sock, struct listener *serv)
807{
808        struct client *new = NULL;
809        socklen_t sl;
810
811        if( (new = (struct client *)malloc(sizeof(struct client))) != NULL )
812        {
813                memset(new, 0, sizeof(struct client));
814
815                new->socket = sock;
816                new->server = serv;
817
818                /* get remote endpoint addr */
819                sl = sizeof(struct sockaddr_in6);
820                memset(&(new->peeraddr), 0, sl);
821                getpeername(sock, (struct sockaddr *) &(new->peeraddr), &sl);
822
823                /* get local endpoint addr */
824                sl = sizeof(struct sockaddr_in6);
825                memset(&(new->servaddr), 0, sl);
826                getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
827
828                new->next = uh_clients;
829                uh_clients = new;
830        }
831
832        return new;
833}
834
835struct client * uh_client_lookup(int sock)
836{
837        struct client *cur = NULL;
838
839        for( cur = uh_clients; cur; cur = cur->next )
840                if( cur->socket == sock )
841                        return cur;
842
843        return NULL;
844}
845
846void uh_client_remove(int sock)
847{
848        struct client *cur = NULL;
849        struct client *prv = NULL;
850
851        for( cur = uh_clients; cur; prv = cur, cur = cur->next )
852        {
853                if( cur->socket == sock )
854                {
855                        if( prv )
856                                prv->next = cur->next;
857                        else
858                                uh_clients = cur->next;
859
860                        free(cur);
861                        break;
862                }
863        }
864}
865
866
867#ifdef HAVE_CGI
868static struct interpreter *uh_interpreters = NULL;
869
870struct interpreter * uh_interpreter_add(const char *extn, const char *path)
871{
872        struct interpreter *new = NULL;
873
874        if( (new = (struct interpreter *)
875                        malloc(sizeof(struct interpreter))) != NULL )
876        {
877                memset(new, 0, sizeof(struct interpreter));
878
879                memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1));
880                memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1));
881
882                new->next = uh_interpreters;
883                uh_interpreters = new;
884
885                return new;
886        }
887
888        return NULL;
889}
890
891struct interpreter * uh_interpreter_lookup(const char *path)
892{
893        struct interpreter *cur = NULL;
894        const char *e;
895
896        for( cur = uh_interpreters; cur; cur = cur->next )
897        {
898                e = &path[max(strlen(path) - strlen(cur->extn), 0)];
899
900                if( !strcmp(e, cur->extn) )
901                        return cur;
902        }
903
904        return NULL;
905}
906#endif
Note: See TracBrowser for help on using the repository browser.