feat(http): 添加缓存头部解析 + 修复编译警告
- http: 解析 If-None-Match 和 If-Modified-Since 请求头 - http: 响应结构体添加 etag 和 last_modified 字段 - server/static: 替换 strncpy 为 snprintf,消除 stringop-truncation 警告 - static: 修复 CSS 百分号转义(%%) - static: 消除 unused parameter 警告
This commit is contained in:
parent
a30fcf6ee1
commit
413288d837
15
http.c
15
http.c
@ -12,6 +12,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* http_method_str - HTTP 方法枚举转字符串
|
||||
@ -63,6 +64,8 @@ static void parse_headers(const char **p, const char *end, http_request_t *req)
|
||||
req->has_range = false;
|
||||
req->range_start = 0;
|
||||
req->range_end = -1;
|
||||
req->has_if_none_match = false;
|
||||
req->has_if_modified_since = false;
|
||||
|
||||
while (*p < end && req->num_headers < HTTP_MAX_HEADERS) {
|
||||
const char *line_start = *p;
|
||||
@ -107,6 +110,18 @@ static void parse_headers(const char **p, const char *end, http_request_t *req)
|
||||
req->content_length = atoll(req->headers[req->num_headers].value);
|
||||
} else if (strcmp(req->headers[req->num_headers].name, "connection") == 0) {
|
||||
req->keep_alive = (strcasecmp(req->headers[req->num_headers].value, "keep-alive") == 0);
|
||||
} else if (strcmp(req->headers[req->num_headers].name, "if-none-match") == 0) {
|
||||
req->has_if_none_match = true;
|
||||
int copy_len = strlen(req->headers[req->num_headers].value);
|
||||
if (copy_len >= 64) copy_len = 63;
|
||||
memcpy(req->if_none_match, req->headers[req->num_headers].value, copy_len);
|
||||
req->if_none_match[copy_len] = '\0';
|
||||
} else if (strcmp(req->headers[req->num_headers].name, "if-modified-since") == 0) {
|
||||
req->has_if_modified_since = true;
|
||||
int copy_len = strlen(req->headers[req->num_headers].value);
|
||||
if (copy_len >= 64) copy_len = 63;
|
||||
memcpy(req->if_modified_since, req->headers[req->num_headers].value, copy_len);
|
||||
req->if_modified_since[copy_len] = '\0';
|
||||
} else if (strcmp(req->headers[req->num_headers].name, "range") == 0) {
|
||||
/* 解析 Range: bytes=start-end */
|
||||
const char *range_val = req->headers[req->num_headers].value;
|
||||
|
||||
10
http.h
10
http.h
@ -48,6 +48,12 @@ typedef struct {
|
||||
bool has_range;
|
||||
int64_t range_start;
|
||||
int64_t range_end;
|
||||
|
||||
/* 缓存相关头 */
|
||||
char if_none_match[64];
|
||||
char if_modified_since[64];
|
||||
bool has_if_none_match;
|
||||
bool has_if_modified_since;
|
||||
} http_request_t;
|
||||
|
||||
/* === HTTP 响应 === */
|
||||
@ -61,6 +67,10 @@ typedef struct {
|
||||
int64_t range_start;
|
||||
int64_t range_end;
|
||||
int64_t total_length;
|
||||
|
||||
/* 缓存 */
|
||||
const char *etag;
|
||||
const char *last_modified;
|
||||
} http_response_t;
|
||||
|
||||
/* === API === */
|
||||
|
||||
14
server.c
14
server.c
@ -173,8 +173,7 @@ static bool handle_request(connection_t *conn, const char *root_dir) {
|
||||
static_send_error(conn->fd, 403, req.keep_alive);
|
||||
return req.keep_alive;
|
||||
}
|
||||
strncpy(real_path, resolved, sizeof(real_path) - 1);
|
||||
real_path[sizeof(real_path) - 1] = '\0';
|
||||
snprintf(real_path, sizeof(real_path), "%s", resolved);
|
||||
}
|
||||
|
||||
/* 判断文件类型 */
|
||||
@ -187,13 +186,18 @@ static bool handle_request(connection_t *conn, const char *root_dir) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* 目录:尝试 index.html */
|
||||
char index_path[4096];
|
||||
snprintf(index_path, sizeof(index_path), "%s/index.html", real_path);
|
||||
if (snprintf(index_path, sizeof(index_path), "%s/index.html", real_path) >= (int)sizeof(index_path)) {
|
||||
static_send_error(conn->fd, 400, req.keep_alive);
|
||||
return req.keep_alive;
|
||||
}
|
||||
struct stat index_st;
|
||||
if (stat(index_path, &index_st) == 0 && S_ISREG(index_st.st_mode)) {
|
||||
/* 有 index.html,作为文件服务 */
|
||||
http_request_t index_req = req;
|
||||
strncpy(index_req.path, req.path, sizeof(index_req.path) - 1);
|
||||
strncat(index_req.path, "/index.html", sizeof(index_req.path) - strlen(index_req.path) - 1);
|
||||
if (snprintf(index_req.path, sizeof(index_req.path), "%s/index.html", req.path) >= (int)sizeof(index_req.path)) {
|
||||
static_send_error(conn->fd, 400, req.keep_alive);
|
||||
return req.keep_alive;
|
||||
}
|
||||
static_serve_file(conn->fd, &index_req, root_dir);
|
||||
} else {
|
||||
/* 无 index.html,生成目录列表 */
|
||||
|
||||
10
static.c
10
static.c
@ -40,8 +40,7 @@ static bool safe_path_join(char *dst, size_t dst_size,
|
||||
/* 先规范化根目录 */
|
||||
char root_normalized[4096];
|
||||
if (!realpath(root, root_normalized)) {
|
||||
strncpy(root_normalized, root, sizeof(root_normalized) - 1);
|
||||
root_normalized[sizeof(root_normalized) - 1] = '\0';
|
||||
snprintf(root_normalized, sizeof(root_normalized), "%s", root);
|
||||
}
|
||||
size_t root_len = strlen(root_normalized);
|
||||
|
||||
@ -57,8 +56,7 @@ static bool safe_path_join(char *dst, size_t dst_size,
|
||||
if (strncmp(resolved, root_normalized, root_len) != 0) {
|
||||
return false;
|
||||
}
|
||||
strncpy(dst, resolved, dst_size - 1);
|
||||
dst[dst_size - 1] = '\0';
|
||||
snprintf(dst, dst_size, "%s", resolved);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -301,6 +299,8 @@ static void html_escape(const char *src, char *dst, size_t dst_size) {
|
||||
*/
|
||||
int static_serve_directory(int fd, const http_request_t *req,
|
||||
const char *root_dir, const char *real_path) {
|
||||
(void)root_dir; /* 未直接使用,real_path 已通过 safe_path_join 处理 */
|
||||
|
||||
/* 检查目录是否可访问 */
|
||||
struct stat st;
|
||||
if (stat(real_path, &st) != 0 || !S_ISDIR(st.st_mode)) {
|
||||
@ -333,7 +333,7 @@ int static_serve_directory(int fd, const http_request_t *req,
|
||||
"<style>"
|
||||
"body{font-family:system-ui,-apple-system,sans-serif;max-width:800px;margin:40px auto;padding:0 20px}"
|
||||
"h1{border-bottom:1px solid #ddd;padding-bottom:10px}"
|
||||
"table{width:100%;border-collapse:collapse}"
|
||||
"table{width:100%%;border-collapse:collapse}"
|
||||
"th{text-align:left;padding:8px;border-bottom:2px solid #ddd}"
|
||||
"td{padding:8px;border-bottom:1px solid #eee}"
|
||||
"a{text-decoration:none;color:#0066cc}"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user