18969e74dd80a519197cf02c91a5940cc03e6a5a
[openwrt/svn-archive/archive.git] / package / uhttpd / src / uhttpd-utils.c
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
30 static char *uh_index_files[] = {
31 "index.html",
32 "index.htm",
33 "default.html",
34 "default.htm"
35 };
36
37
38 const 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
50 const 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
57 int sa_port(void *sa)
58 {
59 return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
60 }
61
62 int 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. */
78 char *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() */
107 int 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
127 int uh_tcp_send_lowlevel(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 return send(cl->socket, buf, len, 0);
140
141 return -1;
142 }
143
144 int uh_tcp_send(struct client *cl, const char *buf, int len)
145 {
146 #ifdef HAVE_TLS
147 if (cl->tls)
148 return cl->server->conf->tls_send(cl, (void *)buf, len);
149 else
150 #endif
151 return uh_tcp_send_lowlevel(cl, buf, len);
152 }
153
154 int uh_tcp_peek(struct client *cl, char *buf, int len)
155 {
156 /* sanity check, prevent overflowing peek buffer */
157 if (len > sizeof(cl->peekbuf))
158 return -1;
159
160 int sz = uh_tcp_recv(cl, buf, len);
161
162 /* store received data in peek buffer */
163 if (sz > 0)
164 {
165 cl->peeklen = sz;
166 memcpy(cl->peekbuf, buf, sz);
167 }
168
169 return sz;
170 }
171
172 int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
173 {
174 fd_set reader;
175 struct timeval timeout;
176
177 FD_ZERO(&reader);
178 FD_SET(cl->socket, &reader);
179
180 timeout.tv_sec = cl->server->conf->network_timeout;
181 timeout.tv_usec = 0;
182
183 if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0)
184 return recv(cl->socket, buf, len, 0);
185
186 return -1;
187 }
188
189 int uh_tcp_recv(struct client *cl, char *buf, int len)
190 {
191 int sz = 0;
192 int rsz = 0;
193
194 /* first serve data from peek buffer */
195 if (cl->peeklen > 0)
196 {
197 sz = min(cl->peeklen, len);
198 len -= sz; cl->peeklen -= sz;
199 memcpy(buf, cl->peekbuf, sz);
200 memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
201 }
202
203 /* caller wants more */
204 if (len > 0)
205 {
206 #ifdef HAVE_TLS
207 if (cl->tls)
208 rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
209 else
210 #endif
211 rsz = uh_tcp_recv_lowlevel(cl, (void *)&buf[sz], len);
212
213 if (rsz < 0)
214 return rsz;
215
216 sz += rsz;
217 }
218
219 return sz;
220 }
221
222
223 int uh_http_sendhf(struct client *cl, int code, const char *summary,
224 const char *fmt, ...)
225 {
226 va_list ap;
227
228 char buffer[UH_LIMIT_MSGHEAD];
229 int len;
230
231 len = snprintf(buffer, sizeof(buffer),
232 "HTTP/1.1 %03i %s\r\n"
233 "Connection: close\r\n"
234 "Content-Type: text/plain\r\n"
235 "Transfer-Encoding: chunked\r\n\r\n",
236 code, summary
237 );
238
239 ensure_ret(uh_tcp_send(cl, buffer, len));
240
241 va_start(ap, fmt);
242 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
243 va_end(ap);
244
245 ensure_ret(uh_http_sendc(cl, buffer, len));
246 ensure_ret(uh_http_sendc(cl, NULL, 0));
247
248 return 0;
249 }
250
251
252 int uh_http_sendc(struct client *cl, const char *data, int len)
253 {
254 char chunk[8];
255 int clen;
256
257 if (len == -1)
258 len = strlen(data);
259
260 if (len > 0)
261 {
262 clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
263 ensure_ret(uh_tcp_send(cl, chunk, clen));
264 ensure_ret(uh_tcp_send(cl, data, len));
265 ensure_ret(uh_tcp_send(cl, "\r\n", 2));
266 }
267 else
268 {
269 ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5));
270 }
271
272 return 0;
273 }
274
275 int uh_http_sendf(struct client *cl, struct http_request *req,
276 const char *fmt, ...)
277 {
278 va_list ap;
279 char buffer[UH_LIMIT_MSGHEAD];
280 int len;
281
282 va_start(ap, fmt);
283 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
284 va_end(ap);
285
286 if ((req != NULL) && (req->version > 1.0))
287 ensure_ret(uh_http_sendc(cl, buffer, len));
288 else if (len > 0)
289 ensure_ret(uh_tcp_send(cl, buffer, len));
290
291 return 0;
292 }
293
294 int uh_http_send(struct client *cl, struct http_request *req,
295 const char *buf, int len)
296 {
297 if (len < 0)
298 len = strlen(buf);
299
300 if ((req != NULL) && (req->version > 1.0))
301 ensure_ret(uh_http_sendc(cl, buf, len));
302 else if (len > 0)
303 ensure_ret(uh_tcp_send(cl, buf, len));
304
305 return 0;
306 }
307
308
309 /* blen is the size of buf; slen is the length of src. The input-string need
310 ** not be, and the output string will not be, null-terminated. Returns the
311 ** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
312 int uh_urldecode(char *buf, int blen, const char *src, int slen)
313 {
314 int i;
315 int len = 0;
316
317 #define hex(x) \
318 (((x) <= '9') ? ((x) - '0') : \
319 (((x) <= 'F') ? ((x) - 'A' + 10) : \
320 ((x) - 'a' + 10)))
321
322 for (i = 0; (i < slen) && (len < blen); i++)
323 {
324 if (src[i] == '%')
325 {
326 if (((i+2) < slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]))
327 {
328 buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
329 i += 2;
330 }
331 else
332 {
333 /* Encoding error: it's hard to think of a
334 ** scenario in which returning an incorrect
335 ** 'decoding' of the malformed string is
336 ** preferable to signaling an error condition. */
337 #if 0 /* WORSE_IS_BETTER */
338 buf[len++] = '%';
339 #else
340 return -2;
341 #endif
342 }
343 }
344 else
345 {
346 buf[len++] = src[i];
347 }
348 }
349
350 return (i == slen) ? len : -1;
351 }
352
353 /* blen is the size of buf; slen is the length of src. The input-string need
354 ** not be, and the output string will not be, null-terminated. Returns the
355 ** length of the encoded string, or -1 on error (buffer overflow) */
356 int uh_urlencode(char *buf, int blen, const char *src, int slen)
357 {
358 int i;
359 int len = 0;
360 const char hex[] = "0123456789abcdef";
361
362 for (i = 0; (i < slen) && (len < blen); i++)
363 {
364 if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
365 (src[i] == '.') || (src[i] == '~') )
366 {
367 buf[len++] = src[i];
368 }
369 else if ((len+3) <= blen)
370 {
371 buf[len++] = '%';
372 buf[len++] = hex[(src[i] >> 4) & 15];
373 buf[len++] = hex[ src[i] & 15];
374 }
375 else
376 {
377 len = -1;
378 break;
379 }
380 }
381
382 return (i == slen) ? len : -1;
383 }
384
385 int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
386 {
387 int i = 0;
388 int len = 0;
389
390 unsigned int cin = 0;
391 unsigned int cout = 0;
392
393
394 for (i = 0; (i <= slen) && (src[i] != 0); i++)
395 {
396 cin = src[i];
397
398 if ((cin >= '0') && (cin <= '9'))
399 cin = cin - '0' + 52;
400 else if ((cin >= 'A') && (cin <= 'Z'))
401 cin = cin - 'A';
402 else if ((cin >= 'a') && (cin <= 'z'))
403 cin = cin - 'a' + 26;
404 else if (cin == '+')
405 cin = 62;
406 else if (cin == '/')
407 cin = 63;
408 else if (cin == '=')
409 cin = 0;
410 else
411 continue;
412
413 cout = (cout << 6) | cin;
414
415 if ((i % 4) == 3)
416 {
417 if ((len + 3) < blen)
418 {
419 buf[len++] = (char)(cout >> 16);
420 buf[len++] = (char)(cout >> 8);
421 buf[len++] = (char)(cout);
422 }
423 else
424 {
425 break;
426 }
427 }
428 }
429
430 buf[len++] = 0;
431 return len;
432 }
433
434 static char * canonpath(const char *path, char *path_resolved)
435 {
436 char path_copy[PATH_MAX];
437 char *path_cpy = path_copy;
438 char *path_res = path_resolved;
439
440 struct stat s;
441
442
443 /* relative -> absolute */
444 if (*path != '/')
445 {
446 getcwd(path_copy, PATH_MAX);
447 strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
448 strncat(path_copy, path, PATH_MAX - strlen(path_copy));
449 }
450 else
451 {
452 strncpy(path_copy, path, PATH_MAX);
453 }
454
455 /* normalize */
456 while ((*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)))
457 {
458 if (*path_cpy == '/')
459 {
460 /* skip repeating / */
461 if (path_cpy[1] == '/')
462 {
463 path_cpy++;
464 continue;
465 }
466
467 /* /./ or /../ */
468 else if (path_cpy[1] == '.')
469 {
470 /* skip /./ */
471 if ((path_cpy[2] == '/') || (path_cpy[2] == '\0'))
472 {
473 path_cpy += 2;
474 continue;
475 }
476
477 /* collapse /x/../ */
478 else if ((path_cpy[2] == '.') &&
479 ((path_cpy[3] == '/') || (path_cpy[3] == '\0')))
480 {
481 while ((path_res > path_resolved) && (*--path_res != '/'))
482 ;
483
484 path_cpy += 3;
485 continue;
486 }
487 }
488 }
489
490 *path_res++ = *path_cpy++;
491 }
492
493 /* remove trailing slash if not root / */
494 if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
495 path_res--;
496 else if (path_res == path_resolved)
497 *path_res++ = '/';
498
499 *path_res = '\0';
500
501 /* test access */
502 if (!stat(path_resolved, &s) && (s.st_mode & S_IROTH))
503 return path_resolved;
504
505 return NULL;
506 }
507
508 /* Returns NULL on error.
509 ** NB: improperly encoded URL should give client 400 [Bad Syntax]; returning
510 ** NULL here causes 404 [Not Found], but that's not too unreasonable. */
511 struct path_info * uh_path_lookup(struct client *cl, const char *url)
512 {
513 static char path_phys[PATH_MAX];
514 static char path_info[PATH_MAX];
515 static struct path_info p;
516
517 char buffer[UH_LIMIT_MSGHEAD];
518 char *docroot = cl->server->conf->docroot;
519 char *pathptr = NULL;
520
521 int slash = 0;
522 int no_sym = cl->server->conf->no_symlinks;
523 int i = 0;
524 struct stat s;
525
526 /* back out early if url is undefined */
527 if (url == NULL)
528 return NULL;
529
530 memset(path_phys, 0, sizeof(path_phys));
531 memset(path_info, 0, sizeof(path_info));
532 memset(buffer, 0, sizeof(buffer));
533 memset(&p, 0, sizeof(p));
534
535 /* copy docroot */
536 memcpy(buffer, docroot,
537 min(strlen(docroot), sizeof(buffer) - 1));
538
539 /* separate query string from url */
540 if ((pathptr = strchr(url, '?')) != NULL)
541 {
542 p.query = pathptr[1] ? pathptr + 1 : NULL;
543
544 /* urldecode component w/o query */
545 if (pathptr > url)
546 {
547 if (uh_urldecode(&buffer[strlen(docroot)],
548 sizeof(buffer) - strlen(docroot) - 1,
549 url, pathptr - url ) < 0)
550 {
551 return NULL; /* bad URL */
552 }
553 }
554 }
555
556 /* no query string, decode all of url */
557 else
558 {
559 if (uh_urldecode(&buffer[strlen(docroot)],
560 sizeof(buffer) - strlen(docroot) - 1,
561 url, strlen(url) ) < 0)
562 {
563 return NULL; /* bad URL */
564 }
565 }
566
567 /* create canon path */
568 for (i = strlen(buffer), slash = (buffer[max(0, i-1)] == '/'); i >= 0; i--)
569 {
570 if ((buffer[i] == 0) || (buffer[i] == '/'))
571 {
572 memset(path_info, 0, sizeof(path_info));
573 memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
574
575 if (no_sym ? realpath(path_info, path_phys)
576 : canonpath(path_info, path_phys))
577 {
578 memset(path_info, 0, sizeof(path_info));
579 memcpy(path_info, &buffer[i],
580 min(strlen(buffer) - i, sizeof(path_info) - 1));
581
582 break;
583 }
584 }
585 }
586
587 /* check whether found path is within docroot */
588 if (strncmp(path_phys, docroot, strlen(docroot)) ||
589 ((path_phys[strlen(docroot)] != 0) &&
590 (path_phys[strlen(docroot)] != '/')))
591 {
592 return NULL;
593 }
594
595 /* test current path */
596 if (!stat(path_phys, &p.stat))
597 {
598 /* is a regular file */
599 if (p.stat.st_mode & S_IFREG)
600 {
601 p.root = docroot;
602 p.phys = path_phys;
603 p.name = &path_phys[strlen(docroot)];
604 p.info = path_info[0] ? path_info : NULL;
605 }
606
607 /* is a directory */
608 else if ((p.stat.st_mode & S_IFDIR) && !strlen(path_info))
609 {
610 /* ensure trailing slash */
611 if (path_phys[strlen(path_phys)-1] != '/')
612 path_phys[strlen(path_phys)] = '/';
613
614 /* try to locate index file */
615 memset(buffer, 0, sizeof(buffer));
616 memcpy(buffer, path_phys, sizeof(buffer));
617 pathptr = &buffer[strlen(buffer)];
618
619 /* if requested url resolves to a directory and a trailing slash
620 is missing in the request url, redirect the client to the same
621 url with trailing slash appended */
622 if (!slash)
623 {
624 uh_http_sendf(cl, NULL,
625 "HTTP/1.1 302 Found\r\n"
626 "Location: %s%s%s\r\n"
627 "Connection: close\r\n\r\n",
628 &path_phys[strlen(docroot)],
629 p.query ? "?" : "",
630 p.query ? p.query : ""
631 );
632
633 p.redirected = 1;
634 }
635 else if (cl->server->conf->index_file)
636 {
637 strncat(buffer, cl->server->conf->index_file, sizeof(buffer));
638
639 if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
640 {
641 memcpy(path_phys, buffer, sizeof(path_phys));
642 memcpy(&p.stat, &s, sizeof(p.stat));
643 }
644 }
645 else
646 {
647 for (i = 0; i < array_size(uh_index_files); i++)
648 {
649 strncat(buffer, uh_index_files[i], sizeof(buffer));
650
651 if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
652 {
653 memcpy(path_phys, buffer, sizeof(path_phys));
654 memcpy(&p.stat, &s, sizeof(p.stat));
655 break;
656 }
657
658 *pathptr = 0;
659 }
660 }
661
662 p.root = docroot;
663 p.phys = path_phys;
664 p.name = &path_phys[strlen(docroot)];
665 }
666 }
667
668 return p.phys ? &p : NULL;
669 }
670
671
672 static struct auth_realm *uh_realms = NULL;
673
674 struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
675 {
676 struct auth_realm *new = NULL;
677 struct passwd *pwd;
678
679 #ifdef HAVE_SHADOW
680 struct spwd *spwd;
681 #endif
682
683 if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)
684 {
685 memset(new, 0, sizeof(struct auth_realm));
686
687 memcpy(new->path, path,
688 min(strlen(path), sizeof(new->path) - 1));
689
690 memcpy(new->user, user,
691 min(strlen(user), sizeof(new->user) - 1));
692
693 /* given password refers to a passwd entry */
694 if ((strlen(pass) > 3) && !strncmp(pass, "$p$", 3))
695 {
696 #ifdef HAVE_SHADOW
697 /* try to resolve shadow entry */
698 if (((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp)
699 {
700 memcpy(new->pass, spwd->sp_pwdp,
701 min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1));
702 }
703
704 else
705 #endif
706
707 /* try to resolve passwd entry */
708 if (((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd &&
709 (pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0))
710 {
711 memcpy(new->pass, pwd->pw_passwd,
712 min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
713 }
714 }
715
716 /* ordinary pwd */
717 else
718 {
719 memcpy(new->pass, pass,
720 min(strlen(pass), sizeof(new->pass) - 1));
721 }
722
723 if (new->pass[0])
724 {
725 new->next = uh_realms;
726 uh_realms = new;
727
728 return new;
729 }
730
731 free(new);
732 }
733
734 return NULL;
735 }
736
737 int uh_auth_check(struct client *cl, struct http_request *req,
738 struct path_info *pi)
739 {
740 int i, plen, rlen, protected;
741 char buffer[UH_LIMIT_MSGHEAD];
742 char *user = NULL;
743 char *pass = NULL;
744
745 struct auth_realm *realm = NULL;
746
747 plen = strlen(pi->name);
748 protected = 0;
749
750 /* check whether at least one realm covers the requested url */
751 for (realm = uh_realms; realm; realm = realm->next)
752 {
753 rlen = strlen(realm->path);
754
755 if ((plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen))
756 {
757 req->realm = realm;
758 protected = 1;
759 break;
760 }
761 }
762
763 /* requested resource is covered by a realm */
764 if (protected)
765 {
766 /* try to get client auth info */
767 foreach_header(i, req->headers)
768 {
769 if (!strcasecmp(req->headers[i], "Authorization") &&
770 (strlen(req->headers[i+1]) > 6) &&
771 !strncasecmp(req->headers[i+1], "Basic ", 6))
772 {
773 memset(buffer, 0, sizeof(buffer));
774 uh_b64decode(buffer, sizeof(buffer) - 1,
775 (unsigned char *) &req->headers[i+1][6],
776 strlen(req->headers[i+1]) - 6);
777
778 if ((pass = strchr(buffer, ':')) != NULL)
779 {
780 user = buffer;
781 *pass++ = 0;
782 }
783
784 break;
785 }
786 }
787
788 /* have client auth */
789 if (user && pass)
790 {
791 /* find matching realm */
792 for (realm = uh_realms; realm; realm = realm->next)
793 {
794 rlen = strlen(realm->path);
795
796 if ((plen >= rlen) &&
797 !strncasecmp(pi->name, realm->path, rlen) &&
798 !strcmp(user, realm->user))
799 {
800 req->realm = realm;
801 break;
802 }
803 }
804
805 /* found a realm matching the username */
806 if (realm)
807 {
808 /* check user pass */
809 if (!strcmp(pass, realm->pass) ||
810 !strcmp(crypt(pass, realm->pass), realm->pass))
811 return 1;
812 }
813 }
814
815 /* 401 */
816 uh_http_sendf(cl, NULL,
817 "HTTP/%.1f 401 Authorization Required\r\n"
818 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
819 "Content-Type: text/plain\r\n"
820 "Content-Length: 23\r\n\r\n"
821 "Authorization Required\n",
822 req->version, cl->server->conf->realm
823 );
824
825 return 0;
826 }
827
828 return 1;
829 }
830
831
832 static struct listener *uh_listeners = NULL;
833 static struct client *uh_clients = NULL;
834
835 struct listener * uh_listener_add(int sock, struct config *conf)
836 {
837 struct listener *new = NULL;
838 socklen_t sl;
839
840 if ((new = (struct listener *)malloc(sizeof(struct listener))) != NULL)
841 {
842 memset(new, 0, sizeof(struct listener));
843
844 new->socket = sock;
845 new->conf = conf;
846
847 /* get local endpoint addr */
848 sl = sizeof(struct sockaddr_in6);
849 memset(&(new->addr), 0, sl);
850 getsockname(sock, (struct sockaddr *) &(new->addr), &sl);
851
852 new->next = uh_listeners;
853 uh_listeners = new;
854
855 return new;
856 }
857
858 return NULL;
859 }
860
861 struct listener * uh_listener_lookup(int sock)
862 {
863 struct listener *cur = NULL;
864
865 for (cur = uh_listeners; cur; cur = cur->next)
866 if (cur->socket == sock)
867 return cur;
868
869 return NULL;
870 }
871
872
873 struct client * uh_client_add(int sock, struct listener *serv)
874 {
875 struct client *new = NULL;
876 socklen_t sl;
877
878 if ((new = (struct client *)malloc(sizeof(struct client))) != NULL)
879 {
880 memset(new, 0, sizeof(struct client));
881
882 new->socket = sock;
883 new->server = serv;
884
885 /* get remote endpoint addr */
886 sl = sizeof(struct sockaddr_in6);
887 memset(&(new->peeraddr), 0, sl);
888 getpeername(sock, (struct sockaddr *) &(new->peeraddr), &sl);
889
890 /* get local endpoint addr */
891 sl = sizeof(struct sockaddr_in6);
892 memset(&(new->servaddr), 0, sl);
893 getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
894
895 new->next = uh_clients;
896 uh_clients = new;
897 }
898
899 return new;
900 }
901
902 struct client * uh_client_lookup(int sock)
903 {
904 struct client *cur = NULL;
905
906 for (cur = uh_clients; cur; cur = cur->next)
907 if (cur->socket == sock)
908 return cur;
909
910 return NULL;
911 }
912
913 void uh_client_remove(int sock)
914 {
915 struct client *cur = NULL;
916 struct client *prv = NULL;
917
918 for (cur = uh_clients; cur; prv = cur, cur = cur->next)
919 {
920 if (cur->socket == sock)
921 {
922 if (prv)
923 prv->next = cur->next;
924 else
925 uh_clients = cur->next;
926
927 free(cur);
928 break;
929 }
930 }
931 }
932
933
934 #ifdef HAVE_CGI
935 static struct interpreter *uh_interpreters = NULL;
936
937 struct interpreter * uh_interpreter_add(const char *extn, const char *path)
938 {
939 struct interpreter *new = NULL;
940
941 if ((new = (struct interpreter *)malloc(sizeof(struct interpreter))) != NULL)
942 {
943 memset(new, 0, sizeof(struct interpreter));
944
945 memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1));
946 memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1));
947
948 new->next = uh_interpreters;
949 uh_interpreters = new;
950
951 return new;
952 }
953
954 return NULL;
955 }
956
957 struct interpreter * uh_interpreter_lookup(const char *path)
958 {
959 struct interpreter *cur = NULL;
960 const char *e;
961
962 for (cur = uh_interpreters; cur; cur = cur->next)
963 {
964 e = &path[max(strlen(path) - strlen(cur->extn), 0)];
965
966 if (!strcmp(e, cur->extn))
967 return cur;
968 }
969
970 return NULL;
971 }
972 #endif