- Timestamp:
- Sep 14, 2024, 9:39:39 PM (2 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Common/Makefile
r6 r21 6 6 .SUFFIXES: .c .o 7 7 8 OBJS = string.o log.o 8 OBJS = string.o log.o dir.o 9 9 10 10 all: common.a -
trunk/Common/cm_string.h
r20 r21 8 8 int cm_hex(const char* str, int len); 9 9 char* cm_html_escape(const char* str); 10 char* cm_url_escape(const char* str); 10 11 char* cm_strcat(const char* a, const char* b); 11 12 char* cm_strcat3(const char* a, const char* b, const char* c); -
trunk/Common/string.c
r20 r21 160 160 return result; 161 161 } 162 163 char* cm_url_escape(const char* str) { 164 int i; 165 char* result = malloc(1); 166 result[0] = 0; 167 char cbuf[2]; 168 cbuf[1] = 0; 169 for(i = 0; str[i] != 0; i++) { 170 cbuf[0] = str[i]; 171 if('!' <= str[i] && str[i] <= '@' && str[i] != '.' && str[i] != '-' && str[i] != '/' && !('0' <= str[i] && str[i] <= '9')) { 172 char code[4]; 173 sprintf(code, "%%%02X", str[i]); 174 char* tmp = result; 175 result = cm_strcat(tmp, code); 176 free(tmp); 177 } else { 178 char* tmp = result; 179 result = cm_strcat(tmp, cbuf); 180 free(tmp); 181 } 182 } 183 return result; 184 } -
trunk/Server/config.c
r20 r21 31 31 } 32 32 33 bool tw_permission_allowed(const char* path, SOCKADDR addr, struct tw_http_request req, struct tw_config_entry* vhost){ 34 int i; 35 bool found = false; 36 bool pathstart = false; 37 bool perm = false; 38 again: 39 for(i = 0; i < vhost->dir_count; i++){ 40 struct tw_dir_entry* e = &vhost->dirs[i]; 41 pathstart = false; 42 if(strlen(path) >= strlen(e->dir)){ 43 pathstart = true; 44 int j; 45 for(j = 0; path[j] != 0 && e->dir[j] != 0; j++){ 46 if(path[j] != e->dir[j]){ 47 pathstart = false; 48 break; 49 } 50 } 51 } 52 char* noslash = cm_strdup(e->dir); 53 noslash[strlen(noslash) - 1] = 0; 54 if(strcmp(e->dir, path) == 0 || strcmp(noslash, path) == 0 || pathstart){ 55 found = true; 56 if(strcmp(e->name, "all") == 0){ 57 perm = e->type == TW_DIR_ALLOW; 58 } 59 } 60 free(noslash); 61 } 62 if(!found && vhost != &config.root){ 63 vhost = &config.root; 64 goto again; 65 } 66 return perm; 67 } 68 33 69 void tw_config_init(void) { 34 70 int i; … … 44 80 config.root.sslcert = NULL; 45 81 config.root.root = NULL; 82 config.root.mime_count = 0; 83 config.root.dir_count = 0; 46 84 config.vhost_count = 0; 47 85 config.module_count = 0; … … 63 101 struct tw_config_entry* current = &config.root; 64 102 char* vhost = NULL; 103 char* dir = NULL; 65 104 while(stop == 0) { 66 105 int c = fread(cbuf, 1, 1, f); … … 78 117 } 79 118 } 119 } else if(cm_strcaseequ(r[0], "BeginDirectory")) { 120 if(dir != NULL) { 121 cm_log("Config", "Already in directory section at line %d", ln); 122 stop = 1; 123 } else { 124 if(r[1] == NULL) { 125 cm_log("Config", "Missing directory at line %d", ln); 126 stop = 1; 127 } else { 128 dir = cm_strcat(r[1], r[1][strlen(r[1]) - 1] == '/' ? "" : "/"); 129 } 130 } 131 } else if(cm_strcaseequ(r[0], "EndDirectory")) { 132 if(dir == NULL) { 133 cm_log("Config", "Not in directory section at line %d", ln); 134 stop = 1; 135 } else { 136 free(dir); 137 dir = NULL; 138 } 139 } else if(cm_strcaseequ(r[0], "Allow")) { 140 if(dir == NULL) { 141 cm_log("Config", "Not in directory section at line %d", ln); 142 stop = 1; 143 } else { 144 if(r[1] == NULL) { 145 cm_log("Config", "Missing argument at line %d", ln); 146 stop = 1; 147 } else { 148 struct tw_dir_entry* e = ¤t->dirs[current->dir_count++]; 149 e->name = cm_strdup(r[1]); 150 e->dir = cm_strdup(dir); 151 e->type = TW_DIR_ALLOW; 152 } 153 } 154 } else if(cm_strcaseequ(r[0], "Deny")) { 155 if(dir == NULL) { 156 cm_log("Config", "Not in directory section at line %d", ln); 157 stop = 1; 158 } else { 159 if(r[1] == NULL) { 160 cm_log("Config", "Missing argument at line %d", ln); 161 stop = 1; 162 } else { 163 struct tw_dir_entry* e = ¤t->dirs[current->dir_count++]; 164 e->name = cm_strdup(r[1]); 165 e->dir = cm_strdup(dir); 166 e->type = TW_DIR_DENY; 167 } 168 } 80 169 } else if(cm_strcaseequ(r[0], "BeginVirtualHost")) { 81 170 if(vhost != NULL) { … … 89 178 vhost = cm_strdup(r[1]); 90 179 current = &config.vhosts[config.vhost_count++]; 180 current->dir_count = 0; 181 current->mime_count = 0; 91 182 int i; 92 183 current->name = cm_strdup(vhost); … … 142 233 } else { 143 234 if(current->root != NULL) free(current->root); 144 current->root = cm_strdup( r[1]);235 current->root = cm_strdup(strcmp(r[1], "/") == 0 ? "" : r[1]); 145 236 } 146 237 } else if(cm_strcaseequ(r[0], "ServerRoot")) { … … 151 242 if(config.server_root != NULL) free(config.server_root); 152 243 config.server_root = cm_strdup(r[1]); 244 } 245 } else if(cm_strcaseequ(r[0], "MIMEType")) { 246 if(r[1] == NULL) { 247 cm_log("Config", "Missing extension at line %d", ln); 248 stop = 1; 249 }else if(r[2] == NULL) { 250 cm_log("Config", "Missing MIME at line %d", ln); 251 stop = 1; 252 } else { 253 struct tw_mime_entry* e = ¤t->mimes[current->mime_count++]; 254 e->ext = cm_strdup(r[1]); 255 e->mime = cm_strdup(r[2]); 153 256 } 154 257 } else if(cm_strcaseequ(r[0], "LoadModule")) { -
trunk/Server/server.c
r20 r21 15 15 #include <stdbool.h> 16 16 #include <stdarg.h> 17 #include <sys/stat.h> 17 18 18 19 #include <cm_string.h> 19 20 #include <cm_log.h> 21 #include <cm_dir.h> 20 22 21 23 #ifdef __MINGW32__ 22 24 #include <winsock2.h> 23 25 #include <process.h> 24 #define NO_IPV625 26 #else 26 27 #include <sys/select.h> … … 37 38 int sockcount = 0; 38 39 39 #ifdef NO_IPV640 #define SOCKADDR struct sockaddr_in41 #else42 #define SOCKADDR struct sockaddr_in643 #endif44 40 SOCKADDR addresses[MAX_PORTS]; 45 41 int sockets[MAX_PORTS]; … … 152 148 "</html>\n" 153 149 154 void tw_process_page(SSL* ssl, int sock, const char* status, const char* type, const unsigned char* doc, size_t size) {150 void tw_process_page(SSL* ssl, int sock, const char* status, const char* type, FILE* f, const unsigned char* doc, size_t size) { 155 151 char construct[512]; 156 152 sprintf(construct, "%llu", (unsigned long long)size); … … 170 166 size_t incr = 0; 171 167 while(1) { 172 tw_write(ssl, sock, (unsigned char*)doc + incr, size < 128 ? size : 128); 168 if(f != NULL){ 169 char buffer[128]; 170 fread(buffer, size < 128 ? size : 128, 1, f); 171 tw_write(ssl, sock, buffer, size < 128 ? size : 128); 172 }else{ 173 tw_write(ssl, sock, (unsigned char*)doc + incr, size < 128 ? size : 128); 174 } 173 175 incr += 128; 174 176 if(size <= 128) break; … … 216 218 void tw_http_error(SSL* ssl, int sock, int error, char* name, int port) { 217 219 char* str = tw_http_default_error(error, name, port); 218 tw_process_page(ssl, sock, tw_http_status(error), "text/html", str, strlen(str));220 tw_process_page(ssl, sock, tw_http_status(error), "text/html", NULL, str, strlen(str)); 219 221 free(str); 220 222 } … … 240 242 free(tmp); 241 243 free(h); 244 } else if(add[i] == 'l') { 245 char* h = cm_url_escape(va_arg(va, const char*)); 246 char* tmp = *str; 247 *str = cm_strcat(tmp, h); 248 free(tmp); 249 free(h); 242 250 } else if(add[i] == 'd') { 243 251 int n = va_arg(va, int); … … 266 274 int port; 267 275 bool ssl; 276 SOCKADDR addr; 268 277 }; 269 278 … … 272 281 bool ssl = ((struct pass_entry*)ptr)->ssl; 273 282 int port = ((struct pass_entry*)ptr)->port; 283 SOCKADDR addr = ((struct pass_entry*)ptr)->addr; 274 284 free(ptr); 275 285 #else 276 void tw_server_pass(int sock, bool ssl, int port ) {286 void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) { 277 287 #endif 278 288 char* name = config.hostname; … … 295 305 int ret = tw_http_parse(s, sock, &req); 296 306 if(ret == 0) { 307 char* vhost = cm_strdup(config.hostname); 297 308 int i; 309 for(i = 0; req.headers[i] != NULL; i += 2){ 310 if(cm_strcaseequ(req.headers[i], "Host")){ 311 free(vhost); 312 vhost = req.headers[i + 1]; 313 break; 314 } 315 } 316 cm_log("Server", "Host is %s", vhost); 317 int port = s == NULL ? 80 : 443; 318 char* host = cm_strdup(vhost); 319 for(i = 0; vhost[i] != 0; i++){ 320 if(vhost[i] == ':'){ 321 host[i] = 0; 322 port = atoi(host + i + 1); 323 break; 324 } 325 } 326 cm_log("Server", "Hostname is `%s', port is `%d'", host, port); 327 struct tw_config_entry* vhost_entry = tw_vhost_match(host, port); 298 328 for(i = 0; i < config.module_count; i++) { 299 329 tw_mod_request_t mod_req = (tw_mod_request_t)tw_module_symbol(config.modules[i], "mod_request"); … … 313 343 } 314 344 if(!res._processed) { 315 char* str = malloc(1); 316 str[0] = 0; 317 addstring(&str, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"); 318 addstring(&str, "<html>\n"); 319 addstring(&str, " <head>\n"); 320 addstring(&str, " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"); 321 addstring(&str, " <title>Index of %h</title>\n", req.path); 322 addstring(&str, " </head>\n"); 323 addstring(&str, " <body>\n"); 324 addstring(&str, " <h1>Index of %h</h1>\n", req.path); 325 addstring(&str, " <hr>\n"); 326 addstring(&str, " <table border=\"0\">\n"); 327 addstring(&str, " <tr>\n"); 328 addstring(&str, " <th></th>\n"); 329 addstring(&str, " <th>Filename</th>\n"); 330 addstring(&str, " </tr>\n"); 331 addstring(&str, " </table>\n"); 332 addstring(&str, " <hr>\n"); 333 addstring(&str, " <address>%s Server at %s Port %d</address>\n", tw_server, name, port); 334 addstring(&str, " </body>\n"); 335 addstring(&str, "</html>\n"); 336 tw_process_page(s, sock, tw_http_status(200), "text/html", str, strlen(str)); 337 free(str); 338 } 345 cm_log("Server", "Document root is %s", vhost_entry->root == NULL ? "not set" : vhost_entry->root); 346 char* path = cm_strcat(vhost_entry->root == NULL ? "" : vhost_entry->root, req.path); 347 cm_log("Server", "Filesystem path is %s", path); 348 struct stat st; 349 if(stat(path, &st) == 0){ 350 if(!tw_permission_allowed(path, addr, req, vhost_entry)){ 351 tw_http_error(s, sock, 403, name, port); 352 }else if(S_ISDIR(st.st_mode)){ 353 char* str = malloc(1); 354 str[0] = 0; 355 char** items = cm_scandir(path); 356 addstring(&str, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"); 357 addstring(&str, "<html>\n"); 358 addstring(&str, " <head>\n"); 359 addstring(&str, " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"); 360 addstring(&str, " <title>Index of %h</title>\n", req.path); 361 addstring(&str, " </head>\n"); 362 addstring(&str, " <body>\n"); 363 addstring(&str, " <h1>Index of %h</h1>\n", req.path); 364 addstring(&str, " <hr>\n"); 365 addstring(&str, " <table border=\"0\">\n"); 366 addstring(&str, " <tr>\n"); 367 addstring(&str, " <th></th>\n"); 368 addstring(&str, " <th>Filename</th>\n"); 369 addstring(&str, " </tr>\n"); 370 if(items != NULL){ 371 for(i = 0; items[i] != NULL; i++){ 372 addstring(&str, "<tr>\n"); 373 addstring(&str, " <td></td>\n"); 374 addstring(&str, " <td><a href=\"%l\">%h</a></td>\n", items[i], items[i]); 375 addstring(&str, "</tr>\n"); 376 } 377 } 378 addstring(&str, " </table>\n"); 379 addstring(&str, " <hr>\n"); 380 addstring(&str, " <address>%s Server at %s Port %d</address>\n", tw_server, name, port); 381 addstring(&str, " </body>\n"); 382 addstring(&str, "</html>\n"); 383 tw_process_page(s, sock, tw_http_status(200), "text/html", NULL, str, strlen(str)); 384 free(str); 385 }else{ 386 char* mime = "application/octet-stream"; 387 bool set = false; 388 char* ext = NULL; 389 for(i = strlen(req.path) - 1; i >= 0; i--){ 390 if(req.path[i] == '.'){ 391 ext = cm_strdup(req.path + i); 392 break; 393 } 394 } 395 for(i = 0; i < vhost_entry->mime_count; i++){ 396 if(strcmp(vhost_entry->mimes[i].ext, "all") == 0 || (ext != NULL && strcmp(vhost_entry->mimes[i].ext, ext) == 0)){ 397 mime = vhost_entry->mimes[i].mime; 398 set = true; 399 } 400 } 401 if(!set){ 402 for(i = 0; i < config.root.mime_count; i++){ 403 if(strcmp(config.root.mimes[i].ext, "all") == 0 || (ext != NULL && strcmp(config.root.mimes[i].ext, ext) == 0)){ 404 mime = config.root.mimes[i].mime; 405 set = true; 406 } 407 } 408 } 409 if(ext != NULL) free(ext); 410 FILE* f = fopen(path, "rb"); 411 tw_process_page(s, sock, tw_http_status(200), mime, f, NULL, st.st_size); 412 fclose(f); 413 } 414 }else{ 415 tw_http_error(s, sock, 404, name, port); 416 } 417 free(path); 418 } 419 free(vhost); 420 free(host); 339 421 } else { 340 422 tw_http_error(s, sock, 400, name, port); … … 379 461 e->ssl = config.ports[i] & (1ULL << 32); 380 462 e->port = config.ports[i]; 463 e->addr = claddr; 381 464 thread = (HANDLE)_beginthreadex(NULL, 0, tw_server_pass, e, 0, NULL); 382 465 #else 383 466 pid_t pid = fork(); 384 467 if(pid == 0) { 385 tw_server_pass(sock, config.ports[i] & (1ULL << 32), config.ports[i] );468 tw_server_pass(sock, config.ports[i] & (1ULL << 32), config.ports[i], claddr); 386 469 _exit(0); 387 470 } else { -
trunk/Server/tw_config.h
r19 r21 4 4 #define __TW_CONFIG_H__ 5 5 6 #include "tw_http.h" 7 6 8 #include <stdint.h> 9 #include <stdbool.h> 7 10 8 #define MAX_PORTS 1024 9 #define MAX_VHOSTS 1024 10 #define MAX_MODULES 1024 11 #ifdef __MINGW32__ 12 #include <winsock2.h> 13 #define NO_IPV6 14 #else 15 #include <netinet/in.h> 16 #endif 17 18 #ifdef NO_IPV6 19 #define SOCKADDR struct sockaddr_in 20 #else 21 #define SOCKADDR struct sockaddr_in6 22 #endif 23 24 #define MAX_PORTS 1024 25 #define MAX_VHOSTS 1024 26 #define MAX_MODULES 1024 27 #define MAX_DIRS 1024 28 #define MAX_MIME 1024 29 30 enum TW_DIR_TYPE { 31 TW_DIR_ALLOW = 0, 32 TW_DIR_DENY 33 }; 34 35 struct tw_dir_entry { 36 char* name; 37 char* dir; 38 int type; 39 }; 40 41 struct tw_mime_entry { 42 char* ext; 43 char* mime; 44 }; 11 45 12 46 struct tw_config_entry { … … 16 50 char* sslcert; 17 51 char* root; 52 struct tw_dir_entry dirs[MAX_DIRS]; 53 int dir_count; 54 struct tw_mime_entry mimes[MAX_DIRS]; 55 int mime_count; 18 56 }; 19 57 … … 33 71 int tw_config_read(const char* path); 34 72 struct tw_config_entry* tw_vhost_match(const char* name, int port); 73 bool tw_permission_allowed(const char* path, SOCKADDR addr, struct tw_http_request req, struct tw_config_entry* vhost); 35 74 36 75 #endif -
trunk/example.conf
r20 r21 10 10 SSLCertificate cert.pem 11 11 12 DocumentRoot /var/www 12 MIMEType all application/octet-stream 13 MIMEType .html text/html 14 15 DocumentRoot / 16 17 BeginDirectory / 18 Allow all 19 EndDirectory 20 21 BeginDirectory /var/www 22 Deny all 23 EndDirectory 13 24 14 25 BeginVirtualHost nishinbsd-ssd
Note:
See TracChangeset
for help on using the changeset viewer.