feat(ncm): MUSIC_U 临期主动续期 — 启动查龄超阈值后台静默刷新/eapi 会话锚点/cookie 合并+冷却
用户定案:失效前用当前 cookie 换新登录态(用户无感);仅刷新失败才退扫码重登。 - core/ncm_req.c|h:eapi Cookie 头补齐会话锚点 MUSIC_U/MUSIC_A(对齐 request.rs, 补 §36.5 遗留——登录刷新/song_url 会员档依赖);新增 ncm_req_cookie_merge (patch 覆盖 base 同名 cookie,MUSIC_A/__remember_me 等不丢)。 - core/ncm_login.c|h:ncm_login_refresh(eapi /api/login/token/refresh 空体, code200+set-cookie→merge;code!=200→NCM_ERR_AUTH 退扫码;网络/TLS→负码退避)。 - app/logic/account.c:account.json 增 last_refresh_ts + 拆分 cvip/svip; account_cookie_maybe_refresh(年龄阈值 12h 可配 ncm.cookie_refresh_h,单飞/boot, 失败冷却 30min 跨 boot 持久化,AUTH 置回登录页标志)+ mark_fresh/need_relogin。 - app/ui/home.c:home_worker 先续期再拉歌单;app/ui/login.c:803 落盘后 mark_fresh; app/app.c:UI tick 消费回登录标志 → logout+切登录页。 - 新增测试:test_ncm_core 的 cookie_merge + eapi_musicu_hdr;bench/cookie_refresh_sim (端点语义,0 网络);bench/account_cookie_sim(临期/未临期/退避/失效/冷却,0 网络)。 验证:host+qemu 核心测试 PASS;build_ncm_sims.sh 全家桶 PASS;build_ncm.sh 0 warning。 真机只读探针 2 次(设备 10.78.193.50,不写回):refresh 走 eapi 域 interface.music.163.com 在当前网络被 TLS reset(alert 80)→ rc=-5 瞬断退避, session.enc/deviceId md5 前后一致(登录态零损伤)。新 ncm md5 c960244b。
This commit is contained in:
1 parent
de18cef02c
commit
cd7329d141
17 files changed
+673
-13
No files matched your search
@@ -0,0 +1,189 @@
|
||||
/* bench/account_cookie_sim.c — MUSIC_U 临期续期决策逻辑验证(§NEW,0 真实 NCM 请求)。
|
||||
*
|
||||
* 用**真实** app/logic/account.c,仅把外围依赖换成桩(g_st 状态 + meow_config/log +
|
||||
* ncm_login_refresh(强制结果)+ ncm_ctx_set_cookie(记录落盘)+ ncm_store/json),验证
|
||||
* account_cookie_maybe_refresh 的语义(用户定案):
|
||||
* ① 临期触发:cookie 年龄超阈值(12h)→ 后台静默刷一次(refresh 被调、新 cookie 应用、落盘
|
||||
* last_refresh_ts 更新);
|
||||
* ② 未临期:年龄 ≤ 阈值 → 不刷(refresh 零调用);
|
||||
* ③ 首次/旧会话(last_refresh_ts=0,未知年龄)→ 视为临期刷一次;
|
||||
* ④ 失败退避:网络/TLS 瞬断 → 负错误码返回 + 冷却记录(30 分钟内重拨不重刷);
|
||||
* ⑤ 失效兜底:code301/-460 → NCM_ERR_AUTH + 置「需回登录页」标志(UI 退扫码);
|
||||
* ⑥ 冷却:上次失败 < 30 分钟(跨 boot 持久化 fail_ts)→ 即使临期也不刷。
|
||||
* 风控纪律:0 次真实 NCM 请求;ncm_login_refresh 为桩、时间由 g_now 推动。
|
||||
|
||||
* 编译(宿主),在 ncm_app 目录:见 build_ncm_sims.sh 新增 account_cookie_sim 段。
|
||||
* 运行:./account_cookie_sim
|
||||
*/
|
||||
#include "ncm.h"
|
||||
#include "ncm_app_internal.h" /* ncm_app_state_t / g_st / account_* 声明 */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ---- 真实 account.o 依赖的外围桩 ---- */
|
||||
ncm_app_state_t g_st; /* 全局状态(app.c 通常定义;本桩自持) */
|
||||
|
||||
static int64_t g_now_ms = 0; /* 时钟(ncm_now_ms 桩返回,驱动年龄/冷却) */
|
||||
int64_t ncm_now_ms(void) { return g_now_ms; }
|
||||
|
||||
static int g_refresh_calls = 0; /* ncm_login_refresh 桩调用计数 */
|
||||
static int g_refresh_rc = NCM_OK; /* 桩强制返回码 */
|
||||
static const char *g_refresh_out = NULL; /* 成功时写入 out_cookie 的串 */
|
||||
int ncm_login_refresh(const char *device_id, const char *cookie,
|
||||
char *out_cookie, size_t out_cookie_sz) {
|
||||
(void)device_id; (void)cookie;
|
||||
g_refresh_calls++;
|
||||
if (g_refresh_rc == NCM_OK && g_refresh_out)
|
||||
snprintf(out_cookie, out_cookie_sz, "%s", g_refresh_out);
|
||||
return g_refresh_rc;
|
||||
}
|
||||
|
||||
static char g_applied_cookie[NCM_COOKIE_MAX]; /* ncm_ctx_set_cookie 落盘内容 */
|
||||
static int g_set_cookie_calls = 0;
|
||||
int ncm_ctx_set_cookie(ncm_ctx_t *ctx, const char *cookie) {
|
||||
if (cookie) snprintf(ctx->cookie, sizeof ctx->cookie, "%s", cookie);
|
||||
else ctx->cookie[0] = 0;
|
||||
snprintf(g_applied_cookie, sizeof g_applied_cookie, "%s", cookie ? cookie : "");
|
||||
g_set_cookie_calls++;
|
||||
return NCM_OK;
|
||||
}
|
||||
|
||||
static char g_account_json[1024]; /* account_persist 写出的 account.json */
|
||||
static int g_write_calls = 0;
|
||||
int ncm_store_read_file(const char *path, char *buf, size_t sz) { (void)path; (void)buf; (void)sz; return -1; }
|
||||
int ncm_store_write_file(const char *path, const void *data, size_t len) {
|
||||
(void)path;
|
||||
size_t n = len < sizeof g_account_json - 1 ? len : sizeof g_account_json - 1;
|
||||
memcpy(g_account_json, data, n); g_account_json[n] = 0;
|
||||
g_write_calls++;
|
||||
return NCM_OK;
|
||||
}
|
||||
|
||||
/* account.o 引用的 json 便捷函数(本桩不调用 account_load,占位保证链接) */
|
||||
int ncm_json_parse(ncm_json_t *j, const char *text, size_t len,
|
||||
jsmntok_t *toks, int tokcap, int *parent) {
|
||||
(void)j; (void)text; (void)len; (void)toks; (void)tokcap; (void)parent; return -1;
|
||||
}
|
||||
int ncm_json_path(const ncm_json_t *j, const char *path) { (void)j; (void)path; return -1; }
|
||||
int ncm_json_path_int(const ncm_json_t *j, const char *path, long *out) { (void)j; (void)path; if (out) *out = 0; return NCM_OK; }
|
||||
int64_t ncm_json_get_i64_at(const ncm_json_t *j, int tok, int *rc) { (void)j; (void)tok; if (rc) *rc = NCM_OK; return 0; }
|
||||
int ncm_api_vip_info(const char *d, const char *ck, const char *uid, ncm_vip_info_t *out) {
|
||||
(void)d; (void)ck; (void)uid; if (out) memset(out, 0, sizeof *out); return NCM_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
static int g_cfg_hours = 12; /* ncm.cookie_refresh_h 配置 */
|
||||
static int g_cfg_fail_ts = 0; /* ncm.cookie_refresh_fail_ts 配置(跨 boot 冷却) */
|
||||
int meow_config_int(const char *key, int def) {
|
||||
if (strcmp(key, "ncm.cookie_refresh_h") == 0) return g_cfg_hours;
|
||||
if (strcmp(key, "ncm.cookie_refresh_fail_ts") == 0) return g_cfg_fail_ts;
|
||||
return def;
|
||||
}
|
||||
int meow_config_get(const char *key, char *out, int outsz) {
|
||||
(void)outsz;
|
||||
char b[24];
|
||||
if (strcmp(key, "ncm.cookie_refresh_fail_ts") == 0) { snprintf(b, sizeof b, "%d", g_cfg_fail_ts); }
|
||||
else { snprintf(b, sizeof b, "%d", meow_config_int(key, 0)); }
|
||||
snprintf(out, (size_t)outsz, "%s", b);
|
||||
return 0;
|
||||
}
|
||||
int meow_config_set(const char *key, const char *val) {
|
||||
if (strcmp(key, "ncm.cookie_refresh_fail_ts") == 0) g_cfg_fail_ts = atoi(val);
|
||||
return 0;
|
||||
}
|
||||
void meow_log(meow_log_level lvl, const char *fmt, ...) { (void)lvl; (void)fmt; }
|
||||
|
||||
/* ---- harness ---- */
|
||||
static int g_fail = 0;
|
||||
#define CHECK(cond, fmt, ...) do { \
|
||||
if (cond) printf(" PASS " fmt "\n", ##__VA_ARGS__); \
|
||||
else { printf(" FAIL " fmt "\n", ##__VA_ARGS__); g_fail = 1; } \
|
||||
} while (0)
|
||||
|
||||
#define NOW_S (1'700'000'000ll) /* 基准秒 */
|
||||
#define COOKIE "MUSIC_U=OLD_TOKEN; __csrf=cs; MUSIC_A=anon"
|
||||
static void reset_state(int64_t last_refresh_ts)
|
||||
{
|
||||
memset(&g_st, 0, sizeof g_st);
|
||||
g_st.logged_in = 1;
|
||||
snprintf(g_st.ctx.cookie, sizeof g_st.ctx.cookie, "%s", COOKIE);
|
||||
snprintf(g_st.ctx.device_id, sizeof g_st.ctx.device_id, "AA11BB22CC33DD44EE55FF6600112233445566778899AABB00");
|
||||
g_st.vip = NCM_VIP_NONE;
|
||||
g_now_ms = NOW_S * 1000;
|
||||
g_refresh_calls = 0; g_refresh_rc = NCM_OK; g_refresh_out = "MUSIC_U=NEW_TOKEN; __csrf=cs2; MUSIC_A=anon";
|
||||
g_set_cookie_calls = 0; g_applied_cookie[0] = 0;
|
||||
g_account_json[0] = 0; g_write_calls = 0;
|
||||
g_cfg_hours = 12; g_cfg_fail_ts = 0;
|
||||
/* mark_fresh 重置 account.c 内单飞/冷却/回登录标志(跨用例需手动清) */
|
||||
account_cookie_mark_fresh();
|
||||
g_st.cookie_last_refresh_ts = last_refresh_ts; /* 覆盖为用例指定年龄 */
|
||||
g_st.logged_in = 1; /* mark_fresh 不碰登录态,显式恢复 */
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
puts("== account_cookie_sim: 临期续期决策 ==");
|
||||
|
||||
/* ① 临期触发:年龄超阈值(12h)→ 后台静默刷一次,新 cookie 应用 + 落盘 last_refresh_ts */
|
||||
reset_state(NOW_S - 13 * 3600); /* 13h 前刷过 → 已临期 */
|
||||
int rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK, "临期: rc=0 (got %d)", rc);
|
||||
CHECK(g_refresh_calls == 1, "临期: refresh 被调 1 次 (got %d)", g_refresh_calls);
|
||||
CHECK(g_set_cookie_calls == 1, "临期: 新 cookie 已应用落盘 (got %d)", g_set_cookie_calls);
|
||||
CHECK(strstr(g_applied_cookie, "NEW_TOKEN") != NULL, "临期: 应用的是新 MUSIC_U");
|
||||
CHECK(g_st.cookie_last_refresh_ts == NOW_S, "临期: last_refresh_ts 更新为 now (got %lld)",
|
||||
(long long)g_st.cookie_last_refresh_ts);
|
||||
CHECK(strstr(g_account_json, "\"last_refresh_ts\":") != NULL, "临时: account.json 记录 last_refresh_ts");
|
||||
CHECK(g_cfg_fail_ts == 0, "临期成功: 冷却已清 (got %d)", g_cfg_fail_ts);
|
||||
|
||||
/* ② 未临期:年龄 ≤ 阈值 → 不刷 */
|
||||
reset_state(NOW_S - 5 * 3600); /* 5h 前刷过 → 未临期 */
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK && g_refresh_calls == 0, "未临期: 不刷 (calls=%d)", g_refresh_calls);
|
||||
|
||||
/* ③ 首次/旧会话:last_refresh_ts=0 → 视为临期刷一次 */
|
||||
reset_state(0);
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK && g_refresh_calls == 1, "旧会话(last=0): 视为临期刷一次 (calls=%d)", g_refresh_calls);
|
||||
|
||||
/* ④ 失败退避:网络/TLS 瞬断 → 负错误码 + 冷却记录,随后冷却期内不重刷 */
|
||||
reset_state(NOW_S - 13 * 3600);
|
||||
g_refresh_rc = NCM_ERR_NET;
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_ERR_NET, "瞬断: rc=%d (期望 %d)", rc, NCM_ERR_NET);
|
||||
CHECK(g_set_cookie_calls == 0, "瞬断: 未应用新 cookie");
|
||||
CHECK(g_cfg_fail_ts == (int)NOW_S, "瞬断: 冷却时间已持久化 (got %d)", g_cfg_fail_ts);
|
||||
/* 同 boot 再调(单飞)→ 不重刷;跨 boot 冷却:走新进程静态清零但 fail_ts 持久化在 config */
|
||||
int c = g_refresh_calls;
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK && g_refresh_calls == c, "瞬断+单飞: 本 boot 不再重试 (calls=%d)", g_refresh_calls);
|
||||
|
||||
/* ⑤ 失效兜底:code301 → NCM_ERR_AUTH + 置「需回登录页」标志 */
|
||||
reset_state(NOW_S - 13 * 3600);
|
||||
g_refresh_rc = NCM_ERR_AUTH;
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_ERR_AUTH, "失效: rc=%d (期望 %d)", rc, NCM_ERR_AUTH);
|
||||
CHECK(account_cookie_need_relogin() == 1, "失效: 置回登录页标志");
|
||||
account_cookie_relogin_consume();
|
||||
CHECK(account_cookie_need_relogin() == 0, "失效: 标志可被 UI 消费");
|
||||
|
||||
/* ⑥ 冷却(跨 boot):config fail_ts 为 10 分钟前,即使临期也不刷 */
|
||||
reset_state(NOW_S - 13 * 3600);
|
||||
g_cfg_fail_ts = (int)(NOW_S - 10 * 60); /* 上次失败 10 分钟前 < 30 分钟冷却 */
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK && g_refresh_calls == 0, "冷却(10min<30min): 不刷 (calls=%d)", g_refresh_calls);
|
||||
/* 冷却过期(>30min)后再刷 */
|
||||
reset_state(NOW_S - 13 * 3600);
|
||||
g_cfg_fail_ts = (int)(NOW_S - 31 * 60); /* 31 分钟前 > 冷却 */
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK && g_refresh_calls == 1, "冷却过期(31min>30min): 重刷 (calls=%d)", g_refresh_calls);
|
||||
|
||||
/* ⑦ 登录重置:mark_fresh 后年龄=now、冷却清、单飞清 → 不再临期(默认阈值内) */
|
||||
reset_state(NOW_S - 13 * 3600);
|
||||
account_cookie_mark_fresh();
|
||||
g_refresh_calls = 0;
|
||||
rc = account_cookie_maybe_refresh();
|
||||
CHECK(rc == NCM_OK && g_refresh_calls == 0, "登录后 mark_fresh: 视为全新不刷 (calls=%d)", g_refresh_calls);
|
||||
|
||||
printf("\n%s\n", g_fail ? "== RESULT: FAIL ==" : "== RESULT: PASS ==");
|
||||
return g_fail ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/* bench/cookie_refresh_sim.c — MUSIC_U 登录续期端点语义验证(§NEW,0 真实 NCM 请求)。
|
||||
*
|
||||
* 用真实 core(ncm_login.c / ncm_req.c / ncm_crypto.c / ncm_json.c / ncm_common.c),
|
||||
* 仅把网络层换成计数桩(canned eapi set-cookie 响应 / 网络错误),验证 ncm_login_refresh:
|
||||
* ① 成功(code200 + Set-Cookie MUSIC_U/__csrf)→ NCM_OK,新 MUSIC_U patch 进 cookie、
|
||||
* 旧 cookie 其它字段(MUSIC_A/__remember_me)保留(= 新 cookie 替换落盘的合并源);
|
||||
* ② 会话失效(code301)→ NCM_ERR_AUTH(调用方据此退扫码重登);
|
||||
* ③ 网络/TLS 瞬断 → 负错误码(调用方退避,保持旧 cookie);
|
||||
* ④ code200 但无 set-cookie(服务端未轮换)→ NCM_OK,cookie 原样(不损坏)。
|
||||
* 风控纪律:0 次真实 NCM 请求;桩按 mode 切换。
|
||||
|
||||
* 编译(宿主),在 ncm_app 目录:见 build_ncm_sims.sh 新增 cookie_refresh_sim 段。
|
||||
* 运行:./cookie_refresh_sim
|
||||
*/
|
||||
#include "ncm.h"
|
||||
#include "ncm_http.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int g_mode; /* 0=成功+set-cookie; 1=code301; 2=网络错误; 3=code200 无 set-cookie */
|
||||
static int g_http_calls; /* ncm_http_request 桩计数 = 真实网络调用数 */
|
||||
|
||||
static const char *HDR_OK =
|
||||
"Content-Type: application/json\r\n"
|
||||
"Set-Cookie: MUSIC_U=NEWTOKEN123; Path=/; Max-Age=7776000; HttpOnly\r\n"
|
||||
"Set-Cookie: __csrf=newcsrf99; Domain=.music.163.com\r\n";
|
||||
static const char *BODY_OK = "{\"code\":200,\"message\":\"ok\"}";
|
||||
static const char *BODY_AUTH = "{\"code\":301,\"message\":\"需要登录\"}";
|
||||
|
||||
int ncm_http_request(const ncm_http_req_t *req, char *buf, size_t buf_sz, ncm_http_resp_t *resp) {
|
||||
(void)req; (void)buf_sz;
|
||||
g_http_calls++;
|
||||
memset(resp, 0, sizeof *resp);
|
||||
if (g_mode == 2) return NCM_ERR_NET; /* 网络瞬断 */
|
||||
const char *body = (g_mode == 1) ? BODY_AUTH : BODY_OK;
|
||||
size_t bn = strlen(body);
|
||||
memcpy(buf, body, bn);
|
||||
resp->status = 200;
|
||||
resp->body = buf;
|
||||
resp->body_len = bn;
|
||||
resp->content_length = bn;
|
||||
if (g_mode == 0) { /* 带 Set-Cookie 轮换 */
|
||||
size_t hn = strlen(HDR_OK);
|
||||
memcpy(resp->headers, HDR_OK, hn);
|
||||
resp->headers_len = hn;
|
||||
}
|
||||
return NCM_OK;
|
||||
}
|
||||
|
||||
/* 复刻 ncm_http.c 的 set-cookie 提取(解析所有 Set-Cookie 名值,去属性,"; " 连接) */
|
||||
int ncm_http_parse_set_cookie(const char *hdrs, size_t len, char *out, size_t out_sz) {
|
||||
if (!hdrs || !out || out_sz == 0) return -1;
|
||||
out[0] = 0;
|
||||
size_t o = 0;
|
||||
int count = 0;
|
||||
const char *p = hdrs;
|
||||
const char *end = hdrs + len;
|
||||
while ((p = strstr(p, "Set-Cookie:")) != NULL && p < end) {
|
||||
const char *val = p + strlen("Set-Cookie:");
|
||||
while (*val == ' ' || *val == '\t') val++;
|
||||
const char *semi = strchr(val, ';');
|
||||
size_t nlen = semi ? (size_t)(semi - val) : strlen(val);
|
||||
while (nlen && (val[nlen-1]==' '||val[nlen-1]=='\t')) nlen--;
|
||||
if (nlen == 0) { p = val; continue; }
|
||||
if (o > 0) { if (o + 2 >= out_sz) break; out[o++] = ';'; out[o++] = ' '; }
|
||||
if (o + nlen >= out_sz) break;
|
||||
memcpy(out + o, val, nlen);
|
||||
o += nlen;
|
||||
count++;
|
||||
p = val;
|
||||
}
|
||||
out[o] = 0;
|
||||
return count;
|
||||
}
|
||||
void ncm_http_set_verify_default(int verify, const char *ca_path) { (void)verify; (void)ca_path; }
|
||||
|
||||
static int g_fail = 0;
|
||||
#define CHECK(cond, fmt, ...) do { \
|
||||
if (cond) printf(" PASS " fmt "\n", ##__VA_ARGS__); \
|
||||
else { printf(" FAIL " fmt "\n", ##__VA_ARGS__); g_fail = 1; } \
|
||||
} while (0)
|
||||
|
||||
static const char *g_device = "AA11BB22CC33DD44EE55FF6600112233445566778899AABB00";
|
||||
|
||||
int main(void) {
|
||||
/* 基础会话 cookie(MUSIC_U 在中间,__remember_me/MUSIC_A 在后——验证不丢失、不被重排破坏) */
|
||||
static char cookie[NCM_COOKIE_MAX];
|
||||
snprintf(cookie, sizeof cookie,
|
||||
"__csrf=old_csrf; MUSIC_U=OLD_TOKEN_abc_123; MUSIC_A=anon_a; __remember_me=true");
|
||||
char out[NCM_COOKIE_MAX];
|
||||
char v[64];
|
||||
|
||||
puts("== cookie_refresh_sim: ncm_login_refresh endpoint semantics ==");
|
||||
|
||||
/* ① 成功:code200 + Set-Cookie 轮换 → 新 MUSIC_U 覆盖旧值,其余字段保留 */
|
||||
g_mode = 0; g_http_calls = 0;
|
||||
int rc = ncm_login_refresh(g_device, cookie, out, sizeof out);
|
||||
CHECK(rc == NCM_OK, "success rc=0 (got %d)", rc);
|
||||
CHECK(g_http_calls == 1, "exactly 1 http call (got %d)", g_http_calls);
|
||||
CHECK(ncm_req_cookie_get(out, "MUSIC_U", v, sizeof v) == NCM_OK &&
|
||||
strcmp(v, "NEWTOKEN123") == 0, "MUSIC_U replaced with NEWTOKEN123 (got %s)", v);
|
||||
CHECK(ncm_req_cookie_get(out, "__csrf", v, sizeof v) == NCM_OK &&
|
||||
strcmp(v, "newcsrf99") == 0, "__csrf replaced (got %s)", v);
|
||||
CHECK(ncm_req_cookie_get(out, "MUSIC_A", v, sizeof v) == NCM_OK &&
|
||||
strcmp(v, "anon_a") == 0, "MUSIC_A preserved (got %s)", v);
|
||||
CHECK(ncm_req_cookie_get(out, "__remember_me", v, sizeof v) == NCM_OK &&
|
||||
strcmp(v, "true") == 0, "__remember_me preserved (got %s)", v);
|
||||
|
||||
/* ② 会话失效:code301 → NCM_ERR_AUTH(退扫码重登) */
|
||||
g_mode = 1; g_http_calls = 0;
|
||||
rc = ncm_login_refresh(g_device, cookie, out, sizeof out);
|
||||
CHECK(rc == NCM_ERR_AUTH, "auth-fail rc=%d (期望 %d)", rc, NCM_ERR_AUTH);
|
||||
|
||||
/* ③ 网络瞬断 → 负错误码(退避,保持旧 cookie 由调用方保证) */
|
||||
g_mode = 2; g_http_calls = 0;
|
||||
rc = ncm_login_refresh(g_device, cookie, out, sizeof out);
|
||||
CHECK(rc == NCM_ERR_NET, "net-fail rc=%d (期望 %d)", rc, NCM_ERR_NET);
|
||||
|
||||
/* ④ code200 但无 set-cookie(未轮换)→ NCM_OK,cookie 原样(无害) */
|
||||
g_mode = 3; g_http_calls = 0;
|
||||
memset(out, 0, sizeof out);
|
||||
rc = ncm_login_refresh(g_device, cookie, out, sizeof out);
|
||||
CHECK(rc == NCM_OK, "code200-no-cookie rc=0 (got %d)", rc);
|
||||
CHECK(strcmp(out, cookie) == 0, "no-cookie: cookie unchanged");
|
||||
|
||||
/* ⑤ 无 cookie(未登录)→ 参数允许空 body 字段但仍应优雅(eapi 头不注入 MUSIC_U) */
|
||||
g_mode = 3; g_http_calls = 0;
|
||||
rc = ncm_login_refresh(g_device, "", out, sizeof out);
|
||||
CHECK(rc == NCM_OK, "empty-cookie still builds http ok (got %d)", rc);
|
||||
|
||||
printf("\n%s\n", g_fail ? "== RESULT: FAIL ==" : "== RESULT: PASS ==");
|
||||
return g_fail ? 1 : 0;
|
||||
}
|
||||
Reference in new issue
Block a user