Files
AskaEth 074ffc4ebf
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(gateway): gateway 剩余文件注释改中文(逐行 1:1,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批:
已推库 16 个文件 + 本批剩余文件)。
校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0);
全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
2026-10-03 22:28:25 +08:00

74 lines
2.4 KiB
Go
Raw Permalink 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.
package gateway
import (
"net/http"
"strings"
)
// originChecker 允许同源、同 host 以及白名单内的 WebSocket 来源,
// 镜像 CORS 允许列表。"*" 允许全部。
//
// 同 host 放宽:cyrene 提供自己的内嵌前端时(生产
// 模式),页面来源恰好是网关的 Host(例如 http://localhost:10942),
// 它不在开发期的 ALLOWED_ORIGINS 列表中。我们必须放行它,使
// 改过 PORT 的用户不必为了 WS 能连上而编辑 .env。只有真正的
// 跨源客户端(外部 IM / 另一来源上的看板)才会走允许列表。
func originChecker(allowed map[string]bool, allowAll bool) func(*http.Request) bool {
return func(r *http.Request) bool {
origin := r.Header.Get("Origin")
if origin == "" {
return true
}
if allowAll {
return true
}
if allowed[origin] {
return true
}
// 同 host:Origin 与该请求的 Host 匹配(scheme://host:port == host[:port])。
return sameOriginAsHost(origin, r)
}
}
// sameOriginAsHost 报告 origin(完整的 URL 来源串,例如
// "http://localhost:10942")是否对应本请求的 Host 头。它比较
// host[:port] 部分并做回环等价:"localhost" 与 "127.0.0.1"
// (以及 IPv6 形式)被视为同一 host,因此在 127.0.0.1 上提供内嵌
// 前端而客户端经 localhost 连接(或反之)仍然通过。
func sameOriginAsHost(origin string, r *http.Request) bool {
if origin == "" || r == nil {
return false
}
after := origin
if i := strings.Index(after, "://"); i >= 0 {
after = after[i+3:]
}
if i := strings.IndexByte(after, '/'); i >= 0 {
after = after[:i]
}
return hostEquivalent(after, r.Host)
}
// hostEquivalent 比较两个 host[:port] 串,把空端口变体、
// 大小写与回环别名都视为相等。它处理 "localhost" 与 "127.0.0.1"
// 以及带括号的 IPv6 回环 "[::1]"。
func hostEquivalent(a, b string) bool {
na := normalizeHost(a)
nb := normalizeHost(b)
if na == nb {
return true
}
// 回环别名:localhost、127.0.0.1、[::1]
loop := map[string]bool{"localhost": true, "127.0.0.1": true, "[::1]": true, "::1": true, "127.0.0.2": true}
return loop[na] && loop[nb]
}
// normalizeHost 剥掉端口(若有)、转小写并去掉括号。
func normalizeHost(h string) string {
h = strings.ToLower(strings.TrimSpace(h))
if i := strings.LastIndex(h, ":"); i >= 0 && !strings.Contains(h[i:], "]") {
h = h[:i]
}
return strings.TrimPrefix(strings.TrimSuffix(h, "]"), "[")
}