source: Main/trunk/Server/server.c@ 405

Last change on this file since 405 was 402, checked in by Nishi, on Nov 3, 2024 at 7:39:59 PM

amiga

  • Property svn:keywords set to Id
File size: 30.9 KB
Line 
1/* $Id: server.c 402 2024-11-03 10:39:59Z nishi $ */
2
3#define SOURCE
4
5#include "../config.h"
6
7#include "tw_server.h"
8
9#ifndef NO_SSL
10#include "tw_ssl.h"
11#endif
12
13#include "tw_config.h"
14#include "tw_http.h"
15#include "tw_module.h"
16#include "tw_version.h"
17
18#ifdef __amiga__
19#include <pthread.h>
20#endif
21
22#if !defined(_MSC_VER) && !defined(__BORLANDC__)
23#include <unistd.h>
24#endif
25#include <ctype.h>
26#include <string.h>
27#include <stdbool.h>
28#include <stdarg.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <errno.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <time.h>
35
36#include <cm_string.h>
37#include <cm_log.h>
38#include <cm_dir.h>
39
40#ifdef __OS2__
41#include <types.h>
42#include <sys/time.h>
43#define INCL_DOSPROCESS
44#include <os2.h>
45#include <process.h>
46#define HANDLE void*
47
48#include "strptime.h"
49typedef int socklen_t;
50
51#include <tcpustd.h>
52#endif
53
54#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__OS2__) && !defined(__NETWARE__) && !defined(__DOS__))
55#ifndef NO_GETNAMEINFO
56#include <ws2tcpip.h>
57#include <wspiapi.h>
58#endif
59#ifdef USE_WINSOCK1
60#include <winsock.h>
61#else
62#include <winsock2.h>
63#endif
64#include <process.h>
65#include <windows.h>
66
67#include "strptime.h"
68typedef int socklen_t;
69#elif defined(__NETWARE__)
70#include <sys/bsdskt.h>
71#include <sys/socket.h>
72
73#define IPPROTO_TCP 0
74#define INADDR_ANY 0
75#include "strptime.h"
76typedef int socklen_t;
77
78uint16_t htons(uint16_t n) { return ((n >> 8) & 0xff) | ((n << 8) & 0xff00); }
79#elif defined(__DOS__)
80#include <netinet/tcp.h>
81#include <netinet/in.h>
82#include <arpa/inet.h>
83#include <sys/select.h>
84
85#include "strptime.h"
86#else
87#ifdef USE_POLL
88#ifdef __PPU__
89#include <net/poll.h>
90#else
91#include <poll.h>
92#endif
93#else
94#ifndef __NeXT__
95#include <sys/select.h>
96#endif
97#ifdef __OS2__
98#include <netinet/in.h>
99#endif
100#endif
101#include <sys/socket.h>
102#include <arpa/inet.h>
103#if !defined(__PPU__)
104#ifdef __NeXT__
105#include <netinet/in_systm.h>
106#endif
107#include <netinet/tcp.h>
108#endif
109#ifndef NO_GETNAMEINFO
110#include <netdb.h>
111#endif
112#endif
113
114#if defined(_PSP) || defined(__ps2sdk__) || defined(__bsdi__) || defined(__amiga__)
115#include "strptime.h"
116#endif
117
118#ifdef __HAIKU__
119#include <OS.h>
120#endif
121
122#ifdef __NeXT__
123#include <sys/time.h>
124#endif
125
126#if defined(__USLC__) || defined(__NeXT__)
127typedef int socklen_t;
128#endif
129
130#ifndef S_ISDIR
131#define S_ISDIR(x) ((x) & _S_IFDIR)
132#endif
133
134extern struct tw_config config;
135extern char tw_server[];
136
137int sockcount = 0;
138
139SOCKADDR addresses[MAX_PORTS];
140int sockets[MAX_PORTS];
141
142#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
143const char* reserved_names[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
144#endif
145
146/* https://qiita.com/gyu-don/items/5a640c6d2252a860c8cd */
147int tw_wildcard_match(const char* wildcard, const char* target) {
148 const char *pw = wildcard, *pt = target;
149
150 while(1) {
151 if(*pt == 0) {
152 while(*pw == '*') pw++;
153 return *pw == 0;
154 } else if(*pw == 0) {
155 return 0;
156 } else if(*pw == '*') {
157 return *(pw + 1) == 0 || tw_wildcard_match(pw, pt + 1) || tw_wildcard_match(pw + 1, pt);
158 } else if(*pw == '?' || (tolower(*pw) == tolower(*pt))) {
159 pw++;
160 pt++;
161 continue;
162 } else {
163 return 0;
164 }
165 }
166}
167
168void close_socket(int sock) {
169#ifdef __OS2__
170 soclose(sock);
171#elif defined(__NETWARE__)
172 shutdown(sock, 2);
173#elif defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
174 closesocket(sock);
175#else
176 close(sock);
177#endif
178}
179
180int tw_server_init(void) {
181 int i;
182#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__OS2__) && !defined(__NETWARE__) && !defined(__DOS__))
183 WSADATA wsa;
184#ifdef USE_WINSOCK1
185 WSAStartup(MAKEWORD(1, 1), &wsa);
186#else
187 WSAStartup(MAKEWORD(2, 0), &wsa);
188#endif
189#endif
190#ifdef __OS2__
191 sock_init();
192#endif
193 for(i = 0; config.ports[i] != -1; i++)
194 ;
195 sockcount = i;
196 for(i = 0; config.ports[i] != -1; i++) {
197 int yes = 1;
198 int no = 0;
199#ifdef NO_IPV6
200 int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
201#else
202 int sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
203#endif
204#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__)
205 if(sock == INVALID_SOCKET)
206#else
207 if(sock < 0)
208#endif
209 {
210 cm_log("Server", "Socket creation failure");
211 return 1;
212 }
213 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(yes)) < 0) {
214 close_socket(sock);
215 cm_log("Server", "setsockopt failure (reuseaddr)");
216 return 1;
217 }
218#if !defined(__PPU__) && !defined(__minix)
219 if(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(yes)) < 0) {
220 close_socket(sock);
221 cm_log("Server", "setsockopt failure (nodelay)");
222 return 1;
223 }
224#endif
225#ifndef NO_IPV6
226 if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&no, sizeof(no)) < 0) {
227 close_socket(sock);
228 cm_log("Server", "setsockopt failure (IPv6)");
229 return 1;
230 }
231#endif
232 memset(&addresses[i], 0, sizeof(addresses[i]));
233#ifdef NO_IPV6
234 addresses[i].sin_family = AF_INET;
235 addresses[i].sin_addr.s_addr = INADDR_ANY;
236 addresses[i].sin_port = htons(config.ports[i] & 0xffff);
237#else
238 addresses[i].sin6_family = AF_INET6;
239 addresses[i].sin6_addr = in6addr_any;
240 addresses[i].sin6_port = htons(config.ports[i] & 0xffff);
241#endif
242 if(bind(sock, (struct sockaddr*)&addresses[i], sizeof(addresses[i])) < 0) {
243 close_socket(sock);
244 cm_log("Server", "Bind failure");
245 return 1;
246 }
247 if(listen(sock, 128) < 0) {
248 close_socket(sock);
249 cm_log("Server", "Listen failure");
250 return 1;
251 }
252 sockets[i] = sock;
253 }
254 return 0;
255}
256
257size_t tw_read(SSL* ssl, int s, void* data, size_t len) {
258#ifndef NO_SSL
259 if(ssl == NULL) {
260 return recv(s, data, len, 0);
261 } else {
262 return SSL_read(ssl, data, len);
263 }
264#else
265 return recv(s, data, len, 0);
266#endif
267}
268
269size_t tw_write(SSL* ssl, int s, void* data, size_t len) {
270#ifndef NO_SSL
271 if(ssl == NULL) {
272 return send(s, data, len, 0);
273 } else {
274 return SSL_write(ssl, data, len);
275 }
276#else
277 return send(s, data, len, 0);
278#endif
279}
280
281#define ERROR_HTML \
282 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" \
283 "<html>\n" \
284 " <head>\n" \
285 " <title>%s</title>\n" \
286 " </head>\n" \
287 " <body>\n" \
288 " <h1>%s</h1>\n" \
289 " <hr>\n" \
290 " ", \
291 address, \
292 "\n" \
293 " </body>\n" \
294 "</html>\n"
295
296void _tw_process_page(SSL* ssl, int sock, const char* status, const char* type, FILE* f, const unsigned char* doc, size_t size, char** headers, time_t mtime, time_t cmtime) {
297 char construct[512];
298 size_t incr;
299 if(mtime != 0 && cmtime != 0 && mtime <= cmtime) {
300 status = "304 Not Modified";
301 type = NULL;
302 size = 0;
303 headers = NULL;
304 f = NULL;
305 doc = NULL;
306 }
307#if defined(_MSC_VER) || defined(__BORLANDC__)
308 sprintf(construct, "%lu", (unsigned long)size);
309#else
310 sprintf(construct, "%llu", (unsigned long long)size);
311#endif
312 tw_write(ssl, sock, "HTTP/1.1 ", 9);
313 tw_write(ssl, sock, (char*)status, strlen(status));
314 tw_write(ssl, sock, "\r\n", 2);
315 if(type != NULL) {
316 tw_write(ssl, sock, "Content-Type: ", 7 + 5 + 2);
317 tw_write(ssl, sock, (char*)type, strlen(type));
318 tw_write(ssl, sock, "\r\n", 2);
319 }
320 tw_write(ssl, sock, "Server: ", 6 + 2);
321 tw_write(ssl, sock, tw_server, strlen(tw_server));
322 tw_write(ssl, sock, "\r\n", 2);
323 if(size != 0) {
324 tw_write(ssl, sock, "Content-Length: ", 7 + 7 + 2);
325 tw_write(ssl, sock, construct, strlen(construct));
326 tw_write(ssl, sock, "\r\n", 2);
327 if(mtime != 0) {
328 struct tm* tm = gmtime(&mtime);
329 char date[513];
330 strftime(date, 512, "%a, %d %b %Y %H:%M:%S GMT", tm);
331 tw_write(ssl, sock, "Last-Modified: ", 5 + 8 + 2);
332 tw_write(ssl, sock, date, strlen(date));
333 tw_write(ssl, sock, "\r\n", 2);
334 }
335 }
336 if(headers != NULL) {
337 int i;
338 for(i = 0; headers[i] != NULL; i += 2) {
339 tw_write(ssl, sock, headers[i], strlen(headers[i]));
340 tw_write(ssl, sock, ": ", 2);
341 tw_write(ssl, sock, headers[i + 1], strlen(headers[i + 1]));
342 tw_write(ssl, sock, "\r\n", 2);
343 }
344 }
345 tw_write(ssl, sock, "\r\n", 2);
346 if(doc == NULL && f == NULL) return;
347 incr = 0;
348 while(1) {
349 if(f != NULL) {
350 char buffer[512];
351 int st;
352 fread(buffer, size < 512 ? size : 512, 1, f);
353 if((st = tw_write(ssl, sock, buffer, size < 512 ? size : 512)) <= 0) break;
354 } else {
355 if(tw_write(ssl, sock, (unsigned char*)doc + incr, size < 512 ? size : 512) <= 0) break;
356 }
357 incr += 512;
358 if(size <= 512) break;
359 size -= 512;
360 }
361}
362
363void tw_process_page(SSL* ssl, int sock, const char* status, const char* type, FILE* f, const unsigned char* doc, size_t size, time_t mtime, time_t cmtime) { _tw_process_page(ssl, sock, status, type, f, doc, size, NULL, mtime, cmtime); }
364
365const char* tw_http_status(int code) {
366 if(code == 200) {
367 return "200 OK";
368 } else if(code == 301) {
369 return "301 Moved Permanently";
370 } else if(code == 308) {
371 return "308 Permanent Redirect";
372 } else if(code == 400) {
373 return "400 Bad Request";
374 } else if(code == 401) {
375 return "401 Unauthorized";
376 } else if(code == 403) {
377 return "403 Forbidden";
378 } else if(code == 404) {
379 return "404 Not Found";
380 } else if(code == 500) {
381 return "500 Internal Server Error";
382 } else {
383 return "400 Bad Request";
384 }
385}
386
387char* tw_http_default_error(int code, char* name, int port, struct tw_config_entry* vhost) {
388 char address[1024];
389 char* st;
390 char* st2;
391 char* buffer;
392 char* str;
393 int i;
394
395 if((vhost->hideport == -1 ? config.root.hideport : vhost->hideport) == 1) {
396 sprintf(address, "<address>%s Server at %s</address>", tw_server, name, port);
397 } else {
398 sprintf(address, "<address>%s Server at %s Port %d</address>", tw_server, name, port);
399 }
400
401 st = cm_strdup(tw_http_status(code));
402 for(i = 0; st[i] != 0; i++) {
403 if(st[i] == ' ') {
404 st2 = cm_strdup(st + i + 1);
405 break;
406 }
407 }
408 buffer = malloc(4096);
409 str = cm_strcat3(ERROR_HTML);
410 sprintf(buffer, str, st, st2);
411 free(str);
412 free(st);
413 return buffer;
414}
415
416void tw_http_error(SSL* ssl, int sock, int error, char* name, int port, struct tw_config_entry* vhost) {
417 char* str = tw_http_default_error(error, name, port, vhost);
418 tw_process_page(ssl, sock, tw_http_status(error), "text/html", NULL, str, strlen(str), 0, 0);
419 free(str);
420}
421
422void addstring(char** str, const char* add, ...) {
423 int i;
424 char cbuf[2];
425 va_list va;
426 cbuf[1] = 0;
427 va_start(va, add);
428 for(i = 0; add[i] != 0; i++) {
429 cbuf[0] = add[i];
430 if(add[i] == '%') {
431 i++;
432 if(add[i] == 's') {
433 char* tmp = *str;
434 *str = cm_strcat(tmp, va_arg(va, const char*));
435 free(tmp);
436 } else if(add[i] == 'h') {
437 char* h = cm_html_escape(va_arg(va, const char*));
438 char* tmp = *str;
439 *str = cm_strcat(tmp, h);
440 free(tmp);
441 free(h);
442 } else if(add[i] == 'l') {
443 char* h = cm_url_escape(va_arg(va, const char*));
444 char* tmp = *str;
445 *str = cm_strcat(tmp, h);
446 free(tmp);
447 free(h);
448 } else if(add[i] == 'd') {
449 int n = va_arg(va, int);
450 char* h = malloc(512);
451 char* tmp = *str;
452 sprintf(h, "%d", n);
453 *str = cm_strcat(tmp, h);
454 free(tmp);
455 free(h);
456 } else if(add[i] == '%') {
457 char* tmp = *str;
458 *str = cm_strcat(tmp, "%");
459 free(tmp);
460 }
461 } else {
462 char* tmp = *str;
463 *str = cm_strcat(tmp, cbuf);
464 free(tmp);
465 }
466 }
467 va_end(va);
468}
469
470char* tw_get_mime(const char* ext, struct tw_config_entry* vhost_entry) {
471 char* mime = "application/octet-stream";
472 bool set = false;
473 int i;
474 if(ext == NULL) return mime;
475 for(i = 0; i < vhost_entry->mime_count; i++) {
476 if(strcmp(vhost_entry->mimes[i].ext, "all") == 0 || (ext != NULL && tw_wildcard_match(vhost_entry->mimes[i].ext, ext))) {
477 mime = vhost_entry->mimes[i].mime;
478 set = true;
479 }
480 }
481 if(!set) {
482 for(i = 0; i < config.root.mime_count; i++) {
483 if(strcmp(config.root.mimes[i].ext, "all") == 0 || (ext != NULL && tw_wildcard_match(config.root.mimes[i].ext, ext))) {
484 mime = config.root.mimes[i].mime;
485 }
486 }
487 }
488 return mime;
489}
490
491char* tw_get_icon(const char* mime, struct tw_config_entry* vhost_entry) {
492 char* icon = "";
493 bool set = false;
494 int i;
495 if(mime == NULL) return "";
496 for(i = 0; i < vhost_entry->icon_count; i++) {
497 if(strcmp(vhost_entry->icons[i].mime, "all") == 0 || (mime != NULL && tw_wildcard_match(vhost_entry->icons[i].mime, mime))) {
498 icon = vhost_entry->icons[i].icon;
499 set = true;
500 }
501 }
502 if(!set) {
503 for(i = 0; i < config.root.icon_count; i++) {
504 if(strcmp(config.root.icons[i].mime, "all") == 0 || (mime != NULL && tw_wildcard_match(config.root.icons[i].mime, mime))) {
505 icon = config.root.icons[i].icon;
506 }
507 }
508 }
509 return icon;
510}
511
512struct pass_entry {
513 int sock;
514 int port;
515 bool ssl;
516 SOCKADDR addr;
517};
518
519#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
520#define NO_RETURN_THREAD
521void tw_server_pass(void* ptr) {
522#elif defined(__amiga__)
523void* tw_server_pass(void* ptr) {
524#elif defined(__HAIKU__)
525int32_t tw_server_pass(void* ptr) {
526#elif defined(_PSP) || defined(__PPU__)
527int tw_server_pass(void* ptr) {
528#endif
529#if defined(__HAIKU__) || defined(__MINGW32__) || defined(_PSP) || defined(__PPU__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__amiga__)
530#define FREE_PTR
531 int sock = ((struct pass_entry*)ptr)->sock;
532 bool ssl = ((struct pass_entry*)ptr)->ssl;
533 int port = ((struct pass_entry*)ptr)->port;
534 SOCKADDR addr = ((struct pass_entry*)ptr)->addr;
535#else
536#define NO_RETURN_THREAD
537 void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) {
538#endif
539 SSL* s = NULL;
540#ifndef NO_SSL
541 SSL_CTX* ctx = NULL;
542 bool sslworks = false;
543 if(ssl) {
544 ctx = tw_create_ssl_ctx(port);
545 s = SSL_new(ctx);
546 SSL_set_fd(s, sock);
547 if(SSL_accept(s) <= 0) goto cleanup;
548 sslworks = true;
549 }
550#endif
551 char* name = config.hostname;
552 char address[513];
553 int ret;
554 struct tw_http_request req;
555 struct tw_http_response res;
556 struct tw_tool tools;
557 char* addrstr;
558#ifndef NO_GETNAMEINFO
559 struct sockaddr* sa = (struct sockaddr*)&addr;
560 getnameinfo(sa, sizeof(addr), address, 512, NULL, 0, NI_NUMERICHOST);
561#elif defined(__NETWARE__)
562 address[0] = 0;
563#else
564 addrstr = inet_ntoa(addr.sin_addr);
565 strcpy(address, addrstr);
566 address[strlen(addrstr)] = 0;
567#endif
568#ifdef FREE_PTR
569 free(ptr);
570#endif
571
572 res._processed = false;
573 tw_init_tools(&tools);
574 ret = tw_http_parse(s, sock, &req);
575 if(ret == 0) {
576 char date[513];
577 time_t t = time(NULL);
578 struct tm* tm = localtime(&t);
579 char* useragent = cm_strdup("");
580 int i;
581 char* tmp;
582 char* tmp2;
583 char* tmp3;
584 char* tmp4;
585 char* tmp5;
586 char* log;
587 char* vhost;
588 time_t cmtime;
589 bool rej;
590 char* host;
591 int port;
592 char* chrootpath;
593 struct tw_config_entry* vhost_entry;
594 strftime(date, 512, "%a, %d %b %Y %H:%M:%S %Z", tm);
595
596 for(i = 0; req.headers[i] != NULL; i += 2) {
597 if(cm_strcaseequ(req.headers[i], "User-Agent")) {
598 free(useragent);
599 useragent = cm_strdup(req.headers[i + 1]);
600 }
601 }
602
603 tmp = cm_strcat3(address, " - [", date);
604 tmp2 = cm_strcat3(tmp, "] \"", req.method);
605 tmp3 = cm_strcat3(tmp2, " ", req.path);
606 tmp4 = cm_strcat3(tmp3, " ", req.version);
607 tmp5 = cm_strcat3(tmp4, "\" \"", useragent);
608 log = cm_strcat(tmp5, "\"");
609 free(tmp);
610 free(tmp2);
611 free(tmp3);
612 free(tmp4);
613 free(tmp5);
614 free(useragent);
615 cm_force_log(log);
616 free(log);
617
618 vhost = cm_strdup(config.hostname);
619 cmtime = 0;
620 if(req.headers != NULL) {
621 for(i = 0; req.headers[i] != NULL; i += 2) {
622 if(cm_strcaseequ(req.headers[i], "Host")) {
623 free(vhost);
624 vhost = cm_strdup(req.headers[i + 1]);
625 } else if(cm_strcaseequ(req.headers[i], "If-Modified-Since")) {
626 struct tm tm;
627 time_t t;
628 struct tm* btm;
629 strptime(req.headers[i + 1], "%a, %d %b %Y %H:%M:%S GMT", &tm);
630#if defined(__MINGW32__) || defined(_PSP) || defined(__PPU__) || defined(__ps2sdk__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__USLC__) || defined(__NeXT__) || defined(__bsdi__) || defined(__amiga__)
631 t = 0;
632 btm = localtime(&t);
633 cmtime = mktime(&tm);
634 cmtime -= (btm->tm_hour * 60 + btm->tm_min) * 60;
635#else
636 cmtime = timegm(&tm);
637#endif
638 }
639 }
640 }
641 rej = false;
642 cm_log("Server", "Host is %s", vhost);
643 port = s == NULL ? 80 : 443;
644 host = cm_strdup(vhost);
645 for(i = 0; vhost[i] != 0; i++) {
646 if(vhost[i] == ':') {
647 host[i] = 0;
648 port = atoi(host + i + 1);
649 break;
650 }else if(vhost[i] == '['){
651 for(; vhost[i] != 0 && vhost[i] != ']'; i++);
652 }
653 }
654 name = host;
655 cm_log("Server", "Hostname is `%s', port is `%d'", host, port);
656 vhost_entry = tw_vhost_match(host, port);
657#ifdef HAS_CHROOT
658 chrootpath = vhost_entry->chroot_path != NULL ? vhost_entry->chroot_path : config.root.chroot_path;
659 if(chrootpath != NULL) {
660 if(chdir(chrootpath) == 0) {
661 if(chroot(".") == 0) {
662 cm_log("Server", "Chroot successful");
663 }
664 } else {
665 cm_log("Server", "chdir() failed, cannot chroot");
666 tw_http_error(s, sock, 500, name, port, vhost_entry);
667 rej = true;
668 }
669 }
670#endif
671 for(i = 0; i < config.module_count; i++) {
672#ifdef __OS2__
673 tw_mod_request_t mod_req = (tw_mod_request_t)tw_module_symbol(config.modules[i], "MOD_REQUEST");
674#else
675 tw_mod_request_t mod_req = (tw_mod_request_t)tw_module_symbol(config.modules[i], "mod_request");
676#endif
677 if(mod_req != NULL) {
678 int ret = mod_req(&tools, &req, &res);
679 int co = ret & 0xff;
680 if(co == _TW_MODULE_PASS) {
681 continue;
682 } else if(co == _TW_MODULE_STOP) {
683 /* Handle response here ... */
684 res._processed = true;
685 break;
686 } else if(co == _TW_MODULE_STOP2) {
687 res._processed = true;
688 break;
689 } else if(co == _TW_MODULE_ERROR) {
690 tw_http_error(s, sock, (ret & 0xffff00) >> 8, name, port, vhost_entry);
691 break;
692 }
693 }
694 }
695 if(!res._processed) {
696 char* path;
697 char* rpath;
698 struct stat st;
699 char* slash;
700 cm_log("Server", "Document root is %s", vhost_entry->root == NULL ? "not set" : vhost_entry->root);
701 path = cm_strcat(vhost_entry->root == NULL ? "" : vhost_entry->root, req.path);
702 cm_log("Server", "Filesystem path is %s", path);
703#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
704 for(i = strlen(path) - 1; i >= 0; i--) {
705 if(path[i] == '/') {
706 path[i] = 0;
707 } else {
708 break;
709 }
710 }
711#endif
712#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
713 rpath = cm_strdup(path);
714 for(i = strlen(rpath) - 1; i >= 0; i--) {
715 if(rpath[i] == '/') {
716 int j;
717 for(j = i + 1; rpath[j] != 0; j++) {
718 if(rpath[j] == ':' || rpath[j] == '.') {
719 rpath[j] = 0;
720 break;
721 }
722 }
723 break;
724 }
725 }
726 for(i = 0; i < sizeof(reserved_names) / sizeof(reserved_names[0]); i++) {
727 char* n = cm_strcat("/", reserved_names[i]);
728 if(cm_nocase_endswith(rpath, n)) {
729 tw_http_error(s, sock, 403, name, port, vhost_entry);
730 free(n);
731 rej = true;
732 cm_log("Server", "XP Patch ; rejecting access to device");
733 break;
734 }
735 free(n);
736 }
737 free(rpath);
738#endif
739 if(!rej && stat(path, &st) == 0) {
740 if(!tw_permission_allowed(path, addr, req, vhost_entry)) {
741 tw_http_error(s, sock, 403, name, port, vhost_entry);
742 } else if(S_ISDIR(st.st_mode)) {
743 if(req.path[strlen(req.path) - 1] != '/') {
744 char* headers[3] = {"Location", NULL, NULL};
745 headers[1] = cm_strcat(req.path, "/");
746 cm_log("Server", "Accessing directory without the slash at the end");
747 _tw_process_page(s, sock, tw_http_status(301), NULL, NULL, NULL, 0, headers, 0, 0);
748 free(headers[1]);
749 } else {
750 char** indexes = vhost_entry->index_count == 0 ? config.root.indexes : vhost_entry->indexes;
751 int index_count = vhost_entry->index_count == 0 ? config.root.index_count : vhost_entry->index_count;
752 bool found = false;
753 for(i = 0; i < index_count; i++) {
754 char* p = cm_strcat3(path, "/", indexes[i]);
755 FILE* f = fopen(p, "rb");
756 if(f != NULL) {
757 char* ext = NULL;
758 int j;
759 struct stat st;
760 char* mime;
761 for(j = strlen(p) - 1; j >= 0; j--) {
762 if(p[j] == '.') {
763 ext = cm_strdup(p + j);
764 break;
765 } else if(p[j] == '/') {
766 break;
767 }
768 }
769 stat(p, &st);
770 mime = tw_get_mime(ext, vhost_entry);
771 tw_process_page(s, sock, tw_http_status(200), mime, f, NULL, st.st_size, 0, 0);
772 fclose(f);
773 if(ext != NULL) free(ext);
774 free(p);
775 found = true;
776 break;
777 }
778 free(p);
779 }
780 if(!found) {
781 char* str = malloc(1);
782 char** items;
783 int readme;
784 char** readmes;
785 int readme_count;
786 int hp;
787 str[0] = 0;
788 items = cm_scandir(path);
789 addstring(&str, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
790 addstring(&str, "<html>\n");
791 addstring(&str, " <head>\n");
792 addstring(&str, " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
793 addstring(&str, " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
794 addstring(&str, " <title>Index of %h</title>\n", req.path);
795 addstring(&str, " </head>\n");
796 addstring(&str, " <body>\n");
797 addstring(&str, " <h1>Index of %h</h1>\n", req.path);
798 addstring(&str, " <hr>\n");
799 addstring(&str, " <table border=\"0\">\n");
800 addstring(&str, " <tr>\n");
801 addstring(&str, " <th></th>\n");
802 addstring(&str, " <th>Filename</th>\n");
803 addstring(&str, " <th>Last-modified</th>\n");
804 addstring(&str, " <th>MIME</th>\n");
805 addstring(&str, " <th>Size</th>\n");
806 addstring(&str, " </tr>\n");
807 readme = -1;
808 readmes = vhost_entry->readme_count == 0 ? config.root.readmes : vhost_entry->readmes;
809 readme_count = vhost_entry->readme_count == 0 ? config.root.readme_count : vhost_entry->readme_count;
810 if(items != NULL) {
811 int phase = 0;
812 doit:
813 for(i = 0; items[i] != NULL; i++) {
814 int j;
815 char* ext;
816 char* itm;
817 char* icon;
818 char* fpth = cm_strcat3(path, "/", items[i]);
819 struct stat s;
820 char size[512];
821 char date[512];
822 char* showmime;
823 char* mime;
824 struct tm* tm;
825 size[0] = 0;
826 stat(fpth, &s);
827 tm = localtime(&s.st_mtime);
828 strftime(date, 512, "%a, %d %b %Y %H:%M:%S %Z", tm);
829 if(phase == 0 && !S_ISDIR(s.st_mode)) {
830 free(fpth);
831 continue;
832 } else if(phase == 1 && S_ISDIR(s.st_mode)) {
833 free(fpth);
834 continue;
835 }
836 if(readme == -1) {
837 for(j = 0; j < readme_count; j++) {
838 if(strcmp(items[i], readmes[j]) == 0) {
839 readme = j;
840 break;
841 }
842 }
843 if(readme != -1) {
844 free(fpth);
845 continue;
846 }
847 }
848 if(s.st_size < NUM1024) {
849 sprintf(size, "%d", (int)s.st_size);
850 } else if(s.st_size < NUM1024 * 1024) {
851 sprintf(size, "%.1fK", (double)s.st_size / 1024);
852 } else if(s.st_size < NUM1024 * 1024 * 1024) {
853 sprintf(size, "%.1fM", (double)s.st_size / 1024 / 1024);
854 } else if(s.st_size < NUM1024 * 1024 * 1024 * 1024) {
855 sprintf(size, "%.1fG", (double)s.st_size / 1024 / 1024 / 1024);
856 } else if(s.st_size < NUM1024 * 1024 * 1024 * 1024 * 1024) {
857 sprintf(size, "%.1fT", (double)s.st_size / 1024 / 1024 / 1024 / 1024);
858 }
859
860 free(fpth);
861
862 ext = NULL;
863 for(j = strlen(items[i]) - 1; j >= 0; j--) {
864 if(items[i][j] == '.') {
865 ext = cm_strdup(items[i] + j);
866 break;
867 } else if(items[i][j] == '/') {
868 break;
869 }
870 }
871 showmime = "";
872 mime = tw_get_mime(ext, vhost_entry);
873 if(strcmp(items[i], "../") == 0) {
874 mime = "misc/parent";
875 size[0] = 0;
876 } else if(items[i][strlen(items[i]) - 1] == '/') {
877 mime = "misc/dir";
878 size[0] = 0;
879 } else {
880 showmime = mime;
881 }
882 icon = tw_get_icon(mime, vhost_entry);
883 if(ext != NULL) free(ext);
884 itm = cm_strdup(items[i]);
885 if(strlen(itm) >= 32) {
886 if(itm[strlen(itm) - 1] == '/') {
887 itm[31] = 0;
888 itm[30] = '/';
889 itm[29] = '.';
890 itm[28] = '.';
891 itm[27] = '.';
892 } else {
893 itm[31] = 0;
894 itm[30] = '.';
895 itm[29] = '.';
896 itm[28] = '.';
897 }
898 }
899 addstring(&str, "<tr>\n");
900 addstring(&str, " <td><img src=\"%s\" alt=\"icon\"></td>\n", icon);
901 addstring(&str, " <td><a href=\"%l\"><code>%h</code></a></td>\n", items[i], itm);
902 addstring(&str, " <td><code> %h </code></td>\n", date);
903 addstring(&str, " <td><code> %h </code></td>\n", showmime);
904 addstring(&str, " <td><code> %s </code></td>\n", size);
905 addstring(&str, "</tr>\n");
906 free(itm);
907 }
908 phase++;
909 if(phase != 2) goto doit;
910 for(i = 0; items[i] != NULL; i++) free(items[i]);
911 free(items);
912 }
913 addstring(&str, " </table>\n");
914 if(readme != -1) {
915 struct stat s;
916 FILE* fr;
917 char* fpth;
918 addstring(&str, "<hr>\n");
919 fpth = cm_strcat3(path, "/", readmes[readme]);
920 stat(fpth, &s);
921 fr = fopen(fpth, "r");
922 if(fr != NULL) {
923 char* rmbuf = malloc(s.st_size + 1);
924 rmbuf[s.st_size] = 0;
925 fread(rmbuf, s.st_size, 1, fr);
926 addstring(&str, "<pre><code>%h</code></pre>\n", rmbuf);
927 fclose(fr);
928 free(rmbuf);
929 }
930 free(fpth);
931 }
932 addstring(&str, " <hr>\n");
933 hp = vhost_entry->hideport == -1 ? config.root.hideport : vhost_entry->hideport;
934 if(hp == 0) {
935 addstring(&str, " <address>%s Server at %s Port %d</address>\n", tw_server, name, port);
936 } else {
937 addstring(&str, " <address>%s Server at %s</address>\n", tw_server, name, port);
938 }
939 addstring(&str, " </body>\n");
940 addstring(&str, "</html>\n");
941 tw_process_page(s, sock, tw_http_status(200), "text/html", NULL, str, strlen(str), 0, 0);
942 free(str);
943 }
944 }
945 } else {
946 char* ext = NULL;
947 char* mime;
948 FILE* f;
949 for(i = strlen(req.path) - 1; i >= 0; i--) {
950 if(req.path[i] == '.') {
951 ext = cm_strdup(req.path + i);
952 break;
953 } else if(req.path[i] == '/') {
954 break;
955 }
956 }
957 mime = tw_get_mime(ext, vhost_entry);
958 if(ext != NULL) free(ext);
959 f = fopen(path, "rb");
960 if(f == NULL) {
961 tw_http_error(s, sock, 403, name, port, vhost_entry);
962 } else {
963 tw_process_page(s, sock, tw_http_status(200), mime, f, NULL, st.st_size, st.st_mtime, cmtime);
964 fclose(f);
965 }
966 }
967 } else {
968 if(!rej) {
969 tw_http_error(s, sock, 404, name, port, vhost_entry);
970 }
971 }
972 free(path);
973 }
974 free(vhost);
975 free(host);
976 } else if(ret == -1) {
977 } else {
978 tw_http_error(s, sock, 400, name, port, &config.root);
979 }
980 tw_free_request(&req);
981cleanup:
982#ifndef NO_SSL
983 if(sslworks) {
984 SSL_shutdown(s);
985 }
986 SSL_free(s);
987#endif
988 close_socket(sock);
989#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
990#ifdef __NETWARE__
991 ExitThread(EXIT_THREAD, 0);
992#elif defined(__DOS__)
993#else
994 _endthread();
995#endif
996#elif defined(__HAIKU__)
997 exit_thread(0);
998#endif
999#ifndef NO_RETURN_THREAD
1000 return 0;
1001#endif
1002}
1003
1004#ifdef SERVICE
1005extern SERVICE_STATUS status;
1006extern SERVICE_STATUS_HANDLE status_handle;
1007#endif
1008
1009#if defined(__MINGW32__) || defined(__HAIKU__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
1010struct thread_entry {
1011#ifdef __HAIKU__
1012 thread_id thread;
1013#elif defined(__NETWARE__)
1014 int thread;
1015#elif defined(__DOS__)
1016#else
1017 HANDLE handle;
1018#endif
1019 bool used;
1020};
1021#endif
1022
1023extern int running;
1024
1025void tw_server_loop(void) {
1026 int i;
1027#ifndef USE_POLL
1028 fd_set fdset;
1029 struct timeval tv;
1030#endif
1031#if defined(__MINGW32__) || defined(__HAIKU__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__NETWARE__) && !defined(__DOS__))
1032 struct thread_entry threads[128];
1033 for(i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) {
1034 threads[i].used = false;
1035 }
1036#endif
1037#ifdef USE_POLL
1038 struct pollfd* pollfds = malloc(sizeof(*pollfds) * sockcount);
1039 for(i = 0; i < sockcount; i++) {
1040 pollfds[i].fd = sockets[i];
1041 pollfds[i].events = POLLIN | POLLPRI;
1042 }
1043#endif
1044 while(running) {
1045 int ret;
1046#ifdef USE_POLL
1047 ret = poll(pollfds, sockcount, 1000);
1048#else
1049 FD_ZERO(&fdset);
1050 for(i = 0; i < sockcount; i++) {
1051 FD_SET(sockets[i], &fdset);
1052 }
1053 tv.tv_sec = 1;
1054 tv.tv_usec = 0;
1055#ifdef __HAIKU__
1056 ret = select(32, &fdset, NULL, NULL, &tv);
1057#else
1058 ret = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
1059#endif
1060#endif
1061 if(ret == -1) {
1062#if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
1063 if(errno == EINTR) continue;
1064 cm_log("Server", "Select/poll failure: %s", strerror(errno));
1065#endif
1066 break;
1067 } else if(ret == 0) {
1068#ifdef SERVICE
1069 if(status.dwCurrentState == SERVICE_STOP_PENDING) {
1070 break;
1071 }
1072#endif
1073 } else if(ret > 0) {
1074 /* connection */
1075 int i;
1076 for(i = 0; i < sockcount; i++) {
1077 bool cond;
1078#ifdef USE_POLL
1079 cond = pollfds[i].revents & POLLIN;
1080#else
1081 cond = FD_ISSET(sockets[i], &fdset);
1082#endif
1083 if(cond) {
1084 SOCKADDR claddr;
1085 socklen_t clen = sizeof(claddr);
1086 int sock = accept(sockets[i], (struct sockaddr*)&claddr, &clen);
1087#if defined(__MINGW32__) || defined(__HAIKU__) || defined(_PSP) || defined(__PPU__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__amiga__)
1088#ifdef __amiga__
1089 pthread_t thrt;
1090#endif
1091 int j;
1092 struct pass_entry* e = malloc(sizeof(*e));
1093 cm_log("Server", "New connection accepted");
1094 e->sock = sock;
1095#if defined(_MSC_VER) || defined(__BORLANDC__)
1096 e->ssl = config.ports[i] & (1UL << 31);
1097#else
1098 e->ssl = config.ports[i] & (1ULL << 31);
1099#endif
1100 e->port = config.ports[i];
1101 e->addr = claddr;
1102#endif
1103#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
1104#ifdef __OS2__
1105 _beginthread(tw_server_pass, 0, 0, e);
1106#elif defined(__NETWARE__)
1107 BeginThread(tw_server_pass, NULL, 0, e);
1108#elif defined(__DOS__)
1109 tw_server_pass(e);
1110#else
1111 _beginthread(tw_server_pass, 0, e);
1112#endif
1113#elif defined(_PSP) || defined(__PPU__)
1114 tw_server_pass(e);
1115#elif defined(__amiga__)
1116 pthread_create(&thrt, NULL, tw_server_pass, e);
1117#elif defined(__HAIKU__)
1118 for(j = 0; j < sizeof(threads) / sizeof(threads[0]); j++) {
1119 if(threads[j].used) {
1120 thread_info info;
1121 bool kill = false;
1122 if(get_thread_info(threads[j].thread, &info) == B_OK) {
1123 } else {
1124 kill = true;
1125 }
1126 if(kill) {
1127 threads[j].used = false;
1128 }
1129 }
1130 }
1131 for(j = 0; j < sizeof(threads) / sizeof(threads[0]); j++) {
1132 if(!threads[j].used) {
1133 threads[j].thread = spawn_thread(tw_server_pass, "Tewi HTTPd", 60, e);
1134 threads[j].used = true;
1135 resume_thread(threads[j].thread);
1136 break;
1137 }
1138 }
1139#else
1140 pid_t pid = fork();
1141 if(pid == 0) {
1142 int j;
1143 for(j = 0; j < sockcount; j++) close_socket(sockets[j]);
1144 tw_server_pass(sock, config.ports[i] & (1ULL << 31), config.ports[i], claddr);
1145 _exit(0);
1146 } else {
1147 close_socket(sock);
1148 }
1149#endif
1150 }
1151 }
1152 }
1153 }
1154 for(i = 0; i < sockcount; i++) {
1155 close_socket(sockets[i]);
1156 }
1157 cm_force_log("Server is down");
1158}
Note: See TracBrowser for help on using the repository browser.