#include #include #include #include #include #include #include #include #define PORT 12580 #define MAX_REQUEST_SIZE 1500 #define MAX_RESPONSE_SIZE 1500 // 网页根目录 #define WEB_ROOT "/var/www/html/" #define EXIT_CODE 1 #define min(a, b) ((a) < (b) ? (a) : (b)) #define DEFAULT_PAGE "/index.html" int security_check(char *path) { // 检查路径是否包含 .. if (strstr(path, "..")) { return 0; } return 1; } ssize_t send_response(int sockfd, char *response) { return write(sockfd, response, strlen(response)); } void send_header(int sockfd, int content_length, char *path) { char buffer[MAX_RESPONSE_SIZE]; // 获取文件类型 char *content_type; if (strstr(path, ".html")) { content_type = "text/html"; } else if (strstr(path, ".css")) { content_type = "text/css"; } else if (strstr(path, ".js")) { content_type = "application/javascript"; } else if (strstr(path, ".png")) { content_type = "image/png"; } else if (strstr(path, ".jpg")) { content_type = "image/jpeg"; } else if (strstr(path, ".gif")) { content_type = "image/gif"; } else { content_type = "text/plain;charset=utf-8"; } sprintf(buffer, "HTTP/1.1 200 OK\nContent-Type: %s\nContent-Length: %d\n\n", content_type, content_length); send_response(sockfd, buffer); } void send_file(int sockfd, char *path) { printf("send_file: path: %s\n", path); int fd = open(path, 0); if (fd == -1) { send_response( sockfd, "HTTP/1.1 404 Not Found\nContent-Type: text/html\n\n

404 Not Found

DragonOS Http Server

"); return; } int content_length = lseek(fd, 0, SEEK_END); int remaining = content_length; printf("send_file: content_length: %d\n", content_length); lseek(fd, 0, SEEK_SET); send_header(sockfd, content_length, path); char buffer[1048576]; int readSize; while (remaining) { // 由于磁盘IO耗时较长,所以每次读取1MB,然后再分批发送 int to_read = min(1048576, remaining); readSize = read(fd, &buffer, to_read); remaining -= readSize; void *p = buffer; while (readSize > 0) { int wsize = write(sockfd, p, min(readSize, MAX_RESPONSE_SIZE)); if (wsize <= 0) { printf("send_file failed: wsize: %d\n", wsize); close(fd); return; } p += wsize; readSize -= wsize; } } close(fd); } void handle_request(int sockfd, char *request) { char *method, *url, *http_version; char path[MAX_REQUEST_SIZE]; method = strtok(request, " "); url = strtok(NULL, " "); http_version = strtok(NULL, "\r\n"); printf("handle_request: method: %s, url: %s, http_version: %s\n", method, url, http_version); // 检查空指针等异常情况 if (method == NULL || url == NULL || http_version == NULL) { send_response(sockfd, "HTTP/1.1 400 Bad Request\nContent-Type: text/html\n\n

400 Bad " "Request

DragonOS Http Server

"); return; } // 检查url是否为空 if (strlen(url) == 0) { send_response(sockfd, "HTTP/1.1 400 Bad Request\nContent-Type: text/html\n\n

400 Bad " "Request

DragonOS Http Server

"); return; } int default_page = 0; if (url[strlen(url) - 1] == '/') { default_page = 1; } if (strcmp(method, "GET") == 0) { if (default_page) { sprintf(path, "%s%s%s", WEB_ROOT, url, DEFAULT_PAGE); } else { sprintf(path, "%s%s", WEB_ROOT, url); } if (!security_check(path)) { send_response( sockfd, "HTTP/1.1 403 Forbidden\nContent-Type: text/html\n\n

403 Forbidden

DragonOS Http Server

"); return; } send_file(sockfd, path); } else { send_response(sockfd, "HTTP/1.1 501 Not Implemented\nContent-Type: text/html\n\n

501 Not " "Implemented

DragonOS Http Server

"); } } int main(int argc, char const *argv[]) { int server_fd, new_socket, valread; struct sockaddr_in address; int addrlen = sizeof(address); char buffer[MAX_REQUEST_SIZE] = {0}; int opt = 1; // 创建socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_CODE); } // 设置socket选项,允许地址重用 // if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) // { // perror("setsockopt failed"); // exit(EXIT_CODE); // } // 设置地址和端口 address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // 把socket绑定到地址和端口上 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_CODE); } // 监听socket if (listen(server_fd, 3) < 0) { perror("listen failed"); exit(EXIT_CODE); } while (1) { printf("Waiting for a client...\n"); // 等待并接受客户端连接 if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { perror("accept failed"); exit(EXIT_CODE); } // 接收客户端消息 valread = read(new_socket, buffer, MAX_REQUEST_SIZE); printf("%s\n", buffer); // 处理请求 handle_request(new_socket, buffer); // 关闭客户端连接 close(new_socket); } return 0; }