#include #include #include #include #include #include #include #include #include #define MAX_EVENTS 100 #define PORT 8080 #define MAX_REQUEST_SIZE 2048000 #define MAX_PATH_SIZE 1024 void url_decode(char *url) { int len = strlen(url); int i, j; for (i = 0, j = 0; i < len; ++i, ++j) { if (url[i] == '%' && i + 2 < len) { // Decode %20 to space int value; sscanf(url + i + 1, "%2x", &value); url[j] = (char)value; i += 2; } else { url[j] = url[i]; } } url[j] = '\0'; } void *handle_client(void *arg) { int client_socket = *(int *)arg; char request[MAX_REQUEST_SIZE]; char path[MAX_PATH_SIZE]; // Receive the HTTP request ssize_t bytes_received = recv(client_socket, request, sizeof(request) - 1, 0); if (bytes_received <= 0) { perror("Error receiving request"); close(client_socket); return NULL; } // Null-terminate the received data to treat it as a string request[bytes_received] = '\0'; // Parse the request to extract the path sscanf(request, "GET %s HTTP", path); // URL decode the path url_decode(path); // If the path is empty, default to "index.html" if (strlen(path) == 1 && path[0] == '/') { strcpy(path, "/index.html"); } // Open and read the file printf("%s\n", &path[1]); int file_fd = open(&path[1], O_RDONLY); if (file_fd == -1) { // File not found, send 404 Not Found response printf("File not found\n"); char response[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 15\r\n\r\n404 Not Found!"; send(client_socket, response, sizeof(response) - 1, 0); } else { // Read and send the file contents as the response char buffer[4096]; ssize_t bytes_read; char header[1024]; snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n", lseek(file_fd, 0, SEEK_END)); send(client_socket, header, strlen(header), 0); lseek(file_fd, 0, SEEK_SET); // Move the file pointer back to the beginning while ((bytes_read = read(file_fd, buffer, sizeof(buffer))) > 0) { send(client_socket, buffer, bytes_read, 0); } close(file_fd); } close(client_socket); pthread_exit(NULL); return NULL; } int main() { int server_socket, client_socket; struct sockaddr_in server_addr, client_addr; socklen_t client_len = sizeof(client_addr); // Create and set up the server socket server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { perror("Error creating socket"); exit(EXIT_FAILURE); } server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("Error binding socket"); exit(EXIT_FAILURE); } if (listen(server_socket, 5) == -1) { perror("Error listening on socket"); exit(EXIT_FAILURE); } // Set up epoll int epoll_fd = epoll_create1(0); struct epoll_event event, events[MAX_EVENTS]; event.events = EPOLLIN; event.data.fd = server_socket; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &event); while (1) { int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); for (int i = 0; i < num_events; i++) { if (events[i].data.fd == server_socket) { // Accept new connection client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_len); event.events = EPOLLIN; event.data.fd = client_socket; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_socket, &event); } else { // Handle data from an existing client client_socket = events[i].data.fd; pthread_t thread_id; pthread_create(&thread_id, NULL, handle_client, &client_socket); // handle_client(client_socket); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_socket, NULL); } } } close(server_socket); return 0; }