mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-22 20:53:40 +09:00
fix: avoid markup render panic (#38698)
fix #38697 The root problem is that "commitChecker.repo" can be nil when the render is called without a real repo.
This commit is contained in:
@@ -13,35 +13,38 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type commitChecker struct {
|
type commitChecker struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
commitCache map[string]bool
|
commitCache map[string]bool
|
||||||
repo *repo_model.Repository
|
repoOptional *repo_model.Repository
|
||||||
|
|
||||||
gitRepo *git.Repository
|
gitRepo *git.Repository
|
||||||
gitRepoCloser io.Closer
|
gitRepoCloser io.Closer
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCommitChecker(ctx context.Context, repo *repo_model.Repository) *commitChecker {
|
func newCommitChecker(ctx context.Context, repo *repo_model.Repository) *commitChecker {
|
||||||
return &commitChecker{ctx: ctx, commitCache: make(map[string]bool), repo: repo}
|
return &commitChecker{ctx: ctx, commitCache: make(map[string]bool), repoOptional: repo}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commitChecker) Close() error {
|
func (c *commitChecker) Close() error {
|
||||||
if c != nil && c.gitRepoCloser != nil {
|
if c.gitRepoCloser != nil {
|
||||||
return c.gitRepoCloser.Close()
|
return c.gitRepoCloser.Close()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commitChecker) IsCommitIDExisting(commitID string) bool {
|
func (c *commitChecker) IsCommitIDExisting(commitID string) bool {
|
||||||
|
if c.repoOptional == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
exist, inCache := c.commitCache[commitID]
|
exist, inCache := c.commitCache[commitID]
|
||||||
if inCache {
|
if inCache {
|
||||||
return exist
|
return exist
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.gitRepo == nil {
|
if c.gitRepo == nil {
|
||||||
r, closer, err := git.RepositoryFromContextOrOpen(c.ctx, c.repo)
|
r, closer, err := git.RepositoryFromContextOrOpen(c.ctx, c.repoOptional)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to open repository: %s, error: %v", c.repo.FullName(), err)
|
log.Error("Unable to open repository: %s, error: %v", c.repoOptional.FullName(), err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
c.gitRepo, c.gitRepoCloser = r, closer
|
c.gitRepo, c.gitRepoCloser = r, closer
|
||||||
|
|||||||
@@ -51,10 +51,10 @@ func NewRenderContextRepoComment(ctx context.Context, repo *repo_model.Repositor
|
|||||||
helper := &RepoComment{opts: util.OptionalArg(opts)}
|
helper := &RepoComment{opts: util.OptionalArg(opts)}
|
||||||
rctx := markup.NewRenderContext(ctx)
|
rctx := markup.NewRenderContext(ctx)
|
||||||
helper.ctx = rctx
|
helper.ctx = rctx
|
||||||
|
helper.commitChecker = newCommitChecker(ctx, repo)
|
||||||
var metas map[string]string
|
var metas map[string]string
|
||||||
if repo != nil {
|
if repo != nil {
|
||||||
helper.repoLink = repo.Link()
|
helper.repoLink = repo.Link()
|
||||||
helper.commitChecker = newCommitChecker(ctx, repo)
|
|
||||||
metas = repo.ComposeCommentMetas(ctx)
|
metas = repo.ComposeCommentMetas(ctx)
|
||||||
} else {
|
} else {
|
||||||
// repo can be nil when rendering a commit message in user's dashboard feedback whose repository has been deleted
|
// repo can be nil when rendering a commit message in user's dashboard feedback whose repository has been deleted
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ func NewRenderContextRepoFile(ctx context.Context, repo *repo_model.Repository,
|
|||||||
helper := &RepoFile{opts: util.OptionalArg(opts)}
|
helper := &RepoFile{opts: util.OptionalArg(opts)}
|
||||||
rctx := markup.NewRenderContext(ctx)
|
rctx := markup.NewRenderContext(ctx)
|
||||||
helper.ctx = rctx
|
helper.ctx = rctx
|
||||||
|
helper.commitChecker = newCommitChecker(ctx, repo)
|
||||||
if repo != nil {
|
if repo != nil {
|
||||||
helper.repoLink = repo.Link()
|
helper.repoLink = repo.Link()
|
||||||
helper.commitChecker = newCommitChecker(ctx, repo)
|
|
||||||
rctx = rctx.WithMetas(repo.ComposeRepoFileMetas(ctx))
|
rctx = rctx.WithMetas(repo.ComposeRepoFileMetas(ctx))
|
||||||
} else {
|
} else {
|
||||||
// this is almost dead code, only to pass the incorrect tests
|
// this is almost dead code, only to pass the incorrect tests
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ type RepoWikiOptions struct {
|
|||||||
func NewRenderContextRepoWiki(ctx context.Context, repo *repo_model.Repository, opts ...RepoWikiOptions) *markup.RenderContext {
|
func NewRenderContextRepoWiki(ctx context.Context, repo *repo_model.Repository, opts ...RepoWikiOptions) *markup.RenderContext {
|
||||||
helper := &RepoWiki{opts: util.OptionalArg(opts)}
|
helper := &RepoWiki{opts: util.OptionalArg(opts)}
|
||||||
rctx := markup.NewRenderContext(ctx).WithMarkupType(markdown.MarkupName)
|
rctx := markup.NewRenderContext(ctx).WithMarkupType(markdown.MarkupName)
|
||||||
|
helper.commitChecker = newCommitChecker(ctx, repo)
|
||||||
if repo != nil {
|
if repo != nil {
|
||||||
helper.repoLink = repo.Link()
|
helper.repoLink = repo.Link()
|
||||||
helper.commitChecker = newCommitChecker(ctx, repo)
|
|
||||||
rctx = rctx.WithMetas(repo.ComposeWikiMetas(ctx))
|
rctx = rctx.WithMetas(repo.ComposeWikiMetas(ctx))
|
||||||
} else {
|
} else {
|
||||||
// this is almost dead code, only to pass the incorrect tests
|
// this is almost dead code, only to pass the incorrect tests
|
||||||
|
|||||||
@@ -177,49 +177,34 @@ Here are some links to the most important topics. You can find the full list of
|
|||||||
testRenderMarkup(t, "unknown", false, "", "## Test", "unsupported render mode: unknown\n", http.StatusUnprocessableEntity)
|
testRenderMarkup(t, "unknown", false, "", "## Test", "unsupported render mode: unknown\n", http.StatusUnprocessableEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
var simpleCases = []string{
|
|
||||||
// Guard wiki sidebar: special syntax
|
|
||||||
`[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]`,
|
|
||||||
// rendered
|
|
||||||
`<p>[[Guardfile-DSL / Configuring-Guard|Guardfile-DSL---Configuring-Guard]]</p>
|
|
||||||
`,
|
|
||||||
// special syntax
|
|
||||||
`[[Name|Link]]`,
|
|
||||||
// rendered
|
|
||||||
`<p>[[Name|Link]]</p>
|
|
||||||
`,
|
|
||||||
// empty
|
|
||||||
``,
|
|
||||||
// rendered
|
|
||||||
``,
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAPI_RenderSimple(t *testing.T) {
|
func TestAPI_RenderSimple(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
markup.RenderBehaviorForTesting.DisableAdditionalAttributes = true
|
markup.RenderBehaviorForTesting.DisableAdditionalAttributes = true
|
||||||
options := api.MarkdownOption{
|
|
||||||
Mode: "markdown",
|
|
||||||
Text: "",
|
|
||||||
Context: "/user2/repo1",
|
|
||||||
}
|
|
||||||
ctx, resp := contexttest.MockAPIContext(t, "POST /api/v1/markdown")
|
|
||||||
for i := 0; i < len(simpleCases); i += 2 {
|
|
||||||
options.Text = simpleCases[i]
|
|
||||||
web.SetForm(ctx, &options)
|
|
||||||
Markdown(ctx)
|
|
||||||
assert.Equal(t, simpleCases[i+1], resp.Body.String())
|
|
||||||
resp.Body.Reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAPI_RenderRaw(t *testing.T) {
|
testCases := []struct {
|
||||||
setting.AppURL = AppURL
|
in, out string
|
||||||
markup.RenderBehaviorForTesting.DisableAdditionalAttributes = true
|
mode string
|
||||||
ctx, resp := contexttest.MockAPIContext(t, "POST /api/v1/markdown")
|
}{
|
||||||
for i := 0; i < len(simpleCases); i += 2 {
|
{in: "", out: ""},
|
||||||
ctx.Req.Body = io.NopCloser(strings.NewReader(simpleCases[i]))
|
{in: "[[special-syntax]]", out: "<p>[[special-syntax]]</p>\n", mode: "markdown"},
|
||||||
MarkdownRaw(ctx)
|
{in: "[[special|syntax]]", out: "<p>[[special|syntax]]</p>\n", mode: "markdown"},
|
||||||
assert.Equal(t, simpleCases[i+1], resp.Body.String())
|
{in: "01234567890123456789", out: "<p>01234567890123456789</p>\n", mode: "gfm"}, // commit-like content should not crash the render
|
||||||
resp.Body.Reset()
|
|
||||||
}
|
}
|
||||||
|
t.Run("markdown", func(t *testing.T) {
|
||||||
|
for _, c := range testCases {
|
||||||
|
options := api.MarkdownOption{Mode: c.mode, Text: c.in, Context: "/user2/repo1"}
|
||||||
|
ctx, resp := contexttest.MockAPIContext(t, "POST /api/v1/markdown")
|
||||||
|
web.SetForm(ctx, &options)
|
||||||
|
Markdown(ctx)
|
||||||
|
assert.Equal(t, c.out, resp.Body.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("markdown-raw", func(t *testing.T) {
|
||||||
|
for _, c := range testCases {
|
||||||
|
ctx, resp := contexttest.MockAPIContext(t, "POST /api/v1/markdown")
|
||||||
|
ctx.Req.Body = io.NopCloser(strings.NewReader(c.in))
|
||||||
|
MarkdownRaw(ctx)
|
||||||
|
assert.Equal(t, c.out, resp.Body.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user