fix: remove unsupported regexp backreferences causing panic
Build and Push to GHCR / build-and-push (push) Has been cancelled

Go's regexp package uses RE2 syntax which does not support \1, \2
backreferences. Replace the regex-based refresh/CSS URL rewriting
with plain string scanning to avoid the init() panic.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <[email protected]>
This commit is contained in:
Agent
2026-05-24 19:26:13 +08:00
co-authored by HAPI
parent c1a1c06551
commit 163e625495
+96 -24
View File
@@ -2,7 +2,6 @@ package proxy
import (
"bytes"
"regexp"
"strings"
"golang.org/x/net/html"
@@ -93,37 +92,110 @@ func isRefreshMeta(n *html.Node) bool {
return false
}
var refreshURLRe = regexp.MustCompile(`(?i)(url\s*=\s*)(["']?)(/[^"'>\s;]*)\2`)
// rewriteRefreshContent rewrites URLs inside meta refresh content,
// e.g. "0;url=/path" -> "0;url={prefix}/path"
func rewriteRefreshContent(content, prefix string) string {
return refreshURLRe.ReplaceAllStringFunc(content, func(m string) string {
matches := refreshURLRe.FindStringSubmatch(m)
if len(matches) < 5 {
return m
for _, pat := range []string{"url=\"", "url='", "url="} {
idx := strings.Index(content, pat)
if idx == -1 {
continue
}
urlPart := matches[3]
start := idx + len(pat)
quote := ""
if pat == "url=\"" {
quote = "\""
} else if pat == "url='" {
quote = "'"
}
end := len(content)
if quote != "" {
if q := strings.Index(content[start:], quote); q != -1 {
end = start + q
}
} else {
for i := start; i < len(content); i++ {
if content[i] == ' ' || content[i] == ';' || content[i] == '"' || content[i] == '\'' {
end = i
break
}
}
}
urlPart := content[start:end]
rewritten := rewriteURL(urlPart, prefix)
if rewritten == urlPart {
return m
if rewritten != urlPart {
return content[:start] + rewritten + content[end:]
}
return matches[1] + matches[2] + rewritten + matches[2]
})
}
return content
}
// cssURLRe matches url(/path), url("/path"), url('/path').
var cssURLRe = regexp.MustCompile(`(?i)(url\s*\(\s*)(["']?)(/[^"')\s]*)\2(\s*\))`)
// rewriteCSSURLs rewrites url(/path) inside CSS text.
func rewriteCSSURLs(css, prefix string) string {
return cssURLRe.ReplaceAllStringFunc(css, func(m string) string {
matches := cssURLRe.FindStringSubmatch(m)
if len(matches) < 5 {
return m
var result strings.Builder
i := 0
for i < len(css) {
idx := strings.Index(css[i:], "url(")
if idx == -1 {
result.WriteString(css[i:])
break
}
urlPart := matches[3]
idx += i
result.WriteString(css[i:idx])
start := idx + 4 // after "url("
// skip whitespace
for start < len(css) && (css[start] == ' ' || css[start] == '\t' || css[start] == '\n') {
start++
}
if start >= len(css) {
result.WriteString(css[idx:])
break
}
quote := ""
if css[start] == '"' || css[start] == '\'' {
quote = string(css[start])
start++
}
urlStart := start
urlEnd := len(css)
if quote != "" {
if q := strings.Index(css[start:], quote); q != -1 {
urlEnd = start + q
}
} else {
for j := start; j < len(css); j++ {
if css[j] == ')' || css[j] == ' ' || css[j] == '\t' || css[j] == '\n' {
urlEnd = j
break
}
}
}
urlPart := css[urlStart:urlEnd]
rewritten := rewriteURL(urlPart, prefix)
if rewritten == urlPart {
return m
result.WriteString("url(")
if quote != "" {
result.WriteString(quote)
}
return matches[1] + matches[2] + rewritten + matches[2] + matches[4]
})
result.WriteString(rewritten)
if quote != "" {
result.WriteString(quote)
}
// find closing ')'
i = urlEnd
if quote != "" {
i++ // skip closing quote
}
for i < len(css) && (css[i] == ' ' || css[i] == '\t' || css[i] == '\n') {
i++
}
if i < len(css) && css[i] == ')' {
i++
}
}
return result.String()
}