package eh // 回归测试:EH「Content Warning」拦截页(2026-10 线上问题) // // 现象:部分画廊(多被标成 Offensive For Everyone)第一次访问只返回 // 一个 3~4KB 的黄框页 —— 和 meta 都在,但一个 /s/ 链接都没有, // 旧代码因此报「页面结构无法解析(EH 可能又改版)」,纯属误导。 // // 放行方式:请求一次 ?nw=always,EH 会种下 nw=1 Cookie。 // 关键是这个 Cookie 必须被记住,所以 Client 必须带 cookie jar。 import ( "context" "fmt" "net/http" "net/http/httptest" "strings" "testing" "time" ) // warnPage 复刻 EH 的内容警告页(关键特征:没有 /s/ 链接、没有 taglist) func warnPage(gid, token string) string { return fmt.Sprintf(`<!DOCTYPE html><html><head> <title>[Some Circle] Flagged Gallery - E-Hentai Galleries

Content Warning

This gallery has been flagged as Offensive For Everyone.

[View Gallery]

[Never Warn Me Again]

`, EHBase, gid, token, EHBase, gid, token) } // 拦截页 + nw=always 放行(真实行为:带 nw=always 的请求会被种下 nw=1) func TestFetchGalleryPageContentWarningAutoBypass(t *testing.T) { const ( gid = "4166903" tok = "97d35eebb2" ) real := mockGalleryHTML(t, gid, tok, 25)[0] mux := http.NewServeMux() mux.HandleFunc("/g/"+gid+"/"+tok+"/", func(w http.ResponseWriter, r *http.Request) { // 真实 EH:看到 nw=always 就种下 nw=1 Cookie,然后进画廊 if r.URL.Query().Get("nw") == "always" { http.SetCookie(w, &http.Cookie{Name: "nw", Value: "1", Path: "/"}) w.Write([]byte(real)) return } c, err := r.Cookie("nw") if err != nil || c.Value != "1" { w.Write([]byte(warnPage(gid, tok))) // 还没放行 -> 拦截页 return } w.Write([]byte(real)) // 已放行 -> 真正的画廊页 }) srv := httptest.NewServer(mux) defer srv.Close() oldBase := EHBase EHBase = srv.URL defer func() { EHBase = oldBase }() c := NewClient(5*time.Second, "", "off", "auto") defer c.Close() g, err := c.FetchGalleryPage(context.Background(), gid, tok, nil) if err != nil { t.Fatalf("撞到内容警告页应该自动放行,不该失败: %v", err) } if len(g.Pages) == 0 { t.Fatal("自动放行后应至少解析出 1 页") } if len(g.Pages) != 20 { t.Errorf("第 1 屏应解析出 20 页,实际 %d", len(g.Pages)) } t.Logf("自动放行成功,解析出 %d 页(总 %d)", len(g.Pages), g.TotalPages) } // 只在 jar 缺失时才会失败——所以单独锁住「Client 必须带 jar」 func TestClientHasCookieJar(t *testing.T) { c := NewClient(5*time.Second, "", "off", "auto") defer c.Close() if c.httpClient(0).Jar == nil { t.Fatal("http.Client 没有 cookie jar —— EH 的 nw=1 记不住,内容警告页永远过不去") } } // 拦截页里识别不出来时的报错文案,不能再说「EH 可能又改版」了 func TestContentWarningDetection(t *testing.T) { if !isContentWarning(warnPage("1", "aa")) { t.Error("应识别出内容警告页") } if !isContentWarning(`

Content Warning

`) { t.Error("大小写/空白差异也应识别") } if isContentWarning(`thumb`) { t.Error("正常画廊页不该被误判成警告页") } } func TestContentWarningErrorMessage(t *testing.T) { const ( gid = "4999999" tok = "deadbeef01" ) // 永远只返回拦截页:即使放行也拿不到内容 mux := http.NewServeMux() mux.HandleFunc("/g/"+gid+"/"+tok+"/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(warnPage(gid, tok))) }) srv := httptest.NewServer(mux) defer srv.Close() oldBase := EHBase EHBase = srv.URL defer func() { EHBase = oldBase }() c := NewClient(5*time.Second, "", "off", "auto") defer c.Close() _, err := c.FetchGalleryPage(context.Background(), gid, tok, nil) if err == nil { t.Fatal("应当失败") } if !strings.Contains(err.Error(), "Offensive For Everyone") { t.Errorf("报错应说明是内容警告,实际: %v", err) } if strings.Contains(err.Error(), "改版") { t.Errorf("报错不该再提「改版」,那会误导排查: %v", err) } }