Merge branch 'main' into fix-any-hash-parse

This commit is contained in:
wxiaoguang 2024-05-02 18:23:00 +08:00
commit 067853f5b2
8 changed files with 57 additions and 11 deletions

View File

@ -17,11 +17,14 @@ import (
"time" "time"
charsetModule "code.gitea.io/gitea/modules/charset" charsetModule "code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/klauspost/compress/gzhttp"
) )
type ServeHeaderOptions struct { type ServeHeaderOptions struct {
@ -38,6 +41,11 @@ type ServeHeaderOptions struct {
func ServeSetHeaders(w http.ResponseWriter, opts *ServeHeaderOptions) { func ServeSetHeaders(w http.ResponseWriter, opts *ServeHeaderOptions) {
header := w.Header() header := w.Header()
skipCompressionExts := container.SetOf(".gz", ".bz2", ".zip", ".xz", ".zst", ".deb", ".apk", ".jar", ".png", ".jpg", ".webp")
if skipCompressionExts.Contains(strings.ToLower(path.Ext(opts.Filename))) {
w.Header().Add(gzhttp.HeaderNoCompression, "1")
}
contentType := typesniffer.ApplicationOctetStream contentType := typesniffer.ApplicationOctetStream
if opts.ContentType != "" { if opts.ContentType != "" {
if opts.ContentTypeCharset != "" { if opts.ContentTypeCharset != "" {

View File

@ -592,17 +592,16 @@ func replaceContentList(node *html.Node, i, j int, newNodes []*html.Node) {
func mentionProcessor(ctx *RenderContext, node *html.Node) { func mentionProcessor(ctx *RenderContext, node *html.Node) {
start := 0 start := 0
next := node.NextSibling for node != nil {
for node != nil && node != next && start < len(node.Data) { found, loc := references.FindFirstMentionBytes(util.UnsafeStringToBytes(node.Data[start:]))
// We replace only the first mention; other mentions will be addressed later
found, loc := references.FindFirstMentionBytes([]byte(node.Data[start:]))
if !found { if !found {
return node = node.NextSibling
start = 0
continue
} }
loc.Start += start loc.Start += start
loc.End += start loc.End += start
mention := node.Data[loc.Start:loc.End] mention := node.Data[loc.Start:loc.End]
var teams string
teams, ok := ctx.Metas["teams"] teams, ok := ctx.Metas["teams"]
// FIXME: util.URLJoin may not be necessary here: // FIXME: util.URLJoin may not be necessary here:
// - setting.AppURL is defined to have a terminal '/' so unless mention[1:] // - setting.AppURL is defined to have a terminal '/' so unless mention[1:]
@ -624,10 +623,10 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) {
if DefaultProcessorHelper.IsUsernameMentionable != nil && DefaultProcessorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) { if DefaultProcessorHelper.IsUsernameMentionable != nil && DefaultProcessorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) {
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), mentionedUsername), mention, "mention")) replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), mentionedUsername), mention, "mention"))
node = node.NextSibling.NextSibling node = node.NextSibling.NextSibling
} else {
node = node.NextSibling
}
start = 0 start = 0
} else {
start = loc.End
}
} }
} }

View File

@ -29,7 +29,7 @@ var (
// TODO: fix invalid linking issue // TODO: fix invalid linking issue
// mentionPattern matches all mentions in the form of "@user" or "@org/team" // mentionPattern matches all mentions in the form of "@user" or "@org/team"
mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_]+\/?[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_][0-9a-zA-Z-_.]+\/?[0-9a-zA-Z-_.]+[0-9a-zA-Z-_])(?:\s|[:,;.?!]\s|[:,;.?!]?$|\)|\])`) mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[-\w][-.\w]*?|@[-\w][-.\w]*?/[-\w][-.\w]*?)(?:\s|$|[:,;.?!](\s|$)|'|\)|\])`)
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287 // issueNumericPattern matches string that references to a numeric issue, e.g. #1287
issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`) issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`)
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234 // issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234

View File

@ -392,6 +392,7 @@ func TestRegExp_mentionPattern(t *testing.T) {
{"@gitea,", "@gitea"}, {"@gitea,", "@gitea"},
{"@gitea;", "@gitea"}, {"@gitea;", "@gitea"},
{"@gitea/team1;", "@gitea/team1"}, {"@gitea/team1;", "@gitea/team1"},
{"@user's idea", "@user"},
} }
falseTestCases := []string{ falseTestCases := []string{
"@ 0", "@ 0",
@ -412,7 +413,6 @@ func TestRegExp_mentionPattern(t *testing.T) {
for _, testCase := range trueTestCases { for _, testCase := range trueTestCases {
found := mentionPattern.FindStringSubmatch(testCase.pat) found := mentionPattern.FindStringSubmatch(testCase.pat)
assert.Len(t, found, 2)
assert.Equal(t, testCase.exp, found[1]) assert.Equal(t, testCase.exp, found[1])
} }
for _, testCase := range falseTestCases { for _, testCase := range falseTestCases {

View File

@ -207,3 +207,8 @@ func TestRenderLabels(t *testing.T) {
expected = `/owner/repo/pulls?labels=123` expected = `/owner/repo/pulls?labels=123`
assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected) assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected)
} }
func TestUserMention(t *testing.T) {
rendered := RenderMarkdownToHtml(context.Background(), "@no-such-user @mention-user @mention-user")
assert.EqualValues(t, `<p>@no-such-user <a href="/mention-user" rel="nofollow">@mention-user</a> <a href="/mention-user" rel="nofollow">@mention-user</a></p>`, strings.TrimSpace(string(rendered)))
}

View File

@ -54,7 +54,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
const GzipMinSize = 1400 // min size to compress for the body size of response var GzipMinSize = 1400 // min size to compress for the body size of response
// optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests. // optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests.
func optionsCorsHandler() func(next http.Handler) http.Handler { func optionsCorsHandler() func(next http.Handler) http.Handler {

View File

@ -0,0 +1,33 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
"io"
"net/http"
"testing"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/web"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestRepoDownloadArchive(t *testing.T) {
defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.EnableGzip, true)()
defer test.MockVariableValue(&web.GzipMinSize, 10)()
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
req := NewRequest(t, "GET", "/user2/repo1/archive/master.zip")
req.Header.Set("Accept-Encoding", "gzip")
resp := MakeRequest(t, req, http.StatusOK)
bs, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
assert.Empty(t, resp.Header().Get("Content-Encoding"))
assert.Equal(t, 320, len(bs))
}

View File

@ -152,6 +152,7 @@
} }
.ui.attached.segment:has(+ .ui[class*="top attached"].header), .ui.attached.segment:has(+ .ui[class*="top attached"].header),
.ui.attached.segment:has(+ .page.buttons),
.ui.attached.segment:last-child, .ui.attached.segment:last-child,
.ui.segment:has(+ .ui.segment:not(.attached)), .ui.segment:has(+ .ui.segment:not(.attached)),
.ui.attached.segment:has(+ .ui.modal) { .ui.attached.segment:has(+ .ui.modal) {