// Package variable 提供 nginx 风格的内置变量支持,用于日志、代理和重写规则。 // // 包含 18 个内置变量常量、动态变量获取函数($arg_name、$http_name、$cookie_name) // 以及 Context 池管理。 // // 作者:xfy package variable import ( "strconv" "time" "github.com/google/uuid" "github.com/valyala/fasthttp" "rua.plus/lolly/internal/netutil" ) // 内置变量常量 const ( // VarHost 请求主机名变量。 VarHost = "host" // VarRemoteAddr 客户端地址变量。 VarRemoteAddr = "remote_addr" // VarRemotePort 客户端端口变量。 VarRemotePort = "remote_port" // VarRequestURI 请求 URI 变量。 VarRequestURI = "request_uri" // VarURI URI 变量。 VarURI = "uri" // VarArgs 查询参数变量。 VarArgs = "args" // VarRequestMethod 请求方法变量。 VarRequestMethod = "request_method" // VarScheme 协议方案变量。 VarScheme = "scheme" // VarServerName 服务器名称变量。 VarServerName = "server_name" // VarServerPort 服务器端口变量。 VarServerPort = "server_port" // VarStatus HTTP 状态码变量。 VarStatus = "status" // VarBodyBytesSent 发送字节数变量。 VarBodyBytesSent = "body_bytes_sent" // VarRequestTime 请求处理时间变量。 VarRequestTime = "request_time" // VarTimeLocal 本地时间变量。 VarTimeLocal = "time_local" // VarTimeISO8601 ISO8601 时间变量。 VarTimeISO8601 = "time_iso8601" // VarRequestID 请求 ID 变量。 VarRequestID = "request_id" // 上游变量 // VarUpstreamAddr 上游地址变量。 VarUpstreamAddr = "upstream_addr" // VarUpstreamStatus 上游状态码变量。 VarUpstreamStatus = "upstream_status" // VarUpstreamResponseTime 上游响应时间变量。 VarUpstreamResponseTime = "upstream_response_time" // VarUpstreamConnectTime 上游连接时间变量。 VarUpstreamConnectTime = "upstream_connect_time" // VarUpstreamHeaderTime 上游响应头时间变量。 VarUpstreamHeaderTime = "upstream_header_time" ) // init 注册所有内置变量 func init() { // 1. $host - 请求 Host 头 RegisterBuiltin(&BuiltinVariable{ Name: VarHost, Description: "请求的主机名(Host 头)", Getter: func(ctx *fasthttp.RequestCtx) string { return string(ctx.Host()) }, GetterBytes: func(ctx *fasthttp.RequestCtx) []byte { // SAFETY: ctx.Host() returns []byte valid within request scope return ctx.Host() }, }) // 2. $remote_addr - 客户端 IP RegisterBuiltin(&BuiltinVariable{ Name: VarRemoteAddr, Description: "客户端 IP 地址", Getter: func(ctx *fasthttp.RequestCtx) string { return netutil.FormatRemoteAddr(ctx) }, }) // 3. $remote_port - 客户端端口 RegisterBuiltin(&BuiltinVariable{ Name: VarRemotePort, Description: "客户端端口", Getter: func(ctx *fasthttp.RequestCtx) string { addr := ctx.RemoteAddr() if addr == nil { return "-" } // 解析地址获取端口,优先用 FormatRemoteAddr 缓存的结果 s := netutil.FormatRemoteAddr(ctx) for i := len(s) - 1; i >= 0; i-- { if s[i] == ':' { return s[i+1:] } } return "-" }, }) // 4. $request_uri - 原始请求 URI RegisterBuiltin(&BuiltinVariable{ Name: VarRequestURI, Description: "原始请求 URI(包含查询参数)", Getter: func(ctx *fasthttp.RequestCtx) string { return string(ctx.RequestURI()) }, GetterBytes: func(ctx *fasthttp.RequestCtx) []byte { // SAFETY: ctx.RequestURI() returns []byte valid within request scope return ctx.RequestURI() }, }) // 5. $uri - 解码后的 URI 路径 RegisterBuiltin(&BuiltinVariable{ Name: VarURI, Description: "URI 路径(不包含查询参数)", Getter: func(ctx *fasthttp.RequestCtx) string { return string(ctx.Path()) }, GetterBytes: func(ctx *fasthttp.RequestCtx) []byte { // SAFETY: ctx.Path() returns []byte valid within request scope return ctx.Path() }, }) // 6. $args - 查询参数字符串 RegisterBuiltin(&BuiltinVariable{ Name: VarArgs, Description: "查询参数字符串", Getter: func(ctx *fasthttp.RequestCtx) string { return string(ctx.QueryArgs().QueryString()) }, GetterBytes: func(ctx *fasthttp.RequestCtx) []byte { // SAFETY: ctx.QueryArgs().QueryString() returns []byte valid within request scope return ctx.QueryArgs().QueryString() }, }) // 7. $request_method - 请求方法 RegisterBuiltin(&BuiltinVariable{ Name: VarRequestMethod, Description: "HTTP 请求方法", Getter: func(ctx *fasthttp.RequestCtx) string { return string(ctx.Method()) }, GetterBytes: func(ctx *fasthttp.RequestCtx) []byte { // SAFETY: ctx.Method() returns []byte valid within request scope return ctx.Method() }, }) // 8. $scheme - 协议 RegisterBuiltin(&BuiltinVariable{ Name: VarScheme, Description: "协议(http 或 https)", Getter: func(ctx *fasthttp.RequestCtx) string { if ctx.IsTLS() { return "https" } return "http" }, }) // 9. $server_name - 服务器名称 // 注意:这个变量需要从 Context 获取 RegisterBuiltin(&BuiltinVariable{ Name: VarServerName, Description: "服务器名称", Getter: func(ctx *fasthttp.RequestCtx) string { // 从 UserValue 获取,由外部设置 if v := ctx.UserValue(VarServerName); v != nil { if s, ok := v.(string); ok { return s } } return "-" }, }) // 10. $server_port - 服务器端口 RegisterBuiltin(&BuiltinVariable{ Name: VarServerPort, Description: "服务器端口", Getter: func(ctx *fasthttp.RequestCtx) string { addr := ctx.LocalAddr() if addr == nil { return "-" } s := addr.String() for i := len(s) - 1; i >= 0; i-- { if s[i] == ':' { return s[i+1:] } } return "-" }, }) // 11. $status - HTTP 状态码 // 需要从 Context 获取 RegisterBuiltin(&BuiltinVariable{ Name: VarStatus, Description: "HTTP 响应状态码", Getter: func(ctx *fasthttp.RequestCtx) string { if v := ctx.UserValue(VarStatus); v != nil { if i, ok := v.(int); ok { return strconv.Itoa(i) } } return "-" }, }) // 12. $body_bytes_sent - 响应体大小 // 需要从 Context 获取 RegisterBuiltin(&BuiltinVariable{ Name: VarBodyBytesSent, Description: "发送的响应体字节数", Getter: func(ctx *fasthttp.RequestCtx) string { if v := ctx.UserValue(VarBodyBytesSent); v != nil { if i, ok := v.(int64); ok { return strconv.FormatInt(i, 10) } } return "0" }, }) // 13. $request_time - 请求处理时间 // 需要从 Context 获取 RegisterBuiltin(&BuiltinVariable{ Name: VarRequestTime, Description: "请求处理时间(秒)", Getter: func(ctx *fasthttp.RequestCtx) string { if v := ctx.UserValue(VarRequestTime); v != nil { if i, ok := v.(int64); ok { return formatRequestTime(i) } } return "0.000" }, }) // 14. $time_local - 本地时间 RegisterBuiltin(&BuiltinVariable{ Name: VarTimeLocal, Description: "本地时间(格式:02/Jan/2024:15:04:05 +0800)", Getter: func(_ *fasthttp.RequestCtx) string { return time.Now().Format("02/Jan/2006:15:04:05 -0700") }, }) // 15. $time_iso8601 - ISO8601 时间 RegisterBuiltin(&BuiltinVariable{ Name: VarTimeISO8601, Description: "ISO8601 格式时间", Getter: func(_ *fasthttp.RequestCtx) string { return time.Now().Format(time.RFC3339) }, }) // 16. $request_id - 唯一请求 ID RegisterBuiltin(&BuiltinVariable{ Name: VarRequestID, Description: "唯一请求标识符", Getter: func(ctx *fasthttp.RequestCtx) string { // 先从 UserValue 获取,如果没有则生成并缓存 if v := ctx.UserValue(VarRequestID); v != nil { if s, ok := v.(string); ok { return s } } id := uuid.New().String() ctx.SetUserValue(VarRequestID, id) return id }, }) } // formatRequestTime 格式化请求处理时间 func formatRequestTime(ns int64) string { // 转换为秒,保留3位小数 sec := float64(ns) / 1e9 return strconv.FormatFloat(sec, 'f', 3, 64) } // SetResponseInfoInContext 在 fasthttp.RequestCtx 中设置响应信息 // 用于在 builtin getter 中获取 status、body_bytes_sent、request_time func SetResponseInfoInContext(ctx *fasthttp.RequestCtx, status int, bodySize int64, durationNs int64) { ctx.SetUserValue(VarStatus, status) ctx.SetUserValue(VarBodyBytesSent, bodySize) ctx.SetUserValue(VarRequestTime, durationNs) }