fix(service): normalize user agent for sticky session hashes
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
@@ -34,6 +36,9 @@ var (
|
||||
patternEmptyTextSpaced = []byte(`"text": ""`)
|
||||
patternEmptyTextSp1 = []byte(`"text" : ""`)
|
||||
patternEmptyTextSp2 = []byte(`"text" :""`)
|
||||
|
||||
sessionUserAgentProductPattern = regexp.MustCompile(`([A-Za-z0-9._-]+)/[A-Za-z0-9._-]+`)
|
||||
sessionUserAgentVersionPattern = regexp.MustCompile(`\bv?\d+(?:\.\d+){1,3}\b`)
|
||||
)
|
||||
|
||||
// SessionContext 粘性会话上下文,用于区分不同来源的请求。
|
||||
@@ -75,6 +80,49 @@ type ParsedRequest struct {
|
||||
OnUpstreamAccepted func()
|
||||
}
|
||||
|
||||
// NormalizeSessionUserAgent reduces UA noise for sticky-session and digest hashing.
|
||||
// It preserves the set of product names from Product/Version tokens while
|
||||
// discarding version-only changes and incidental comments.
|
||||
func NormalizeSessionUserAgent(raw string) string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
matches := sessionUserAgentProductPattern.FindAllStringSubmatch(raw, -1)
|
||||
if len(matches) == 0 {
|
||||
return normalizeSessionUserAgentFallback(raw)
|
||||
}
|
||||
|
||||
products := make([]string, 0, len(matches))
|
||||
seen := make(map[string]struct{}, len(matches))
|
||||
for _, match := range matches {
|
||||
if len(match) < 2 {
|
||||
continue
|
||||
}
|
||||
product := strings.ToLower(strings.TrimSpace(match[1]))
|
||||
if product == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[product]; exists {
|
||||
continue
|
||||
}
|
||||
seen[product] = struct{}{}
|
||||
products = append(products, product)
|
||||
}
|
||||
if len(products) == 0 {
|
||||
return normalizeSessionUserAgentFallback(raw)
|
||||
}
|
||||
sort.Strings(products)
|
||||
return strings.Join(products, "+")
|
||||
}
|
||||
|
||||
func normalizeSessionUserAgentFallback(raw string) string {
|
||||
normalized := strings.ToLower(strings.Join(strings.Fields(raw), " "))
|
||||
normalized = sessionUserAgentVersionPattern.ReplaceAllString(normalized, "")
|
||||
return strings.Join(strings.Fields(normalized), " ")
|
||||
}
|
||||
|
||||
// ParseGatewayRequest 解析网关请求体并返回结构化结果。
|
||||
// protocol 指定请求协议格式(domain.PlatformAnthropic / domain.PlatformGemini),
|
||||
// 不同协议使用不同的 system/messages 字段名。
|
||||
|
||||
Reference in New Issue
Block a user