diff --git a/Server/config.c b/Server/config.c index 15bcee7..a87b1de 100644 --- a/Server/config.c +++ b/Server/config.c @@ -82,6 +82,7 @@ void tw_config_init(void) { config.root.mime_count = 0; config.root.dir_count = 0; config.root.icon_count = 0; + config.root.index_count = 0; config.vhost_count = 0; config.module_count = 0; config.extension = NULL; @@ -181,6 +182,7 @@ int tw_config_read(const char* path) { current->dir_count = 0; current->mime_count = 0; current->icon_count = 0; + current->index_count = 0; int i; current->name = cm_strdup(vhost); current->port = -1; @@ -282,6 +284,10 @@ int tw_config_read(const char* path) { break; } } + } else if(cm_strcaseequ(r[0], "DirectoryIndex")) { + for(i = 1; r[i] != NULL; i++) { + current->indexes[current->index_count++] = cm_strdup(r[i]); + } } else { if(r[0] != NULL) { cm_log("Config", "Unknown directive `%s' at line %d", r[0], ln); diff --git a/Server/server.c b/Server/server.c index 53b1617..0ce6d38 100644 --- a/Server/server.c +++ b/Server/server.c @@ -169,22 +169,36 @@ size_t tw_write(SSL* ssl, int s, void* data, size_t len) { " \n" \ "\n" -void tw_process_page(SSL* ssl, int sock, const char* status, const char* type, FILE* f, const unsigned char* doc, size_t size) { +void _tw_process_page(SSL* ssl, int sock, const char* status, const char* type, FILE* f, const unsigned char* doc, size_t size, char** headers) { char construct[512]; sprintf(construct, "%llu", (unsigned long long)size); tw_write(ssl, sock, "HTTP/1.1 ", 9); tw_write(ssl, sock, (char*)status, strlen(status)); tw_write(ssl, sock, "\r\n", 2); - tw_write(ssl, sock, "Content-Type: ", 7 + 5 + 2); - tw_write(ssl, sock, (char*)type, strlen(type)); - tw_write(ssl, sock, "\r\n", 2); + if(type != NULL) { + tw_write(ssl, sock, "Content-Type: ", 7 + 5 + 2); + tw_write(ssl, sock, (char*)type, strlen(type)); + tw_write(ssl, sock, "\r\n", 2); + } tw_write(ssl, sock, "Server: ", 6 + 2); tw_write(ssl, sock, tw_server, strlen(tw_server)); tw_write(ssl, sock, "\r\n", 2); - tw_write(ssl, sock, "Content-Length: ", 7 + 7 + 2); - tw_write(ssl, sock, construct, strlen(construct)); - tw_write(ssl, sock, "\r\n", 2); + if(size != 0) { + tw_write(ssl, sock, "Content-Length: ", 7 + 7 + 2); + tw_write(ssl, sock, construct, strlen(construct)); + tw_write(ssl, sock, "\r\n", 2); + } + int i; + if(headers != NULL) { + for(i = 0; headers[i] != NULL; i += 2) { + tw_write(ssl, sock, headers[i], strlen(headers[i])); + tw_write(ssl, sock, ": ", 2); + tw_write(ssl, sock, headers[i + 1], strlen(headers[i + 1])); + tw_write(ssl, sock, "\r\n", 2); + } + } tw_write(ssl, sock, "\r\n", 2); + if(doc == NULL && f == NULL) return; size_t incr = 0; while(1) { if(f != NULL) { @@ -200,9 +214,13 @@ void tw_process_page(SSL* ssl, int sock, const char* status, const char* type, F } } +void tw_process_page(SSL* ssl, int sock, const char* status, const char* type, FILE* f, const unsigned char* doc, size_t size) { _tw_process_page(ssl, sock, status, type, f, doc, size, NULL); } + const char* tw_http_status(int code) { if(code == 200) { return "200 OK"; + } else if(code == 308) { + return "308 Permanent Redirect"; } else if(code == 400) { return "400 Bad Request"; } else if(code == 401) { @@ -414,76 +432,116 @@ void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) { if(!tw_permission_allowed(path, addr, req, vhost_entry)) { tw_http_error(s, sock, 403, name, port); } else if(S_ISDIR(st.st_mode)) { - char* str = malloc(1); - str[0] = 0; - char** items = cm_scandir(path); - addstring(&str, "\n"); - addstring(&str, "\n"); - addstring(&str, " \n"); - addstring(&str, " \n"); - addstring(&str, " Index of %h\n", req.path); - addstring(&str, " \n"); - addstring(&str, " \n"); - addstring(&str, "

Index of %h

\n", req.path); - addstring(&str, "
\n"); - addstring(&str, " \n"); - addstring(&str, " \n"); - addstring(&str, " \n"); - addstring(&str, " \n"); - addstring(&str, " \n"); - if(items != NULL) { - for(i = 0; items[i] != NULL; i++) { - char* ext = NULL; - int j; - for(j = strlen(items[i]) - 1; j >= 0; j--) { - if(items[i][j] == '.') { - ext = cm_strdup(items[i] + j); - break; + if(req.path[strlen(req.path) - 1] != '/') { + char* headers[3] = {"Location", cm_strcat(req.path, "/"), NULL}; + _tw_process_page(s, sock, tw_http_status(308), NULL, NULL, NULL, 0, headers); + free(headers[1]); + } else { + char** indexes = vhost_entry->index_count == 0 ? config.root.indexes : vhost_entry->indexes; + int index_count = vhost_entry->index_count == 0 ? config.root.index_count : vhost_entry->index_count; + bool found = false; + for(i = 0; i < index_count; i++) { + char* p = cm_strcat3(path, "/", indexes[i]); + FILE* f = fopen(p, "rb"); + if(f != NULL) { + char* ext = NULL; + int j; + for(j = strlen(p) - 1; j >= 0; j--) { + if(p[j] == '.') { + ext = cm_strdup(p + j); + break; + } else if(p[j] == '/') { + break; + } + } + struct stat st; + stat(p, &st); + char* mime = tw_get_mime(ext, vhost_entry); + tw_process_page(s, sock, tw_http_status(200), mime, f, NULL, st.st_size); + fclose(f); + free(p); + found = true; + break; + } + free(p); + } + if(!found) { + char* str = malloc(1); + str[0] = 0; + char** items = cm_scandir(path); + addstring(&str, "\n"); + addstring(&str, "\n"); + addstring(&str, " \n"); + addstring(&str, " \n"); + addstring(&str, " Index of %h\n", req.path); + addstring(&str, " \n"); + addstring(&str, " \n"); + addstring(&str, "

Index of %h

\n", req.path); + addstring(&str, "
\n"); + addstring(&str, "
Filename
\n"); + addstring(&str, " \n"); + addstring(&str, " \n"); + addstring(&str, " \n"); + addstring(&str, " \n"); + if(items != NULL) { + for(i = 0; items[i] != NULL; i++) { + char* ext = NULL; + int j; + for(j = strlen(items[i]) - 1; j >= 0; j--) { + if(items[i][j] == '.') { + ext = cm_strdup(items[i] + j); + break; + } else if(items[i][j] == '/') { + break; + } + } + char* mime = tw_get_mime(ext, vhost_entry); + if(strcmp(items[i], "../") == 0) { + mime = "misc/parent"; + } else if(items[i][strlen(items[i]) - 1] == '/') { + mime = "misc/dir"; + } + char* icon = tw_get_icon(mime, vhost_entry); + if(ext != NULL) free(ext); + char* itm = cm_strdup(items[i]); + if(strlen(itm) >= 32) { + if(itm[strlen(itm) - 1] == '/') { + itm[31] = 0; + itm[30] = '/'; + itm[29] = '.'; + itm[28] = '.'; + itm[27] = '.'; + } else { + itm[31] = 0; + itm[30] = '.'; + itm[29] = '.'; + itm[28] = '.'; + } + } + addstring(&str, "\n"); + addstring(&str, " \n", icon); + addstring(&str, " \n", items[i], itm); + addstring(&str, "\n"); + free(itm); } } - char* mime = tw_get_mime(ext, vhost_entry); - if(strcmp(items[i], "../") == 0) { - mime = "misc/parent"; - } else if(items[i][strlen(items[i]) - 1] == '/') { - mime = "misc/dir"; - } - char* icon = tw_get_icon(mime, vhost_entry); - if(ext != NULL) free(ext); - char* itm = cm_strdup(items[i]); - if(strlen(itm) >= 32) { - if(itm[strlen(itm) - 1] == '/') { - itm[31] = 0; - itm[30] = '/'; - itm[29] = '.'; - itm[28] = '.'; - itm[27] = '.'; - } else { - itm[31] = 0; - itm[30] = '.'; - itm[29] = '.'; - itm[28] = '.'; - } - } - addstring(&str, "\n"); - addstring(&str, " \n", icon); - addstring(&str, " \n", items[i], itm); - addstring(&str, "\n"); - free(itm); + addstring(&str, "
Filename
\"icon\"%h
\"icon\"%h
\n"); + addstring(&str, "
\n"); + addstring(&str, "
%s Server at %s Port %d
\n", tw_server, name, port); + addstring(&str, " \n"); + addstring(&str, "\n"); + tw_process_page(s, sock, tw_http_status(200), "text/html", NULL, str, strlen(str)); + free(str); } } - addstring(&str, " \n"); - addstring(&str, "
\n"); - addstring(&str, "
%s Server at %s Port %d
\n", tw_server, name, port); - addstring(&str, " \n"); - addstring(&str, "\n"); - tw_process_page(s, sock, tw_http_status(200), "text/html", NULL, str, strlen(str)); - free(str); } else { char* ext = NULL; for(i = strlen(req.path) - 1; i >= 0; i--) { if(req.path[i] == '.') { ext = cm_strdup(req.path + i); break; + } else if(req.path[i] == '/') { + break; } } char* mime = tw_get_mime(ext, vhost_entry); diff --git a/Server/tw_config.h b/Server/tw_config.h index 7f63dda..98bf244 100644 --- a/Server/tw_config.h +++ b/Server/tw_config.h @@ -27,6 +27,7 @@ #define MAX_DIRS 1024 #define MAX_MIME 1024 #define MAX_ICON 1024 +#define MAX_INDEX 1024 enum TW_DIR_TYPE { TW_DIR_ALLOW = 0, @@ -61,6 +62,8 @@ struct tw_config_entry { int mime_count; struct tw_icon_entry icons[MAX_DIRS]; int icon_count; + char* indexes[MAX_INDEX]; + int index_count; }; struct tw_config { diff --git a/example.conf b/example.conf index dabc79a..8e0ec30 100644 --- a/example.conf +++ b/example.conf @@ -16,9 +16,12 @@ MIMEType .png image/png Icon all /icons/unknown.png Icon text/* /icons/text.png +Icon image/* /icons/image.png Icon misc/dir /icons/folder.png Icon misc/parent /icons/parent.png +DirectoryIndex index.html + DocumentRoot /var/www BeginDirectory /