把以下代码中//的注释,修改为/* */
#include "common.h"
/**
* 根据文件扩展名获取MIME类型
* @param path 文件路径
* @return 对应的MIME类型字符串
*/
const char *get_mime_type(const char *path)
{
/* 检查空指针和空字符串 */
if (path == NULL || *path == '\0')
{
return "text/plain";
}
const char *ext = strrchr(path, '.'); // 查找最后一个点号
if (!ext)
return "text/plain"; // 无扩展名默认纯文本
// 常见文件类型匹配
if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0)
return "text/html";
if (strcmp(ext, ".css") == 0)
return "text/css";
if (strcmp(ext, ".js") == 0)
return "application/javascript";
if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0)
return "image/jpeg";
if (strcmp(ext, ".png") == 0)
return "image/png";
if (strcmp(ext, ".gif") == 0)
return "image/gif";
if (strcmp(ext, ".json") == 0)
return "application/json";
if (strcmp(ext, ".ico") == 0)
return "image/x-icon";
return "text/plain"; // 未知扩展名默认纯文本
}
/**
* 发送HTTP响应
* @param fd 客户端套接字
* @param status HTTP状态码
* @param status_msg 状态描述
* @param content_type 内容类型
* @param body 响应体内容
* @param body_len 响应体长度
*/
void send_response(int fd, int status, const char *status_msg,
const char *content_type, const char *body, int body_len)
{
/* 入参检查 */
if (fd < 0 || status <= 0 || status_msg == NULL ||
content_type == NULL || (body_len > 0 && body == NULL))
{
perror("send_response: Invalid input parameters");
return;
}
char header[BUFFER_SIZE];
// 构建HTTP响应头
int header_len = snprintf(header, BUFFER_SIZE,
"HTTP/1.1 %d %s\r\n" // 状态行
"Content-Type: %s\r\n" // 内容类型
"Content-Length: %d\r\n" // 内容长度
"Connection: close\r\n" // 关闭连接
"\r\n", // 空行结束头部
status, status_msg, content_type, body_len);
// 发送响应头
write(fd, header, header_len);
// 发送响应体(如果有)
if (body && body_len > 0)
{
write(fd, body, body_len);
}
}
/**
* 发送文件内容
* @param fd 客户端套接字
* @param path 文件路径
*/
void send_file(int fd, const char *path)
{
/* 入参检查 */
if (fd < 0 || NULL == path)
{
perror("send_file:Invalid input parameters");
return;
}
struct stat file_stat;
// 获取文件状态信息
if (stat(path, &file_stat) < 0 || !S_ISREG(file_stat.st_mode))
{
// 文件不存在或不是普通文件
send_response(fd, 404, "Not Found", "text/html",
"<h1>404 Not Found</h1>", 22);
return;
}
// 打开文件
int file_fd = open(path, O_RDONLY);
if (file_fd < 0)
{
// 文件打开失败
send_response(fd, 500, "Internal Server Error", "text/html",
"<h1>500 Internal Error</h1>", 26);
return;
}
// 获取MIME类型
const char *mime_type = get_mime_type(path);
char header[BUFFER_SIZE];
// 构建成功响应头
int header_len = snprintf(header, BUFFER_SIZE,
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n"
"Connection: close\r\n"
"\r\n",
mime_type, file_stat.st_size);
// 发送响应头
write(fd, header, header_len);
fprintf(stdout, "**********header**********\n%s\n", header);
// 使用sendfile零拷贝发送文件内容
off_t offset = 0;
size_t remaining = file_stat.st_size;
while (remaining > 0)
{
ssize_t sent = sendfile(fd, file_fd, &offset, remaining);
if (sent <= 0)
{
perror("sendfile");
break;
}
remaining -= sent;
}
// 关闭文件
close(file_fd);
}
/**
* 处理GET请求
* @param fd 客户端套接字
* @param path 请求路径
*/
void handle_get_request(int fd, const char *path)
{
/* 入参检查 */
if (fd < 0 || path == NULL || *path == '\0')
{
send_response(fd, 400, "Bad Request", "text/html",
"<h1>400 Invalid Request</h1>", 26);
return;
}
printf("handle_get_request.\n");
char full_path[BUFFER_SIZE];
// 构建完整文件路径
snprintf(full_path, BUFFER_SIZE, "%s%s", ROOT_DIR, path);
// 处理目录请求(以'/'结尾)
if (path[strlen(path) - 1] == '/')
{
DIR *dir = opendir(full_path);
if (!dir)
{
// 目录打开失败
send_response(fd, 404, "Not Found", "text/html",
"<h1>404 Not Found</h1>", 22);
return;
}
// 生成目录列表HTML
char body[BUFFER_SIZE * 2] = "<html><head><title>Index of ";
strcat(body, path);
strcat(body, "</title></head><body><h1>Index of ");
strcat(body, path);
strcat(body, "</h1><hr><ul>");
struct dirent *entry;
// 遍历目录项
while ((entry = readdir(dir)) != NULL)
{
// 跳过.和..
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
char li[256];
// 构建列表项
snprintf(li, sizeof(li),
"<li><a href=\"%s%s\">%s</a></li>",
path, entry->d_name, entry->d_name);
strcat(body, li);
}
strcat(body, "</ul><hr></body></html>");
// 发送目录列表
send_response(fd, 200, "OK", "text/html", body, strlen(body));
fflush(stdout); // 强制刷新缓冲区
closedir(dir);
return;
}
fprintf(stdout, "----\nfull_path:%s\n\n", full_path);
// 发送文件内容
send_file(fd, full_path);
}
/**
* 处理POST请求
* @param fd 客户端套接字
* @param path 请求路径
* @param body 请求体内容
* @param body_len 请求体长度
*/
void handle_post_request(int fd, const char *path, const char *body, int body_len)
{
/* 添加入参检查 */
if (fd < 0 || path == NULL || (body_len > 0 && body == NULL))
{
send_response(fd, 400, "Bad Request", "text/html",
"<h1>400 Invalid Request</h1>", 26);
return;
}
// 示例:处理联系表单提交
printf("%s\n",path);
char *user_data = strstr(body, "name=");
if (user_data != NULL)
{
char *delimiters = "&"; // 三个分隔符
char *tokens[4]; // 存储4个分段结果
int token_count = 0; // 当前分段计数
char *start = user_data; // 当前分段起始位置
char *current = user_data; // 当前扫描位置
// 遍历字符串并分段
while (*current != '\0' && token_count < 3) {
// 检查当前字符是否是目标分隔符
if (strchr(delimiters, *current) != NULL) {
tokens[token_count] = start;
*current = '\0';
start = current + 1;
token_count++;
// 如果已经处理了三个分隔符,跳出循环
if (token_count == 3) break;
}
current++;
}
// 添加最后一个分段
if (token_count < 4) {
tokens[token_count] = start;
token_count++;
}
fprintf(stdout, "%s\n%s\n%s\n",tokens[0],tokens[1],tokens[2]);
const char *filename = "contact_submissions.txt";
// 检查请求体长度
if (body_len <= 0)
{
send_response(fd, 400, "Empty Body", "text/html",
"<h1>400 Form data is empty</h1>", 31);
return;
}
// 安全打开文件(追加模式)
FILE *fp = fopen(filename, "a");
if (!fp)
{
perror("fopen failed");
send_response(fd, 500, "Internal Error", "text/html",
"<h1>500 Server storage error</h1>", 33);
return;
}
// 安全写入数据(防止缓冲区溢出)
if (fprintf(fp, "%s\n%s\n%s\n",tokens[0],tokens[1],tokens[2]) < 0)
{
perror("fprintf failed");
fclose(fp);
return;
}
// 确保数据刷入磁盘
if (fflush(fp) != 0)
{
perror("fflush failed");
}
// 安全关闭文件
if (fclose(fp) != 0)
{
perror("fclose failed");
}
// 返回成功响应
send_response(fd, 200, "OK", "text/html",
"<html><body><h1>Thank You!</h1><p>Form submitted successfully</p></body></html>", 60);
}
else
{
printf("404 post\n");
// 不支持其他POST路径
send_response(fd, 404, "Not Found", "text/html", "<h1>404 Not Found</h1>", 22);
}
}
/**
* 处理HTTP请求
* @param fd 客户端套接字
* @param request 请求数据
*/
void handle_request(int fd, const char *request)
{
/* 添加基础入参检查 */
if (fd < 0 || request == NULL || *request == '\0')
{
send_response(fd, 400, "Bad Request", "text/html",
"<h1>400 Empty Request</h1>", 25);
return;
}
char method[16], path[256], protocol[16];
// 解析请求行
if (sscanf(request, "%15s %255s %15s", method, path, protocol) != 3)
{
printf("400 Bad request.\n");
send_response(fd, 400, "Bad Request", "text/html", "<h1>400 Bad Request</h1>", 24);
return;
}
// 处理根路径请求
if (strcmp(path, "/") == 0)
{
strcpy(path, "/Index.html"); // 默认返回主页
}
// 查找请求体起始位置
const char *body = strstr(request, "\r\n\r\n");
if (body)
body += 4; // 跳过空行
// 方法分发
if (strcmp(method, "GET") == 0)
{
handle_get_request(fd, path);
}
else if (strcmp(method, "POST") == 0)
{
handle_post_request(fd, path, body, (body ? strlen(body) : 0));
}
else
{
// 不支持的方法
send_response(fd, 501, "Not Implemented", "text/html",
"<h1>501 Not Implemented</h1>", 25);
}
}
最新发布