mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-10 05:20:28 +00:00
chore: introduce HTMLBuilder (#37688)
This commit is contained in:
@@ -83,3 +83,34 @@ func HTMLPrintTag(w io.Writer, tag template.HTML, attrs map[string]string) (writ
|
|||||||
written += n
|
written += n
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EscapeString(s string) template.HTML {
|
||||||
|
return template.HTML(template.HTMLEscapeString(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTMLBuilder struct {
|
||||||
|
sb strings.Builder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *HTMLBuilder) WriteString(s string) *HTMLBuilder {
|
||||||
|
b.sb.WriteString(template.HTMLEscapeString(s))
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *HTMLBuilder) WriteHTML(s template.HTML) *HTMLBuilder {
|
||||||
|
b.sb.WriteString(string(s))
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *HTMLBuilder) WriteFormat(fmt template.HTML, args ...any) *HTMLBuilder {
|
||||||
|
_, _ = HTMLPrintf(&b.sb, fmt, args...)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *HTMLBuilder) HTMLString() template.HTML {
|
||||||
|
return template.HTML(b.sb.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *HTMLBuilder) String() string {
|
||||||
|
return b.sb.String()
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,3 +22,10 @@ func TestHTMLFormat(t *testing.T) {
|
|||||||
assert.Equal(t, template.HTML("<>"), HTMLFormat("%s", template.URL("<>")))
|
assert.Equal(t, template.HTML("<>"), HTMLFormat("%s", template.URL("<>")))
|
||||||
assert.Equal(t, template.HTML("&StringMethod &StringMethod"), HTMLFormat("%s %s", testStringer{}, &testStringer{}))
|
assert.Equal(t, template.HTML("&StringMethod &StringMethod"), HTMLFormat("%s %s", testStringer{}, &testStringer{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTMLBuilder(t *testing.T) {
|
||||||
|
b := &HTMLBuilder{}
|
||||||
|
b.WriteString("<").WriteHTML("<hr>").WriteFormat("<span>%s%s</span>", ">", EscapeString(">"))
|
||||||
|
assert.Equal(t, "<<hr><span>>></span>", b.String())
|
||||||
|
assert.Equal(t, template.HTML("<<hr><span>>></span>"), b.HTMLString())
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ func (r *RenderInternal) ProtectSafeAttrs(content template.HTML) template.HTML {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RenderInternal) FormatWithSafeAttrs(w io.Writer, fmt template.HTML, a ...any) error {
|
func (r *RenderInternal) FormatWithSafeAttrs(w io.Writer, fmt template.HTML, a ...any) error {
|
||||||
_, err := w.Write([]byte(r.ProtectSafeAttrs(htmlutil.HTMLFormat(fmt, a...))))
|
htmlStr := r.ProtectSafeAttrs(htmlutil.HTMLFormat(fmt, a...))
|
||||||
|
_, err := io.WriteString(w, string(htmlStr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,31 +106,27 @@ func (r *orgWriter) resolveLink(link string) string {
|
|||||||
// WriteRegularLink renders images, links or videos
|
// WriteRegularLink renders images, links or videos
|
||||||
func (r *orgWriter) WriteRegularLink(l org.RegularLink) {
|
func (r *orgWriter) WriteRegularLink(l org.RegularLink) {
|
||||||
link := r.resolveLink(l.URL)
|
link := r.resolveLink(l.URL)
|
||||||
|
|
||||||
printHTML := func(html template.HTML, a ...any) {
|
|
||||||
_, _ = fmt.Fprint(r, htmlutil.HTMLFormat(html, a...))
|
|
||||||
}
|
|
||||||
// Inspired by https://github.com/niklasfasching/go-org/blob/6eb20dbda93cb88c3503f7508dc78cbbc639378f/org/html_writer.go#L406-L427
|
// Inspired by https://github.com/niklasfasching/go-org/blob/6eb20dbda93cb88c3503f7508dc78cbbc639378f/org/html_writer.go#L406-L427
|
||||||
switch l.Kind() {
|
switch l.Kind() {
|
||||||
case "image":
|
case "image":
|
||||||
if l.Description == nil {
|
if l.Description == nil {
|
||||||
printHTML(`<img src="%s" alt="%s">`, link, link)
|
_, _ = htmlutil.HTMLPrintf(r, `<img src="%s" alt="%s">`, link, link)
|
||||||
} else {
|
} else {
|
||||||
imageSrc := r.resolveLink(org.String(l.Description...))
|
imageSrc := r.resolveLink(org.String(l.Description...))
|
||||||
printHTML(`<a href="%s"><img src="%s" alt="%s"></a>`, link, imageSrc, imageSrc)
|
_, _ = htmlutil.HTMLPrintf(r, `<a href="%s"><img src="%s" alt="%s"></a>`, link, imageSrc, imageSrc)
|
||||||
}
|
}
|
||||||
case "video":
|
case "video":
|
||||||
if l.Description == nil {
|
if l.Description == nil {
|
||||||
printHTML(`<video src="%s">%s</video>`, link, link)
|
_, _ = htmlutil.HTMLPrintf(r, `<video src="%s">%s</video>`, link, link)
|
||||||
} else {
|
} else {
|
||||||
videoSrc := r.resolveLink(org.String(l.Description...))
|
videoSrc := r.resolveLink(org.String(l.Description...))
|
||||||
printHTML(`<a href="%s"><video src="%s">%s</video></a>`, link, videoSrc, videoSrc)
|
_, _ = htmlutil.HTMLPrintf(r, `<a href="%s"><video src="%s">%s</video></a>`, link, videoSrc, videoSrc)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
var description any = link
|
var description any = link
|
||||||
if l.Description != nil {
|
if l.Description != nil {
|
||||||
description = template.HTML(r.WriteNodesAsString(l.Description...)) // orgmode HTMLWriter outputs HTML content
|
description = template.HTML(r.WriteNodesAsString(l.Description...)) // orgmode HTMLWriter outputs HTML content
|
||||||
}
|
}
|
||||||
printHTML(`<a href="%s">%s</a>`, link, description)
|
_, _ = htmlutil.HTMLPrintf(r, `<a href="%s">%s</a>`, link, description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ func (r *Router) normalizeRequestPath(resp http.ResponseWriter, req *http.Reques
|
|||||||
// do not respond to other requests, to simulate a real sub-path environment
|
// do not respond to other requests, to simulate a real sub-path environment
|
||||||
resp.Header().Add("Content-Type", "text/html; charset=utf-8")
|
resp.Header().Add("Content-Type", "text/html; charset=utf-8")
|
||||||
resp.WriteHeader(http.StatusNotFound)
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
_, _ = resp.Write([]byte(htmlutil.HTMLFormat(`404 page not found, sub-path is: <a href="%s">%s</a>`, setting.AppSubURL, setting.AppSubURL)))
|
_, _ = htmlutil.HTMLPrintf(resp, `404 page not found, sub-path is: <a href="%s">%s</a>`, setting.AppSubURL, setting.AppSubURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
normalized = true
|
normalized = true
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ func handleRepoViewSubmodule(ctx *context.Context, commitSubmoduleFile *git.Comm
|
|||||||
redirectLink := submoduleWebLink.CommitWebLink
|
redirectLink := submoduleWebLink.CommitWebLink
|
||||||
if isViewHomeOnlyContent(ctx) {
|
if isViewHomeOnlyContent(ctx) {
|
||||||
ctx.Resp.Header().Set("Content-Type", "text/html; charset=utf-8")
|
ctx.Resp.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
_, _ = ctx.Resp.Write([]byte(htmlutil.HTMLFormat(`<a href="%s">%s</a>`, redirectLink, redirectLink)))
|
_, _ = htmlutil.HTMLPrintf(ctx.Resp, `<a href="%s">%s</a>`, redirectLink, redirectLink)
|
||||||
} else if !httplib.IsCurrentGiteaSiteURL(ctx, redirectLink) {
|
} else if !httplib.IsCurrentGiteaSiteURL(ctx, redirectLink) {
|
||||||
// don't auto-redirect to external URL, to avoid open redirect or phishing
|
// don't auto-redirect to external URL, to avoid open redirect or phishing
|
||||||
ctx.Data["NotFoundPrompt"] = redirectLink
|
ctx.Data["NotFoundPrompt"] = redirectLink
|
||||||
|
|||||||
Reference in New Issue
Block a user