C语言gets/scanf读取含换行HTTP请求字符串提前终止问题求解
问题原因说明
原有读取方式的固有逻辑直接导致读取不符合预期:
gets()是逐行读取函数,碰到第一个换行符就会终止读取,还会自动丢弃读到的换行符,因此最多只能读到第一行的请求行内容,无法获取后续空行和请求体。另外该函数因为存在无法限制读取长度的缓冲区溢出漏洞,早已被C标准废弃,生产环境禁止使用。- 无格式参数的
scanf("%s")读取规则是碰到任意空白字符(空格、换行、制表符)就终止,因此碰到GET后面的空格就会停止,只能读到第一个单词。
实现方案
按照需求分两步实现读取逻辑,全程用安全的fgets()做逐段读取,手动控制读取终止条件和校验逻辑:
- 先读取第一行请求行,解析路径字段做校验:如果路径不是
/api,直接终止读取流程;如果校验通过,把第一行内容写入目标缓冲区。 - 校验通过后继续读取后续内容,累计统计读到的换行符数量,当换行符总数达到3个时立即停止读取,保证刚好读完三行(请求行、空行、请求体行),全程控制写入长度不超过缓冲区大小,避免溢出。
参考实现代码:
#include <stdio.h> #include <string.h> int main() { char msg_send[1000] = {0}; // 记录缓冲区当前写入位置偏移 size_t offset = 0; char line_buf[256] = {0}; int newline_cnt = 0; // 读取第一行做路径校验 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { return -1; } // 统计第一行内的换行符 char* p = line_buf; while (*p) { if (*p == '\n') newline_cnt++; p++; } // 拆分第一行的方法、路径、版本字段 char method[16] = {0}, path[256] = {0}, version[16] = {0}; sscanf(line_buf, "%15s %255s %15s", method, path, version); // 路径不符合要求直接终止流程 if (strcmp(path, "/api") != 0) { return 0; } // 校验通过将第一行写入目标缓冲区 size_t line_len = strlen(line_buf); if (offset + line_len < sizeof(msg_send) - 1) { memcpy(msg_send + offset, line_buf, line_len); offset += line_len; } else { return -1; } // 继续读取后续内容,直到累计读到3个换行符 while (newline_cnt < 3 && fgets(line_buf, sizeof(line_buf), stdin) != NULL) { p = line_buf; while (*p && newline_cnt < 3) { if (*p == '\n') { newline_cnt++; } p++; } line_len = strlen(line_buf); if (offset + line_len < sizeof(msg_send) - 1) { memcpy(msg_send + offset, line_buf, line_len); offset += line_len; } else { return -1; } if (newline_cnt >= 3) break; } // 手动补字符串结束符 msg_send[offset] = '\0'; // 后续可直接操作msg_send处理完整内容 printf("读取到的完整内容:\n%s", msg_send); return 0; }
逻辑说明
- 读取第一行时用带长度限制的
sscanf做格式拆分,直接拿到path字段做比对,满足路径错误即终止的需求,同时避免字段读取溢出。 - 全程维护写入偏移量
offset,每次写入前判断剩余缓冲区空间,不会出现越界写入问题。 - 逐字符统计换行符数量,累计到3个就停止,刚好匹配“读到第三个换行符终止”的规则,不会多读也不会少读。
- 所有读取操作都用
fgets指定最大读取长度,不存在缓冲区溢出风险。
内容的提问来源于stack exchange,提问作者User 1999
相关产品推荐
相关产品推荐

