Skip to content

Commit ae49559

Browse files
6543zeripath
andauthored
Fix panic bug in handling multiple references in commit (go-gitea#13486) (go-gitea#13487)
* Fix panic bug in handling multiple references in commit (go-gitea#13486) The issue lay in determining the position of matches on a second run round a commit message in FindAllIssueReferences. Fix go-gitea#13483 Signed-off-by: Andrew Thornton <[email protected]> * CI.restart() Co-authored-by: Andrew Thornton <[email protected]>
1 parent 1e446bb commit ae49559

File tree

2 files changed

+95
-29
lines changed

2 files changed

+95
-29
lines changed

modules/references/references.go

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -235,40 +235,78 @@ func findAllIssueReferencesMarkdown(content string) []*rawReference {
235235
return findAllIssueReferencesBytes(bcontent, links)
236236
}
237237

238+
func convertFullHTMLReferencesToShortRefs(re *regexp.Regexp, contentBytes *[]byte) {
239+
// We will iterate through the content, rewrite and simplify full references.
240+
//
241+
// We want to transform something like:
242+
//
243+
// this is a https://ourgitea.com/git/owner/repo/issues/123456789, foo
244+
// https://ourgitea.com/git/owner/repo/pulls/123456789
245+
//
246+
// Into something like:
247+
//
248+
// this is a #123456789, foo
249+
// !123456789
250+
251+
pos := 0
252+
for {
253+
// re looks for something like: (\s|^|\(|\[)https://ourgitea.com/git/(owner/repo)/(issues)/(123456789)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)
254+
match := re.FindSubmatchIndex((*contentBytes)[pos:])
255+
if match == nil {
256+
break
257+
}
258+
// match is a bunch of indices into the content from pos onwards so
259+
// to simplify things let's just add pos to all of the indices in match
260+
for i := range match {
261+
match[i] += pos
262+
}
263+
264+
// match[0]-match[1] is whole string
265+
// match[2]-match[3] is preamble
266+
267+
// move the position to the end of the preamble
268+
pos = match[3]
269+
270+
// match[4]-match[5] is owner/repo
271+
// now copy the owner/repo to end of the preamble
272+
endPos := pos + match[5] - match[4]
273+
copy((*contentBytes)[pos:endPos], (*contentBytes)[match[4]:match[5]])
274+
275+
// move the current position to the end of the newly copied owner/repo
276+
pos = endPos
277+
278+
// Now set the issue/pull marker:
279+
//
280+
// match[6]-match[7] == 'issues'
281+
(*contentBytes)[pos] = '#'
282+
if string((*contentBytes)[match[6]:match[7]]) == "pulls" {
283+
(*contentBytes)[pos] = '!'
284+
}
285+
pos++
286+
287+
// Then add the issue/pull number
288+
//
289+
// match[8]-match[9] is the number
290+
endPos = pos + match[9] - match[8]
291+
copy((*contentBytes)[pos:endPos], (*contentBytes)[match[8]:match[9]])
292+
293+
// Now copy what's left at the end of the string to the new end position
294+
copy((*contentBytes)[endPos:], (*contentBytes)[match[9]:])
295+
// now we reset the length
296+
297+
// our new section has length endPos - match[3]
298+
// our old section has length match[9] - match[3]
299+
(*contentBytes) = (*contentBytes)[:len((*contentBytes))-match[9]+endPos]
300+
pos = endPos
301+
}
302+
}
303+
238304
// FindAllIssueReferences returns a list of unvalidated references found in a string.
239305
func FindAllIssueReferences(content string) []IssueReference {
240306
// Need to convert fully qualified html references to local system to #/! short codes
241307
contentBytes := []byte(content)
242308
if re := getGiteaIssuePullPattern(); re != nil {
243-
pos := 0
244-
for {
245-
match := re.FindSubmatchIndex(contentBytes[pos:])
246-
if match == nil {
247-
break
248-
}
249-
// match[0]-match[1] is whole string
250-
// match[2]-match[3] is preamble
251-
pos += match[3]
252-
// match[4]-match[5] is owner/repo
253-
endPos := pos + match[5] - match[4]
254-
copy(contentBytes[pos:endPos], contentBytes[match[4]:match[5]])
255-
pos = endPos
256-
// match[6]-match[7] == 'issues'
257-
contentBytes[pos] = '#'
258-
if string(contentBytes[match[6]:match[7]]) == "pulls" {
259-
contentBytes[pos] = '!'
260-
}
261-
pos++
262-
// match[8]-match[9] is the number
263-
endPos = pos + match[9] - match[8]
264-
copy(contentBytes[pos:endPos], contentBytes[match[8]:match[9]])
265-
copy(contentBytes[endPos:], contentBytes[match[9]:])
266-
// now we reset the length
267-
// our new section has length endPos - match[3]
268-
// our old section has length match[9] - match[3]
269-
contentBytes = contentBytes[:len(contentBytes)-match[9]+endPos]
270-
pos = endPos
271-
}
309+
convertFullHTMLReferencesToShortRefs(re, &contentBytes)
272310
} else {
273311
log.Debug("No GiteaIssuePullPattern pattern")
274312
}

modules/references/references_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package references
66

77
import (
8+
"regexp"
89
"testing"
910

1011
"code.gitea.io/gitea/modules/setting"
@@ -29,6 +30,26 @@ type testResult struct {
2930
TimeLog string
3031
}
3132

33+
func TestConvertFullHTMLReferencesToShortRefs(t *testing.T) {
34+
re := regexp.MustCompile(`(\s|^|\(|\[)` +
35+
regexp.QuoteMeta("https://ourgitea.com/git/") +
36+
`([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+)/` +
37+
`((?:issues)|(?:pulls))/([0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
38+
test := `this is a https://ourgitea.com/git/owner/repo/issues/123456789, foo
39+
https://ourgitea.com/git/owner/repo/pulls/123456789
40+
And https://ourgitea.com/git/owner/repo/pulls/123
41+
`
42+
expect := `this is a owner/repo#123456789, foo
43+
owner/repo!123456789
44+
And owner/repo!123
45+
`
46+
47+
contentBytes := []byte(test)
48+
convertFullHTMLReferencesToShortRefs(re, &contentBytes)
49+
result := string(contentBytes)
50+
assert.EqualValues(t, expect, result)
51+
}
52+
3253
func TestFindAllIssueReferences(t *testing.T) {
3354

3455
fixtures := []testFixture{
@@ -106,6 +127,13 @@ func TestFindAllIssueReferences(t *testing.T) {
106127
{202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""},
107128
},
108129
},
130+
{
131+
"This http://gitea.com:3000/user4/repo5/pulls/202 yes. http://gitea.com:3000/user4/repo5/pulls/203 no",
132+
[]testResult{
133+
{202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""},
134+
{203, "user4", "repo5", "203", true, XRefActionNone, nil, nil, ""},
135+
},
136+
},
109137
{
110138
"This http://GiTeA.COM:3000/user4/repo6/pulls/205 yes.",
111139
[]testResult{

0 commit comments

Comments
 (0)