Files
SingBox-Gopanel/internal/handler/request_url.go
CN-JS-HuiBai 97f0672729
Some checks failed
build / build (api, amd64, linux) (push) Failing after -50s
build / build (api, arm64, linux) (push) Failing after -51s
build / build (api.exe, amd64, windows) (push) Failing after -51s
修复订阅无法正常获取的错误
2026-04-17 23:07:47 +08:00

148 lines
3.2 KiB
Go

package handler
import (
"net"
"net/http"
"net/url"
"strings"
"xboard-go/internal/service"
"github.com/gin-gonic/gin"
)
func requestBaseURL(c *gin.Context) string {
if c != nil {
if origin := requestOrigin(c.Request); origin != "" {
return origin
}
}
if appURL := service.GetAppURL(); appURL != "" {
return strings.TrimRight(appURL, "/")
}
return ""
}
func requestOrigin(r *http.Request) string {
if r == nil {
return ""
}
scheme, host := forwardedOrigin(r)
if scheme != "" && host != "" {
return scheme + "://" + host
}
if host == "" {
host = firstHeaderValue(r.Header.Get("X-Forwarded-Host"))
}
if host == "" {
host = strings.TrimSpace(r.Host)
}
if host == "" {
host = originHostFallback(r)
}
if host == "" {
return ""
}
if scheme == "" {
scheme = firstHeaderValue(r.Header.Get("X-Forwarded-Proto"))
}
if scheme == "" {
scheme = firstHeaderValue(r.Header.Get("X-Forwarded-Scheme"))
}
if scheme == "" {
scheme = firstHeaderValue(r.Header.Get("X-Scheme"))
}
if scheme == "" && strings.EqualFold(strings.TrimSpace(r.Header.Get("Front-End-Https")), "on") {
scheme = "https"
}
if scheme == "" && strings.EqualFold(strings.TrimSpace(r.Header.Get("X-Forwarded-Ssl")), "on") {
scheme = "https"
}
if scheme == "" {
switch strings.TrimSpace(firstHeaderValue(r.Header.Get("X-Forwarded-Port"))) {
case "443":
scheme = "https"
case "80":
scheme = "http"
}
}
if scheme == "" {
scheme = originSchemeFallback(r)
}
if scheme == "" {
if r.TLS != nil {
scheme = "https"
} else {
scheme = "http"
}
}
if forwardedPort := strings.TrimSpace(firstHeaderValue(r.Header.Get("X-Forwarded-Port"))); forwardedPort != "" && !strings.Contains(host, ":") {
defaultPort := map[string]string{
"http": "80",
"https": "443",
}[scheme]
if forwardedPort != defaultPort {
host = net.JoinHostPort(host, forwardedPort)
}
}
return scheme + "://" + host
}
func forwardedOrigin(r *http.Request) (scheme string, host string) {
forwarded := strings.TrimSpace(firstHeaderValue(r.Header.Get("Forwarded")))
if forwarded == "" {
return "", ""
}
for _, segment := range strings.Split(forwarded, ";") {
parts := strings.SplitN(strings.TrimSpace(segment), "=", 2)
if len(parts) != 2 {
continue
}
key := strings.ToLower(strings.TrimSpace(parts[0]))
value := strings.Trim(strings.TrimSpace(parts[1]), "\"")
switch key {
case "proto":
if value != "" {
scheme = value
}
case "host":
if value != "" {
host = value
}
}
}
return scheme, host
}
func firstHeaderValue(value string) string {
if value == "" {
return ""
}
parts := strings.Split(value, ",")
return strings.TrimSpace(parts[0])
}
func originHostFallback(r *http.Request) string {
for _, raw := range []string{r.Header.Get("Origin"), r.Header.Get("Referer")} {
if parsed, err := url.Parse(strings.TrimSpace(raw)); err == nil && parsed.Host != "" {
return parsed.Host
}
}
return ""
}
func originSchemeFallback(r *http.Request) string {
for _, raw := range []string{r.Header.Get("Origin"), r.Header.Get("Referer")} {
if parsed, err := url.Parse(strings.TrimSpace(raw)); err == nil && parsed.Scheme != "" {
return parsed.Scheme
}
}
return ""
}