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

Last change on this file since 402 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
RevLine 
[8]1/* $Id: server.c 402 2024-11-03 10:39:59Z nishi $ */
2
[16]3#define SOURCE
4
[43]5#include "../config.h"
6
[8]7#include "tw_server.h"
8
[43]9#ifndef NO_SSL
[12]10#include "tw_ssl.h"
[43]11#endif
12
[8]13#include "tw_config.h"
[16]14#include "tw_http.h"
[18]15#include "tw_module.h"
16#include "tw_version.h"
[8]17
[402]18#ifdef __amiga__
19#include <pthread.h>
20#endif
21
[215]22#if !defined(_MSC_VER) && !defined(__BORLANDC__)
[8]23#include <unistd.h>
[212]24#endif
[312]25#include <ctype.h>
[8]26#include <string.h>
[11]27#include <stdbool.h>
[20]28#include <stdarg.h>
[43]29#include <stdio.h>
30#include <stdlib.h>
[84]31#include <errno.h>
[212]32#include <sys/types.h>
[21]33#include <sys/stat.h>
[32]34#include <time.h>
[8]35
[18]36#include <cm_string.h>
[8]37#include <cm_log.h>
[21]38#include <cm_dir.h>
[8]39
[312]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
[359]54#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__OS2__) && !defined(__NETWARE__) && !defined(__DOS__))
[255]55#ifndef NO_GETNAMEINFO
[116]56#include <ws2tcpip.h>
57#include <wspiapi.h>
[163]58#endif
[240]59#ifdef USE_WINSOCK1
60#include <winsock.h>
61#else
[8]62#include <winsock2.h>
[240]63#endif
[11]64#include <process.h>
[62]65#include <windows.h>
[32]66
67#include "strptime.h"
[216]68typedef int socklen_t;
[315]69#elif defined(__NETWARE__)
[361]70#include <sys/bsdskt.h>
[315]71#include <sys/socket.h>
[349]72
73#define IPPROTO_TCP 0
74#define INADDR_ANY 0
[315]75#include "strptime.h"
[349]76typedef int socklen_t;
[361]77
78uint16_t htons(uint16_t n) { return ((n >> 8) & 0xff) | ((n << 8) & 0xff00); }
[359]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"
[8]86#else
[118]87#ifdef USE_POLL
[187]88#ifdef __PPU__
89#include <net/poll.h>
90#else
[118]91#include <poll.h>
[187]92#endif
[118]93#else
[328]94#ifndef __NeXT__
[8]95#include <sys/select.h>
[118]96#endif
[348]97#ifdef __OS2__
98#include <netinet/in.h>
[328]99#endif
[348]100#endif
[8]101#include <sys/socket.h>
102#include <arpa/inet.h>
[331]103#if !defined(__PPU__)
[332]104#ifdef __NeXT__
105#include <netinet/in_systm.h>
106#endif
[8]107#include <netinet/tcp.h>
[187]108#endif
[255]109#ifndef NO_GETNAMEINFO
[116]110#include <netdb.h>
[8]111#endif
[163]112#endif
[8]113
[402]114#if defined(_PSP) || defined(__ps2sdk__) || defined(__bsdi__) || defined(__amiga__)
[182]115#include "strptime.h"
116#endif
117
[97]118#ifdef __HAIKU__
119#include <OS.h>
120#endif
121
[334]122#ifdef __NeXT__
123#include <sys/time.h>
124#endif
125
[347]126#if defined(__USLC__) || defined(__NeXT__)
[303]127typedef int socklen_t;
128#endif
129
[212]130#ifndef S_ISDIR
[272]131#define S_ISDIR(x) ((x) & _S_IFDIR)
[212]132#endif
133
[8]134extern struct tw_config config;
[18]135extern char tw_server[];
[8]136
137int sockcount = 0;
138
[9]139SOCKADDR addresses[MAX_PORTS];
140int sockets[MAX_PORTS];
[8]141
[219]142#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[70]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
[23]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);
[312]158 } else if(*pw == '?' || (tolower(*pw) == tolower(*pt))) {
[23]159 pw++;
160 pt++;
161 continue;
162 } else {
163 return 0;
164 }
165 }
166}
167
[8]168void close_socket(int sock) {
[312]169#ifdef __OS2__
170 soclose(sock);
[315]171#elif defined(__NETWARE__)
172 shutdown(sock, 2);
[312]173#elif defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[8]174 closesocket(sock);
175#else
176 close(sock);
177#endif
178}
179
180int tw_server_init(void) {
181 int i;
[359]182#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__OS2__) && !defined(__NETWARE__) && !defined(__DOS__))
[8]183 WSADATA wsa;
[240]184#ifdef USE_WINSOCK1
185 WSAStartup(MAKEWORD(1, 1), &wsa);
186#else
[8]187 WSAStartup(MAKEWORD(2, 0), &wsa);
188#endif
[240]189#endif
[312]190#ifdef __OS2__
191 sock_init();
192#endif
[8]193 for(i = 0; config.ports[i] != -1; i++)
194 ;
195 sockcount = i;
196 for(i = 0; config.ports[i] != -1; i++) {
[212]197 int yes = 1;
198 int no = 0;
[8]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
[215]204#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__)
[8]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 }
[275]218#if !defined(__PPU__) && !defined(__minix)
[8]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 }
[187]224#endif
[8]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;
[214]236 addresses[i].sin_port = htons(config.ports[i] & 0xffff);
[8]237#else
238 addresses[i].sin6_family = AF_INET6;
239 addresses[i].sin6_addr = in6addr_any;
[214]240 addresses[i].sin6_port = htons(config.ports[i] & 0xffff);
[8]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}
[9]256
[16]257size_t tw_read(SSL* ssl, int s, void* data, size_t len) {
[43]258#ifndef NO_SSL
[16]259 if(ssl == NULL) {
260 return recv(s, data, len, 0);
261 } else {
262 return SSL_read(ssl, data, len);
263 }
[43]264#else
265 return recv(s, data, len, 0);
266#endif
[16]267}
268
269size_t tw_write(SSL* ssl, int s, void* data, size_t len) {
[43]270#ifndef NO_SSL
[16]271 if(ssl == NULL) {
272 return send(s, data, len, 0);
273 } else {
274 return SSL_write(ssl, data, len);
275 }
[43]276#else
277 return send(s, data, len, 0);
278#endif
[16]279}
280
[20]281#define ERROR_HTML \
[18]282 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" \
283 "<html>\n" \
284 " <head>\n" \
[20]285 " <title>%s</title>\n" \
[18]286 " </head>\n" \
287 " <body>\n" \
[20]288 " <h1>%s</h1>\n" \
[18]289 " <hr>\n" \
290 " ", \
291 address, \
292 "\n" \
293 " </body>\n" \
294 "</html>\n"
295
[32]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) {
[18]297 char construct[512];
[212]298 size_t incr;
[32]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 }
[215]307#if defined(_MSC_VER) || defined(__BORLANDC__)
[212]308 sprintf(construct, "%lu", (unsigned long)size);
309#else
[18]310 sprintf(construct, "%llu", (unsigned long long)size);
[212]311#endif
[18]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);
[24]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 }
[18]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);
[24]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);
[32]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 }
[24]335 }
336 if(headers != NULL) {
[212]337 int i;
[24]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 }
[18]345 tw_write(ssl, sock, "\r\n", 2);
[24]346 if(doc == NULL && f == NULL) return;
[212]347 incr = 0;
[18]348 while(1) {
[22]349 if(f != NULL) {
[393]350 char buffer[512];
[398]351 int st;
[393]352 fread(buffer, size < 512 ? size : 512, 1, f);
[398]353 if((st = tw_write(ssl, sock, buffer, size < 512 ? size : 512)) <= 0) break;
[22]354 } else {
[398]355 if(tw_write(ssl, sock, (unsigned char*)doc + incr, size < 512 ? size : 512) <= 0) break;
[21]356 }
[393]357 incr += 512;
358 if(size <= 512) break;
359 size -= 512;
[18]360 }
361}
362
[32]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); }
[24]364
[18]365const char* tw_http_status(int code) {
[20]366 if(code == 200) {
367 return "200 OK";
[166]368 } else if(code == 301) {
[167]369 return "301 Moved Permanently";
[24]370 } else if(code == 308) {
371 return "308 Permanent Redirect";
[20]372 } else if(code == 400) {
[18]373 return "400 Bad Request";
[20]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";
[161]380 } else if(code == 500) {
381 return "500 Internal Server Error";
[18]382 } else {
383 return "400 Bad Request";
384 }
385}
386
[123]387char* tw_http_default_error(int code, char* name, int port, struct tw_config_entry* vhost) {
[18]388 char address[1024];
[212]389 char* st;
390 char* st2;
391 char* buffer;
392 char* str;
393 int i;
[20]394
[123]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
[212]401 st = cm_strdup(tw_http_status(code));
[20]402 for(i = 0; st[i] != 0; i++) {
403 if(st[i] == ' ') {
404 st2 = cm_strdup(st + i + 1);
405 break;
406 }
[18]407 }
[212]408 buffer = malloc(4096);
409 str = cm_strcat3(ERROR_HTML);
[20]410 sprintf(buffer, str, st, st2);
411 free(str);
412 free(st);
413 return buffer;
[18]414}
415
[123]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);
[32]418 tw_process_page(ssl, sock, tw_http_status(error), "text/html", NULL, str, strlen(str), 0, 0);
[18]419 free(str);
420}
421
[20]422void addstring(char** str, const char* add, ...) {
423 int i;
424 char cbuf[2];
[212]425 va_list va;
[20]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);
[21]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);
[20]448 } else if(add[i] == 'd') {
449 int n = va_arg(va, int);
450 char* h = malloc(512);
[212]451 char* tmp = *str;
[20]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 }
[74]467 va_end(va);
[20]468}
469
[22]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;
[212]474 if(ext == NULL) return mime;
[22]475 for(i = 0; i < vhost_entry->mime_count; i++) {
[23]476 if(strcmp(vhost_entry->mimes[i].ext, "all") == 0 || (ext != NULL && tw_wildcard_match(vhost_entry->mimes[i].ext, ext))) {
[22]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++) {
[23]483 if(strcmp(config.root.mimes[i].ext, "all") == 0 || (ext != NULL && tw_wildcard_match(config.root.mimes[i].ext, ext))) {
[22]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;
[212]495 if(mime == NULL) return "";
[22]496 for(i = 0; i < vhost_entry->icon_count; i++) {
[23]497 if(strcmp(vhost_entry->icons[i].mime, "all") == 0 || (mime != NULL && tw_wildcard_match(vhost_entry->icons[i].mime, mime))) {
[22]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++) {
[23]504 if(strcmp(config.root.icons[i].mime, "all") == 0 || (mime != NULL && tw_wildcard_match(config.root.icons[i].mime, mime))) {
[22]505 icon = config.root.icons[i].icon;
506 }
507 }
508 }
509 return icon;
510}
511
[11]512struct pass_entry {
513 int sock;
[12]514 int port;
[11]515 bool ssl;
[21]516 SOCKADDR addr;
[11]517};
518
[219]519#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[216]520#define NO_RETURN_THREAD
[215]521void tw_server_pass(void* ptr) {
[402]522#elif defined(__amiga__)
523void* tw_server_pass(void* ptr) {
[97]524#elif defined(__HAIKU__)
525int32_t tw_server_pass(void* ptr) {
[187]526#elif defined(_PSP) || defined(__PPU__)
[183]527int tw_server_pass(void* ptr) {
[105]528#endif
[402]529#if defined(__HAIKU__) || defined(__MINGW32__) || defined(_PSP) || defined(__PPU__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__amiga__)
[212]530#define FREE_PTR
[11]531 int sock = ((struct pass_entry*)ptr)->sock;
532 bool ssl = ((struct pass_entry*)ptr)->ssl;
[14]533 int port = ((struct pass_entry*)ptr)->port;
[21]534 SOCKADDR addr = ((struct pass_entry*)ptr)->addr;
[11]535#else
[216]536#define NO_RETURN_THREAD
[105]537 void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) {
[11]538#endif
[212]539 SSL* s = NULL;
[43]540#ifndef NO_SSL
[12]541 SSL_CTX* ctx = NULL;
[15]542 bool sslworks = false;
[12]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;
[15]548 sslworks = true;
[12]549 }
[43]550#endif
[212]551 char* name = config.hostname;
[116]552 char address[513];
[212]553 int ret;
554 struct tw_http_request req;
555 struct tw_http_response res;
556 struct tw_tool tools;
[255]557 char* addrstr;
558#ifndef NO_GETNAMEINFO
[116]559 struct sockaddr* sa = (struct sockaddr*)&addr;
560 getnameinfo(sa, sizeof(addr), address, 512, NULL, 0, NI_NUMERICHOST);
[315]561#elif defined(__NETWARE__)
562 address[0] = 0;
[257]563#else
[315]564 addrstr = inet_ntoa(addr.sin_addr);
565 strcpy(address, addrstr);
566 address[strlen(addrstr)] = 0;
[163]567#endif
[212]568#ifdef FREE_PTR
569 free(ptr);
570#endif
[116]571
[20]572 res._processed = false;
573 tw_init_tools(&tools);
[212]574 ret = tw_http_parse(s, sock, &req);
[17]575 if(ret == 0) {
[116]576 char date[513];
577 time_t t = time(NULL);
578 struct tm* tm = localtime(&t);
[212]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;
[293]592 char* chrootpath;
[212]593 struct tw_config_entry* vhost_entry;
[116]594 strftime(date, 512, "%a, %d %b %Y %H:%M:%S %Z", tm);
595
[117]596 for(i = 0; req.headers[i] != NULL; i += 2) {
597 if(cm_strcaseequ(req.headers[i], "User-Agent")) {
[116]598 free(useragent);
599 useragent = cm_strdup(req.headers[i + 1]);
600 }
601 }
602
[212]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, "\"");
[116]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
[212]618 vhost = cm_strdup(config.hostname);
619 cmtime = 0;
[70]620 if(req.headers != NULL) {
[64]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;
[212]627 time_t t;
628 struct tm* btm;
[64]629 strptime(req.headers[i + 1], "%a, %d %b %Y %H:%M:%S GMT", &tm);
[402]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__)
[212]631 t = 0;
632 btm = localtime(&t);
[64]633 cmtime = mktime(&tm);
634 cmtime -= (btm->tm_hour * 60 + btm->tm_min) * 60;
[32]635#else
[140]636 cmtime = timegm(&tm);
[32]637#endif
[64]638 }
[21]639 }
640 }
[212]641 rej = false;
[21]642 cm_log("Server", "Host is %s", vhost);
[212]643 port = s == NULL ? 80 : 443;
644 host = cm_strdup(vhost);
[22]645 for(i = 0; vhost[i] != 0; i++) {
646 if(vhost[i] == ':') {
[21]647 host[i] = 0;
648 port = atoi(host + i + 1);
649 break;
[392]650 }else if(vhost[i] == '['){
651 for(; vhost[i] != 0 && vhost[i] != ']'; i++);
[21]652 }
653 }
[136]654 name = host;
[21]655 cm_log("Server", "Hostname is `%s', port is `%d'", host, port);
[212]656 vhost_entry = tw_vhost_match(host, port);
[161]657#ifdef HAS_CHROOT
[293]658 chrootpath = vhost_entry->chroot_path != NULL ? vhost_entry->chroot_path : config.root.chroot_path;
[161]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
[20]671 for(i = 0; i < config.module_count; i++) {
[314]672#ifdef __OS2__
673 tw_mod_request_t mod_req = (tw_mod_request_t)tw_module_symbol(config.modules[i], "MOD_REQUEST");
674#else
[315]675 tw_mod_request_t mod_req = (tw_mod_request_t)tw_module_symbol(config.modules[i], "mod_request");
[314]676#endif
[20]677 if(mod_req != NULL) {
678 int ret = mod_req(&tools, &req, &res);
679 int co = ret & 0xff;
[141]680 if(co == _TW_MODULE_PASS) {
681 continue;
682 } else if(co == _TW_MODULE_STOP) {
683 /* Handle response here ... */
[20]684 res._processed = true;
685 break;
[141]686 } else if(co == _TW_MODULE_STOP2) {
687 res._processed = true;
688 break;
689 } else if(co == _TW_MODULE_ERROR) {
[123]690 tw_http_error(s, sock, (ret & 0xffff00) >> 8, name, port, vhost_entry);
[20]691 break;
692 }
693 }
694 }
695 if(!res._processed) {
[212]696 char* path;
697 char* rpath;
698 struct stat st;
[215]699 char* slash;
[21]700 cm_log("Server", "Document root is %s", vhost_entry->root == NULL ? "not set" : vhost_entry->root);
[212]701 path = cm_strcat(vhost_entry->root == NULL ? "" : vhost_entry->root, req.path);
[21]702 cm_log("Server", "Filesystem path is %s", path);
[219]703#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[216]704 for(i = strlen(path) - 1; i >= 0; i--) {
705 if(path[i] == '/') {
[215]706 path[i] = 0;
[216]707 } else {
[215]708 break;
709 }
710 }
711#endif
[219]712#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[212]713 rpath = cm_strdup(path);
[72]714 for(i = strlen(rpath) - 1; i >= 0; i--) {
[73]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 }
[71]723 break;
724 }
725 }
[70]726 for(i = 0; i < sizeof(reserved_names) / sizeof(reserved_names[0]); i++) {
727 char* n = cm_strcat("/", reserved_names[i]);
[71]728 if(cm_nocase_endswith(rpath, n)) {
[124]729 tw_http_error(s, sock, 403, name, port, vhost_entry);
[70]730 free(n);
731 rej = true;
732 cm_log("Server", "XP Patch ; rejecting access to device");
733 break;
734 }
735 free(n);
736 }
[71]737 free(rpath);
[70]738#endif
739 if(!rej && stat(path, &st) == 0) {
[22]740 if(!tw_permission_allowed(path, addr, req, vhost_entry)) {
[123]741 tw_http_error(s, sock, 403, name, port, vhost_entry);
[22]742 } else if(S_ISDIR(st.st_mode)) {
[24]743 if(req.path[strlen(req.path) - 1] != '/') {
[215]744 char* headers[3] = {"Location", NULL, NULL};
745 headers[1] = cm_strcat(req.path, "/");
[61]746 cm_log("Server", "Accessing directory without the slash at the end");
[166]747 _tw_process_page(s, sock, tw_http_status(301), NULL, NULL, NULL, 0, headers, 0, 0);
[24]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;
[212]759 struct stat st;
760 char* mime;
[24]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 }
[22]768 }
[24]769 stat(p, &st);
[212]770 mime = tw_get_mime(ext, vhost_entry);
[32]771 tw_process_page(s, sock, tw_http_status(200), mime, f, NULL, st.st_size, 0, 0);
[24]772 fclose(f);
[74]773 if(ext != NULL) free(ext);
[24]774 free(p);
775 found = true;
776 break;
[22]777 }
[24]778 free(p);
779 }
780 if(!found) {
781 char* str = malloc(1);
[212]782 char** items;
783 int readme;
784 char** readmes;
785 int readme_count;
786 int hp;
[24]787 str[0] = 0;
[212]788 items = cm_scandir(path);
[122]789 addstring(&str, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
[24]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");
[122]793 addstring(&str, " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
[24]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");
[389]803 addstring(&str, " <th>Last-modified</th>\n");
[28]804 addstring(&str, " <th>MIME</th>\n");
805 addstring(&str, " <th>Size</th>\n");
[24]806 addstring(&str, " </tr>\n");
[212]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;
[24]810 if(items != NULL) {
[29]811 int phase = 0;
812 doit:
[24]813 for(i = 0; items[i] != NULL; i++) {
[33]814 int j;
[212]815 char* ext;
816 char* itm;
817 char* icon;
[28]818 char* fpth = cm_strcat3(path, "/", items[i]);
819 struct stat s;
820 char size[512];
[389]821 char date[512];
[212]822 char* showmime;
823 char* mime;
[389]824 struct tm* tm;
[28]825 size[0] = 0;
826 stat(fpth, &s);
[389]827 tm = localtime(&s.st_mtime);
828 strftime(date, 512, "%a, %d %b %Y %H:%M:%S %Z", tm);
[29]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 }
[33]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 }
[212]848 if(s.st_size < NUM1024) {
[31]849 sprintf(size, "%d", (int)s.st_size);
[212]850 } else if(s.st_size < NUM1024 * 1024) {
[29]851 sprintf(size, "%.1fK", (double)s.st_size / 1024);
[212]852 } else if(s.st_size < NUM1024 * 1024 * 1024) {
[29]853 sprintf(size, "%.1fM", (double)s.st_size / 1024 / 1024);
[212]854 } else if(s.st_size < NUM1024 * 1024 * 1024 * 1024) {
[29]855 sprintf(size, "%.1fG", (double)s.st_size / 1024 / 1024 / 1024);
[212]856 } else if(s.st_size < NUM1024 * 1024 * 1024 * 1024 * 1024) {
[29]857 sprintf(size, "%.1fT", (double)s.st_size / 1024 / 1024 / 1024 / 1024);
[28]858 }
859
860 free(fpth);
861
[212]862 ext = NULL;
[24]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 }
[212]871 showmime = "";
872 mime = tw_get_mime(ext, vhost_entry);
[24]873 if(strcmp(items[i], "../") == 0) {
874 mime = "misc/parent";
[29]875 size[0] = 0;
[24]876 } else if(items[i][strlen(items[i]) - 1] == '/') {
877 mime = "misc/dir";
[29]878 size[0] = 0;
879 } else {
[28]880 showmime = mime;
[24]881 }
[212]882 icon = tw_get_icon(mime, vhost_entry);
[24]883 if(ext != NULL) free(ext);
[212]884 itm = cm_strdup(items[i]);
[24]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);
[389]902 addstring(&str, " <td><code> %h </code></td>\n", date);
[60]903 addstring(&str, " <td><code> %h </code></td>\n", showmime);
904 addstring(&str, " <td><code> %s </code></td>\n", size);
[24]905 addstring(&str, "</tr>\n");
906 free(itm);
[22]907 }
[29]908 phase++;
909 if(phase != 2) goto doit;
910 for(i = 0; items[i] != NULL; i++) free(items[i]);
911 free(items);
[22]912 }
[24]913 addstring(&str, " </table>\n");
[33]914 if(readme != -1) {
[212]915 struct stat s;
916 FILE* fr;
917 char* fpth;
[33]918 addstring(&str, "<hr>\n");
[212]919 fpth = cm_strcat3(path, "/", readmes[readme]);
[33]920 stat(fpth, &s);
[212]921 fr = fopen(fpth, "r");
[33]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);
[70]928 free(rmbuf);
[33]929 }
[66]930 free(fpth);
[33]931 }
[24]932 addstring(&str, " <hr>\n");
[212]933 hp = vhost_entry->hideport == -1 ? config.root.hideport : vhost_entry->hideport;
[123]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 }
[24]939 addstring(&str, " </body>\n");
940 addstring(&str, "</html>\n");
[32]941 tw_process_page(s, sock, tw_http_status(200), "text/html", NULL, str, strlen(str), 0, 0);
[24]942 free(str);
[21]943 }
944 }
[22]945 } else {
[21]946 char* ext = NULL;
[212]947 char* mime;
948 FILE* f;
[22]949 for(i = strlen(req.path) - 1; i >= 0; i--) {
950 if(req.path[i] == '.') {
[21]951 ext = cm_strdup(req.path + i);
952 break;
[24]953 } else if(req.path[i] == '/') {
954 break;
[21]955 }
956 }
[212]957 mime = tw_get_mime(ext, vhost_entry);
[21]958 if(ext != NULL) free(ext);
[212]959 f = fopen(path, "rb");
[173]960 if(f == NULL) {
961 tw_http_error(s, sock, 403, name, port, vhost_entry);
962 } else {
[349]963 tw_process_page(s, sock, tw_http_status(200), mime, f, NULL, st.st_size, st.st_mtime, cmtime);
[173]964 fclose(f);
965 }
[21]966 }
[22]967 } else {
[161]968 if(!rej) {
969 tw_http_error(s, sock, 404, name, port, vhost_entry);
970 }
[21]971 }
972 free(path);
[20]973 }
[21]974 free(vhost);
975 free(host);
[22]976 } else if(ret == -1) {
[18]977 } else {
[123]978 tw_http_error(s, sock, 400, name, port, &config.root);
[17]979 }
[70]980 tw_free_request(&req);
[12]981cleanup:
[43]982#ifndef NO_SSL
[16]983 if(sslworks) {
[15]984 SSL_shutdown(s);
985 }
986 SSL_free(s);
[46]987#endif
[11]988 close_socket(sock);
[219]989#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[315]990#ifdef __NETWARE__
[364]991 ExitThread(EXIT_THREAD, 0);
[359]992#elif defined(__DOS__)
[315]993#else
[216]994 _endthread();
[315]995#endif
[100]996#elif defined(__HAIKU__)
[105]997 exit_thread(0);
[11]998#endif
[216]999#ifndef NO_RETURN_THREAD
[214]1000 return 0;
[215]1001#endif
[11]1002}
1003
[62]1004#ifdef SERVICE
1005extern SERVICE_STATUS status;
1006extern SERVICE_STATUS_HANDLE status_handle;
1007#endif
1008
[219]1009#if defined(__MINGW32__) || defined(__HAIKU__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[65]1010struct thread_entry {
[101]1011#ifdef __HAIKU__
1012 thread_id thread;
[315]1013#elif defined(__NETWARE__)
1014 int thread;
[359]1015#elif defined(__DOS__)
[101]1016#else
[65]1017 HANDLE handle;
[101]1018#endif
[65]1019 bool used;
1020};
1021#endif
1022
[183]1023extern int running;
1024
[11]1025void tw_server_loop(void) {
[68]1026 int i;
[212]1027#ifndef USE_POLL
[213]1028 fd_set fdset;
1029 struct timeval tv;
[212]1030#endif
[384]1031#if defined(__MINGW32__) || defined(__HAIKU__) || defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && !defined(__NETWARE__) && !defined(__DOS__))
[401]1032 struct thread_entry threads[128];
[70]1033 for(i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) {
[65]1034 threads[i].used = false;
1035 }
1036#endif
[118]1037#ifdef USE_POLL
[302]1038 struct pollfd* pollfds = malloc(sizeof(*pollfds) * sockcount);
[118]1039 for(i = 0; i < sockcount; i++) {
1040 pollfds[i].fd = sockets[i];
1041 pollfds[i].events = POLLIN | POLLPRI;
1042 }
1043#endif
[183]1044 while(running) {
[212]1045 int ret;
[118]1046#ifdef USE_POLL
[212]1047 ret = poll(pollfds, sockcount, 1000);
[118]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;
[86]1055#ifdef __HAIKU__
[212]1056 ret = select(32, &fdset, NULL, NULL, &tv);
[86]1057#else
[212]1058 ret = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
[86]1059#endif
[118]1060#endif
[11]1061 if(ret == -1) {
[219]1062#if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
[296]1063 if(errno == EINTR) continue;
[402]1064 cm_log("Server", "Select/poll failure: %s", strerror(errno));
[84]1065#endif
[9]1066 break;
[70]1067 } else if(ret == 0) {
[62]1068#ifdef SERVICE
[70]1069 if(status.dwCurrentState == SERVICE_STOP_PENDING) {
[62]1070 break;
1071 }
1072#endif
[11]1073 } else if(ret > 0) {
[9]1074 /* connection */
1075 int i;
[11]1076 for(i = 0; i < sockcount; i++) {
[118]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) {
[9]1084 SOCKADDR claddr;
[182]1085 socklen_t clen = sizeof(claddr);
[9]1086 int sock = accept(sockets[i], (struct sockaddr*)&claddr, &clen);
[402]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
[212]1091 int j;
1092 struct pass_entry* e = malloc(sizeof(*e));
[12]1093 cm_log("Server", "New connection accepted");
[11]1094 e->sock = sock;
[215]1095#if defined(_MSC_VER) || defined(__BORLANDC__)
[212]1096 e->ssl = config.ports[i] & (1UL << 31);
1097#else
1098 e->ssl = config.ports[i] & (1ULL << 31);
1099#endif
[12]1100 e->port = config.ports[i];
[21]1101 e->addr = claddr;
[97]1102#endif
[219]1103#if defined(__MINGW32__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)
[312]1104#ifdef __OS2__
1105 _beginthread(tw_server_pass, 0, 0, e);
[315]1106#elif defined(__NETWARE__)
[361]1107 BeginThread(tw_server_pass, NULL, 0, e);
[359]1108#elif defined(__DOS__)
1109 tw_server_pass(e);
[312]1110#else
[212]1111 _beginthread(tw_server_pass, 0, e);
[312]1112#endif
[187]1113#elif defined(_PSP) || defined(__PPU__)
[183]1114 tw_server_pass(e);
[402]1115#elif defined(__amiga__)
1116 pthread_create(&thrt, NULL, tw_server_pass, e);
[97]1117#elif defined(__HAIKU__)
[183]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;
[101]1125 }
[183]1126 if(kill) {
1127 threads[j].used = false;
[101]1128 }
1129 }
[183]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 }
[11]1139#else
1140 pid_t pid = fork();
1141 if(pid == 0) {
[89]1142 int j;
1143 for(j = 0; j < sockcount; j++) close_socket(sockets[j]);
[212]1144 tw_server_pass(sock, config.ports[i] & (1ULL << 31), config.ports[i], claddr);
[11]1145 _exit(0);
1146 } else {
1147 close_socket(sock);
1148 }
1149#endif
[9]1150 }
1151 }
1152 }
1153 }
[255]1154 for(i = 0; i < sockcount; i++) {
[253]1155 close_socket(sockets[i]);
1156 }
1157 cm_force_log("Server is down");
[9]1158}
Note: See TracBrowser for help on using the repository browser.