Linux C下HTTP服务器使用虚拟目录代码
时间: 2024-03-16 11:43:57 浏览: 59
以下是一个简单的HTTP服务器示例程序,它使用虚拟目录来映射URL到本地文件系统路径:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_PORT 8080
#define MAX_REQUEST_SIZE 2048
#define DOCUMENT_ROOT "/var/www/html"
#define NOT_FOUND_PAGE "404.html"
#define FORBIDDEN_PAGE "403.html"
void serve(int client_fd, char *request) {
char method[16], url[256], protocol[16];
sscanf(request, "%s %s %s", method, url, protocol);
if (strcmp(method, "GET") != 0) {
dprintf(client_fd, "HTTP/1.1 501 Not Implemented\r\n");
dprintf(client_fd, "Content-Length: 0\r\n\r\n");
return;
}
if (strstr(url, "/../") != NULL || strstr(url, "/..") == url) {
dprintf(client_fd, "HTTP/1.1 403 Forbidden\r\n");
dprintf(client_fd, "Content-Length: 0\r\n\r\n");
return;
}
char path[256];
sprintf(path, "%s%s", DOCUMENT_ROOT, url);
char *file_path = realpath(path, NULL);
if (file_path == NULL || strncmp(file_path, DOCUMENT_ROOT, strlen(DOCUMENT_ROOT)) != 0) {
dprintf(client_fd, "HTTP/1.1 404 Not Found\r\n");
dprintf(client_fd, "Content-Length: 0\r\n\r\n");
return;
}
int file_fd = open(file_path, O_RDONLY);
if (file_fd < 0) {
dprintf(client_fd, "HTTP/1.1 404 Not Found\r\n");
dprintf(client_fd, "Content-Length: 0\r\n\r\n");
return;
}
struct stat file_stat;
fstat(file_fd, &file_stat);
dprintf(client_fd, "HTTP/1.1 200 OK\r\n");
dprintf(client_fd, "Content-Type: text/html\r\n");
dprintf(client_fd, "Content-Length: %ld\r\n\r\n", file_stat.st_size);
char file_buffer[1024];
ssize_t bytes_read, bytes_written;
while ((bytes_read = read(file_fd, file_buffer, sizeof(file_buffer))) > 0) {
bytes_written = write(client_fd, file_buffer, bytes_read);
if (bytes_written < 0) {
break;
}
}
close(file_fd);
}
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket");
exit(1);
}
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(SERVER_PORT),
.sin_addr.s_addr = INADDR_ANY
};
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind");
exit(1);
}
if (listen(server_fd, 128) < 0) {
perror("listen");
exit(1);
}
while (1) {
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_fd < 0) {
perror("accept");
continue;
}
char request[MAX_REQUEST_SIZE];
ssize_t bytes_read = read(client_fd, request, sizeof(request) - 1);
if (bytes_read < 0) {
perror("read");
close(client_fd);
continue;
}
request[bytes_read] = '\0';
printf("%s\n", request);
serve(client_fd, request);
close(client_fd);
}
close(server_fd);
return 0;
}
```
在这个示例程序中,使用`DOCUMENT_ROOT`宏定义指定了网站的根目录。当有客户端连接时,服务器读取客户端发送的HTTP请求,并使用`realpath`函数将请求的URL映射到本地文件系统路径。如果URL中包含`/../`或以`/..`开头,表示客户端试图访问服务器文件系统中的上级目录,这被认为是非法的操作,服务器会返回HTTP状态码403 Forbidden。如果映射到的文件路径不在根目录下,服务器会返回HTTP状态码404 Not Found。否则,服务器打开文件并将其内容发送给客户端。如果文件不存在,则返回HTTP状态码404 Not Found。
阅读全文