mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Fix performance problems related link labels
This commit is contained in:
parent
5ba3327fda
commit
be2bf82af9
2 changed files with 47 additions and 0 deletions
|
|
@ -2,7 +2,9 @@ package goldmark_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
. "github.com/yuin/goldmark"
|
. "github.com/yuin/goldmark"
|
||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
|
|
@ -85,3 +87,21 @@ func TestAutogeneratedIDs(t *testing.T) {
|
||||||
t.Errorf("%s\n---------\n%s", source, b.String())
|
t.Errorf("%s\n---------\n%s", source, b.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeepNestedLabelPerformance(t *testing.T) {
|
||||||
|
markdown := New(WithRendererOptions(
|
||||||
|
html.WithXHTML(),
|
||||||
|
html.WithUnsafe(),
|
||||||
|
))
|
||||||
|
|
||||||
|
started := time.Now().UnixMilli()
|
||||||
|
n := 50000
|
||||||
|
source := []byte(strings.Repeat("[", n) + strings.Repeat("]", n))
|
||||||
|
var b bytes.Buffer
|
||||||
|
_ = markdown.Convert(source, &b)
|
||||||
|
finished := time.Now().UnixMilli()
|
||||||
|
println(finished - started)
|
||||||
|
if (finished - started) > 3000 {
|
||||||
|
t.Error("Parsing deep nested labels took more 3 secs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,13 @@ func (s *linkLabelState) Kind() ast.NodeKind {
|
||||||
return kindLinkLabelState
|
return kindLinkLabelState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func linkLabelStateLength(v *linkLabelState) int {
|
||||||
|
if v == nil || v.Last == nil || v.First == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return v.Last.Segment.Stop - v.First.Segment.Start
|
||||||
|
}
|
||||||
|
|
||||||
func pushLinkLabelState(pc Context, v *linkLabelState) {
|
func pushLinkLabelState(pc Context, v *linkLabelState) {
|
||||||
tlist := pc.Get(linkLabelStateKey)
|
tlist := pc.Get(linkLabelStateKey)
|
||||||
var list *linkLabelState
|
var list *linkLabelState
|
||||||
|
|
@ -140,6 +147,13 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
|
||||||
}
|
}
|
||||||
block.Advance(1)
|
block.Advance(1)
|
||||||
removeLinkLabelState(pc, last)
|
removeLinkLabelState(pc, last)
|
||||||
|
// CommonMark spec says:
|
||||||
|
// > A link label can have at most 999 characters inside the square brackets.
|
||||||
|
if linkLabelStateLength(tlist.(*linkLabelState)) > 998 {
|
||||||
|
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if !last.IsImage && s.containsLink(last) { // a link in a link text is not allowed
|
if !last.IsImage && s.containsLink(last) { // a link in a link text is not allowed
|
||||||
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
|
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -164,6 +178,13 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
|
||||||
block.SetPosition(l, pos)
|
block.SetPosition(l, pos)
|
||||||
ssegment := text.NewSegment(last.Segment.Stop, segment.Start)
|
ssegment := text.NewSegment(last.Segment.Stop, segment.Start)
|
||||||
maybeReference := block.Value(ssegment)
|
maybeReference := block.Value(ssegment)
|
||||||
|
// CommonMark spec says:
|
||||||
|
// > A link label can have at most 999 characters inside the square brackets.
|
||||||
|
if len(maybeReference) > 999 {
|
||||||
|
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
|
ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
|
||||||
if !ok {
|
if !ok {
|
||||||
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
|
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
|
||||||
|
|
@ -251,6 +272,11 @@ func (s *linkParser) parseReferenceLink(parent ast.Node, last *linkLabelState, b
|
||||||
s := text.NewSegment(last.Segment.Stop, orgpos.Start-1)
|
s := text.NewSegment(last.Segment.Stop, orgpos.Start-1)
|
||||||
maybeReference = block.Value(s)
|
maybeReference = block.Value(s)
|
||||||
}
|
}
|
||||||
|
// CommonMark spec says:
|
||||||
|
// > A link label can have at most 999 characters inside the square brackets.
|
||||||
|
if len(maybeReference) > 999 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
|
ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -369,6 +395,7 @@ func parseLinkTitle(block text.Reader) ([]byte, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *linkParser) CloseBlock(parent ast.Node, block text.Reader, pc Context) {
|
func (s *linkParser) CloseBlock(parent ast.Node, block text.Reader, pc Context) {
|
||||||
|
pc.Set(linkBottom, nil)
|
||||||
tlist := pc.Get(linkLabelStateKey)
|
tlist := pc.Get(linkLabelStateKey)
|
||||||
if tlist == nil {
|
if tlist == nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue