#include #include #include #include #include #include #include #include #define PORT 8081 #define BUFFER_SIZE 512 #define MAX_PATH 128 #define ROOT_DIR "." static const struct { const char *ext; const char *type; } mime_types[] = { {".html", "text/html"}, {".css", "text/css"}, {".js", "application/javascript"}, {".jpg", "image/jpeg"}, {".jpeg", "image/jpeg"}, {".png", "image/png"}, {NULL, "application/octet-stream"} }; static const char *get_mime_type(const char *path) { const char *ext = strrchr(path, '.'); if (!ext) return mime_types[0].type; for (int i = 0; mime_types[i].ext; i++) { if (!strcmp(ext, mime_types[i].ext)) return mime_types[i].type; } return mime_types[0].type; } static void send_response(int ssl, const char *status, const char *type, const char *body, size_t len) { char buf[BUFFER_SIZE]; int n = snprintf(buf, sizeof(buf), "HTTP/1.1 %s\r\nContent-Type: %s\r\nContent-Length: %zu\r\n\r\n", status, type, len); write(ssl, buf, n); if (len && body) write(ssl, body, len); } static void write_full(int ssl, const char *data, size_t len) { while (len > 0) { int sent = write(ssl, data, len); if (sent <= 0) break; data += sent; len -= sent; } } static void list_files(int ssl) { char buf[8192] = "File Server

Files

    "; size_t pos = strlen(buf); DIR *dir = opendir(ROOT_DIR); if (!dir) { send_response(ssl, "500 Internal Server Error", "text/plain", "Cannot open directory", 20); return; } struct dirent *entry; while ((entry = readdir(dir)) && pos < sizeof(buf) - 100) { if (entry->d_name[0] == '.') continue; struct stat st; char path[MAX_PATH]; snprintf(path, sizeof(path), "%s/%s", ROOT_DIR, entry->d_name); if (stat(path, &st) < 0 || S_ISDIR(st.st_mode)) continue; pos += snprintf(buf + pos, sizeof(buf) - pos, "
  • %s
  • ", entry->d_name, entry->d_name); } closedir(dir); pos += snprintf(buf + pos, sizeof(buf) - pos, "
"); send_response(ssl, "200 OK", "text/html", buf, pos); } static void handle_request(int ssl, char *req) { char method[8], path[MAX_PATH], proto[8]; if (sscanf(req, "%7s %127s %7s", method, path, proto) != 3) { send_response(ssl, "400 Bad Request", "text/plain", "Bad Request", 11); return; } if (strcmp(method, "GET")) { send_response(ssl, "405 Method Not Allowed", "text/plain", "Method Not Allowed", 18); return; } if (strstr(path, "..")) { send_response(ssl, "403 Forbidden", "text/plain", "Forbidden", 9); return; } if (!strcmp(path, "/favicon.ico")) { send_response(ssl, "204 No Content", "text/plain", NULL, 0); return; } if (!strcmp(path, "/")) { list_files(ssl); return; } char file_path[MAX_PATH]; snprintf(file_path, sizeof(file_path), "%s/%s", ROOT_DIR, path[0] == '/' ? path + 1 : path); struct stat st; if (stat(file_path, &st) < 0 || S_ISDIR(st.st_mode)) { send_response(ssl, st.st_mode ? "403 Forbidden" : "404 Not Found", "text/plain", st.st_mode ? "Directory listing not allowed" : "Not Found", st.st_mode ? 28 : 9); return; } int fd = open(file_path, O_RDONLY); if (fd < 0) { send_response(ssl, "404 Not Found", "text/plain", "Not Found", 9); return; } char buf[BUFFER_SIZE]; int n = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lld\r\n\r\n", get_mime_type(file_path), (long long)st.st_size); write_full(ssl, buf, n); char data[16384]; off_t total_sent = 0; ssize_t bytes; while ((bytes = read(fd, data, sizeof(data))) > 0) { write_full(ssl, data, bytes); total_sent += bytes; } close(fd); if (total_sent != st.st_size) { send_response(ssl, "500 Internal Server Error", "text/plain", "Incomplete transfer", 18); } close(ssl); } int main() { struct stat st; if (stat(ROOT_DIR, &st) < 0 || !S_ISDIR(st.st_mode)) return 1; int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { return 1; } int opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(PORT) }; if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0 || listen(sock, 5) < 0) { close(sock); return 1; } printf("Server started on https://localhost:%d\n", PORT); char buf[BUFFER_SIZE]; struct sockaddr_in client; socklen_t len = sizeof(client); while (1) { int client_sock = accept(sock, (struct sockaddr *)&client, &len); if (client_sock < 0) continue; int n = read(client_sock, buf, BUFFER_SIZE - 1); if (n > 0) { buf[n] = '\0'; handle_request(client_sock, buf); } // close(client_sock); } close(sock); return 0; }