Files
ligent/tests/test_http.c
T
2026-10-03 14:13:21 +08:00

113 lines
5.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* test_http.c - HTTP 层纯逻辑测试(不联网) */
#include "http.h"
#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int failures = 0;
static int checks = 0;
#define CHECK(cond, ...) \
do { \
checks++; \
if (!(cond)) { \
failures++; \
printf(" ✗ %s:%d: ", __FILE__, __LINE__); \
printf(__VA_ARGS__); \
printf("\n"); \
} \
} while (0)
int main(void)
{
puts("重试判定:只重试服务端明确报错的情况");
/* 应当重试 */
long retryable[] = { 408, 409, 429, 500, 502, 503, 504 };
for (size_t i = 0; i < sizeof retryable / sizeof retryable[0]; i++)
CHECK(http_status_retryable(retryable[i]) == 1,
"HTTP %ld 应当可重试", retryable[i]);
/* 绝不应当重试:这些是确定性错误,重试只是浪费时间和钱 */
long permanent[] = { 400, 401, 403, 404, 405, 413, 415, 422, 501,
200, 201, 204, 301, 0, -1 };
for (size_t i = 0; i < sizeof permanent / sizeof permanent[0]; i++)
CHECK(http_status_retryable(permanent[i]) == 0,
"HTTP %ld 不应重试", permanent[i]);
/* 默认策略与上限的合理性 */
HttpRetry def = HTTP_RETRY_DEFAULT;
HttpRetry none = HTTP_RETRY_NONE;
CHECK(def.max_retries > 0, "默认应当会重试");
CHECK(none.max_retries == 0, "HTTP_RETRY_NONE 应当不重试");
CHECK(HTTP_MAX_BODY >= 1024 * 1024, "响应体上限不该小到影响正常使用");
CHECK(HTTP_MAX_ERRBODY < HTTP_MAX_BODY, "错误体上限应远小于正文上限");
/* ---- 调试输出的密钥脱敏 ---- */
puts("--verbose 输出脱敏");
{
const char *key = "sk-0f114e3dac8249f0a36fd8fd5c517360";
char *buf = NULL;
size_t sz = 0;
FILE *f = open_memstream(&buf, &sz);
/* 这条正是曾经漏出去的:libcurl 的 HTTP/2 调试行走的是 CURLINFO_TEXT,
* 不是 HEADER_OUT,所以只处理 HEADER_OUT 的做法根本挡不住 */
const char *h2 = "== Info: [HTTP/2] [1] [authorization: Bearer sk-0f114e3dac8249f0a36fd8fd5c517360]\n";
http_write_redacted(f, h2, strlen(h2), key);
/* 整块请求头(HEADER_OUT 是整块传来的,不是逐行) */
const char *hdrs = "POST /v1/chat/completions HTTP/2\r\n"
"Authorization: Bearer sk-0f114e3dac8249f0a36fd8fd5c517360\r\n"
"Content-Type: application/json\r\n";
http_write_redacted(f, hdrs, strlen(hdrs), key);
/* 其它内容不能被改动 */
const char *plain = "== Info: TLSv1.3 (IN), TLS handshake, Finished (20):\n";
http_write_redacted(f, plain, strlen(plain), key);
/* 没有密钥时原样输出 */
http_write_redacted(f, "no key here\n", 12, "");
fclose(f);
CHECK(strstr(buf, key) == NULL, "输出里不应残留完整密钥");
CHECK(strstr(buf, "<已隐藏>") != NULL, "应替换为占位符");
CHECK(strstr(buf, "[HTTP/2]") != NULL, "HTTP/2 调试行本身应保留");
CHECK(strstr(buf, "Authorization: Bearer <已隐藏>") != NULL,
"请求头里的密钥应脱敏: %.200s", buf);
CHECK(strstr(buf, "TLS handshake") != NULL, "其它调试信息不能被误改");
CHECK(strstr(buf, "no key here") != NULL, "无密钥时原样输出");
/* 一次替换必须整段吃掉,不能留下半个密钥 */
CHECK(strstr(buf, "0f114e3dac") == NULL, "不应留下密钥片段");
free(buf);
}
puts("\n空请求体:POST 分支也要扛得住 body == NULL");
{
/* body 允许为 NULL(http_probe 就是这么调的),但 POST 分支以前写的是
* 无条件的 strlen(body) —— 传 NULL 会在 curl_easy_setopt 期间就段错误。
*
* 这里故意用一个格式非法的 URL:libcurl 会在真正联网之前就拒绝它,
* 所以本测试仍然不碰网络。而 strlen(NULL) 发生在设置 POSTFIELDS 期间、
* curl_easy_perform 之前,也就是说旧代码在这里必崩 —— 这个断言对旧
* 代码是有效的回归守卫,不是走过场。 */
static const HttpRetry no_retry = HTTP_RETRY_NONE;
char errbuf[256] = "";
int attempts = 0;
long status = 0;
http_global_init();
int rc = http_post(":::", "sk-test", NULL, 5, 0, &no_retry,
NULL, &status, &attempts, errbuf, sizeof errbuf);
http_global_cleanup();
CHECK(rc == -1, "非法 URL 应当返回 -1(实际返回 %d)", rc);
CHECK(errbuf[0] != '\0', "失败时必须给出错误说明");
}
printf("\n%d 项检查,%d 项失败\n", checks, failures);
return failures ? 1 : 0;
}