diff --git a/http.c b/http.c index 4ad4e94..8660f26 100644 --- a/http.c +++ b/http.c @@ -12,6 +12,7 @@ #include #include #include +#include /** * 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; diff --git a/http.h b/http.h index f32c9e6..e24c807 100644 --- a/http.h +++ b/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 === */ diff --git a/server.c b/server.c index 3768f1f..abc3d3c 100644 --- a/server.c +++ b/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,生成目录列表 */ diff --git a/static.c b/static.c index bd5598e..72df7b1 100644 --- a/static.c +++ b/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, "