mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-21 18:37:14 +00:00
feat(sub): serve the HTML info page for browser requests on JSON and Clash URLs
Opening the /json or /clash subscription URL in a browser dumped raw JSON/YAML while the base64 URL rendered the info page. Extract the browser-detection and page-rendering branch from subs into maybeServeSubPage and run it first in all three handlers, so every subscription URL shows the same info page in a browser while client apps keep receiving the raw body. Closes #5348
This commit is contained in:
+51
-28
@@ -146,18 +146,54 @@ func (a *SUBController) initRouter(g *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// subs handles HTTP requests for subscription links, returning either HTML page or base64-encoded subscription data.
|
// maybeServeSubPage renders the HTML info page when the request comes from a
|
||||||
func (a *SUBController) subs(c *gin.Context) {
|
// browser (Accept: text/html) or explicitly asks for it (?html=1 or ?view=html).
|
||||||
subId := c.Param("subid")
|
// It reports whether the request was handled. The remark template's per-client
|
||||||
scheme, host, hostWithPort, hostHeader := a.subService.ResolveRequest(c)
|
// info is for the content a client app imports — the raw subscription body. A
|
||||||
subReq := a.subService.ForRequest(host)
|
// browser viewing the HTML info page gets clean, name-only remarks (usage is
|
||||||
// The remark template's per-client info is for the content a client app
|
// shown in the page summary).
|
||||||
// imports — the raw subscription body. A browser viewing the HTML info page
|
func (a *SUBController) maybeServeSubPage(c *gin.Context) bool {
|
||||||
// gets clean, name-only remarks (usage is shown in the page summary).
|
|
||||||
accept := c.GetHeader("Accept")
|
accept := c.GetHeader("Accept")
|
||||||
wantsHTML := strings.Contains(strings.ToLower(accept), "text/html") || c.Query("html") == "1" || strings.EqualFold(c.Query("view"), "html")
|
wantsHTML := strings.Contains(strings.ToLower(accept), "text/html") || c.Query("html") == "1" || strings.EqualFold(c.Query("view"), "html")
|
||||||
subReq.subscriptionBody = !wantsHTML
|
if !wantsHTML {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
subId := c.Param("subid")
|
||||||
|
_, host, _, hostHeader := a.subService.ResolveRequest(c)
|
||||||
|
subReq := a.subService.ForRequest(host)
|
||||||
|
subReq.subscriptionBody = false
|
||||||
subs, emails, lastOnline, traffic, err := subReq.getSubs(subId)
|
subs, emails, lastOnline, traffic, err := subReq.getSubs(subId)
|
||||||
|
if err != nil || len(subs) == 0 {
|
||||||
|
writeSubError(c, err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
subURL, subJsonURL, subClashURL := subReq.BuildURLs(a.subPath, a.subJsonPath, a.subClashPath, subId)
|
||||||
|
if !a.jsonEnabled {
|
||||||
|
subJsonURL = ""
|
||||||
|
}
|
||||||
|
if !a.clashEnabled {
|
||||||
|
subClashURL = ""
|
||||||
|
}
|
||||||
|
basePath, exists := c.Get("base_path")
|
||||||
|
if !exists {
|
||||||
|
basePath = "/"
|
||||||
|
}
|
||||||
|
basePathStr := basePath.(string)
|
||||||
|
page := subReq.BuildPageData(subId, hostHeader, traffic, lastOnline, subs, emails, subURL, subJsonURL, subClashURL, basePathStr, a.subTitle, a.subSupportUrl)
|
||||||
|
a.serveSubPage(c, basePathStr, page)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// subs handles HTTP requests for subscription links, returning either HTML page or base64-encoded subscription data.
|
||||||
|
func (a *SUBController) subs(c *gin.Context) {
|
||||||
|
if a.maybeServeSubPage(c) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subId := c.Param("subid")
|
||||||
|
scheme, host, hostWithPort, _ := a.subService.ResolveRequest(c)
|
||||||
|
subReq := a.subService.ForRequest(host)
|
||||||
|
subReq.subscriptionBody = true
|
||||||
|
subs, _, _, traffic, err := subReq.getSubs(subId)
|
||||||
if err != nil || len(subs) == 0 {
|
if err != nil || len(subs) == 0 {
|
||||||
writeSubError(c, err)
|
writeSubError(c, err)
|
||||||
} else {
|
} else {
|
||||||
@@ -167,25 +203,6 @@ func (a *SUBController) subs(c *gin.Context) {
|
|||||||
result.WriteString("\n")
|
result.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the request expects HTML (e.g., browser) or explicitly asked (?html=1 or ?view=html), render the info page here
|
|
||||||
if wantsHTML {
|
|
||||||
subURL, subJsonURL, subClashURL := subReq.BuildURLs(a.subPath, a.subJsonPath, a.subClashPath, subId)
|
|
||||||
if !a.jsonEnabled {
|
|
||||||
subJsonURL = ""
|
|
||||||
}
|
|
||||||
if !a.clashEnabled {
|
|
||||||
subClashURL = ""
|
|
||||||
}
|
|
||||||
basePath, exists := c.Get("base_path")
|
|
||||||
if !exists {
|
|
||||||
basePath = "/"
|
|
||||||
}
|
|
||||||
basePathStr := basePath.(string)
|
|
||||||
page := subReq.BuildPageData(subId, hostHeader, traffic, lastOnline, subs, emails, subURL, subJsonURL, subClashURL, basePathStr, a.subTitle, a.subSupportUrl)
|
|
||||||
a.serveSubPage(c, basePathStr, page)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add headers
|
// Add headers
|
||||||
header := fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
|
header := fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000)
|
||||||
profileUrl := a.subProfileUrl
|
profileUrl := a.subProfileUrl
|
||||||
@@ -366,6 +383,9 @@ func (a *SUBController) loadSubTemplate(themeDir string) (*template.Template, er
|
|||||||
|
|
||||||
// subJsons handles HTTP requests for JSON subscription configurations.
|
// subJsons handles HTTP requests for JSON subscription configurations.
|
||||||
func (a *SUBController) subJsons(c *gin.Context) {
|
func (a *SUBController) subJsons(c *gin.Context) {
|
||||||
|
if a.maybeServeSubPage(c) {
|
||||||
|
return
|
||||||
|
}
|
||||||
subId := c.Param("subid")
|
subId := c.Param("subid")
|
||||||
scheme, host, hostWithPort, _ := a.subService.ResolveRequest(c)
|
scheme, host, hostWithPort, _ := a.subService.ResolveRequest(c)
|
||||||
jsonSub, header, err := a.subJsonService.GetJson(subId, host)
|
jsonSub, header, err := a.subJsonService.GetJson(subId, host)
|
||||||
@@ -383,6 +403,9 @@ func (a *SUBController) subJsons(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *SUBController) subClashs(c *gin.Context) {
|
func (a *SUBController) subClashs(c *gin.Context) {
|
||||||
|
if a.maybeServeSubPage(c) {
|
||||||
|
return
|
||||||
|
}
|
||||||
subId := c.Param("subid")
|
subId := c.Param("subid")
|
||||||
scheme, host, hostWithPort, _ := a.subService.ResolveRequest(c)
|
scheme, host, hostWithPort, _ := a.subService.ResolveRequest(c)
|
||||||
clashSub, header, err := a.subClashService.GetClash(subId, host)
|
clashSub, header, err := a.subClashService.GetClash(subId, host)
|
||||||
|
|||||||
Reference in New Issue
Block a user