mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-19 19:18:43 +02:00
Merge branch 'main' into feat/add-oauth-management-to-api-for-iac-tooling
This commit is contained in:
commit
06468817d6
@ -59,27 +59,16 @@ RUN_USER = ; git
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; The protocol the server listens on. One of 'http', 'https', 'http+unix', 'fcgi' or 'fcgi+unix'. Defaults to 'http'
|
;; The protocol the server listens on. One of "http", "https", "http+unix", "fcgi" or "fcgi+unix".
|
||||||
;; Note: Value must be lowercase.
|
|
||||||
;PROTOCOL = http
|
;PROTOCOL = http
|
||||||
;;
|
;;
|
||||||
;; Expect PROXY protocol headers on connections
|
;; Set the domain for the server.
|
||||||
;USE_PROXY_PROTOCOL = false
|
;; Most users should set it to the real website domain of their Gitea instance.
|
||||||
;;
|
|
||||||
;; Use PROXY protocol in TLS Bridging mode
|
|
||||||
;PROXY_PROTOCOL_TLS_BRIDGING = false
|
|
||||||
;;
|
|
||||||
; Timeout to wait for PROXY protocol header (set to 0 to have no timeout)
|
|
||||||
;PROXY_PROTOCOL_HEADER_TIMEOUT=5s
|
|
||||||
;;
|
|
||||||
; Accept PROXY protocol headers with UNKNOWN type
|
|
||||||
;PROXY_PROTOCOL_ACCEPT_UNKNOWN=false
|
|
||||||
;;
|
|
||||||
;; Set the domain for the server
|
|
||||||
;DOMAIN = localhost
|
;DOMAIN = localhost
|
||||||
;;
|
;;
|
||||||
;; The AppURL used by Gitea to generate absolute links, defaults to "{PROTOCOL}://{DOMAIN}:{HTTP_PORT}/".
|
;; The AppURL used by Gitea to generate absolute links, defaults to "{PROTOCOL}://{DOMAIN}:{HTTP_PORT}/".
|
||||||
;; Most users should set it to the real website URL of their Gitea instance.
|
;; Most users should set it to the real website URL of their Gitea instance when there is a reverse proxy.
|
||||||
|
;; When it is empty, Gitea will use HTTP "Host" header to generate ROOT_URL, and fall back to the default one if no "Host" header.
|
||||||
;ROOT_URL =
|
;ROOT_URL =
|
||||||
;;
|
;;
|
||||||
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
|
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
|
||||||
@ -90,13 +79,25 @@ RUN_USER = ; git
|
|||||||
;STATIC_URL_PREFIX =
|
;STATIC_URL_PREFIX =
|
||||||
;;
|
;;
|
||||||
;; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
|
;; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
|
||||||
;; If PROTOCOL is set to `http+unix` or `fcgi+unix`, this should be the name of the Unix socket file to use.
|
;; If PROTOCOL is set to "http+unix" or "fcgi+unix", this should be the name of the Unix socket file to use.
|
||||||
;; Relative paths will be made absolute against the _`AppWorkPath`_.
|
;; Relative paths will be made absolute against the _`AppWorkPath`_.
|
||||||
;HTTP_ADDR = 0.0.0.0
|
;HTTP_ADDR = 0.0.0.0
|
||||||
;;
|
;;
|
||||||
;; The port to listen on. Leave empty when using a unix socket.
|
;; The port to listen on for "http" or "https" protocol. Leave empty when using a unix socket.
|
||||||
;HTTP_PORT = 3000
|
;HTTP_PORT = 3000
|
||||||
;;
|
;;
|
||||||
|
;; Expect PROXY protocol headers on connections
|
||||||
|
;USE_PROXY_PROTOCOL = false
|
||||||
|
;;
|
||||||
|
;; Use PROXY protocol in TLS Bridging mode
|
||||||
|
;PROXY_PROTOCOL_TLS_BRIDGING = false
|
||||||
|
;;
|
||||||
|
;; Timeout to wait for PROXY protocol header (set to 0 to have no timeout)
|
||||||
|
;PROXY_PROTOCOL_HEADER_TIMEOUT = 5s
|
||||||
|
;;
|
||||||
|
;; Accept PROXY protocol headers with UNKNOWN type
|
||||||
|
;PROXY_PROTOCOL_ACCEPT_UNKNOWN = false
|
||||||
|
;;
|
||||||
;; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server
|
;; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server
|
||||||
;; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main
|
;; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main
|
||||||
;; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for
|
;; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for
|
||||||
|
@ -70,11 +70,16 @@ func GuessCurrentHostURL(ctx context.Context) string {
|
|||||||
// 1. The reverse proxy is configured correctly, it passes "X-Forwarded-Proto/Host" headers. Perfect, Gitea can handle it correctly.
|
// 1. The reverse proxy is configured correctly, it passes "X-Forwarded-Proto/Host" headers. Perfect, Gitea can handle it correctly.
|
||||||
// 2. The reverse proxy is not configured correctly, doesn't pass "X-Forwarded-Proto/Host" headers, eg: only one "proxy_pass http://gitea:3000" in Nginx.
|
// 2. The reverse proxy is not configured correctly, doesn't pass "X-Forwarded-Proto/Host" headers, eg: only one "proxy_pass http://gitea:3000" in Nginx.
|
||||||
// 3. There is no reverse proxy.
|
// 3. There is no reverse proxy.
|
||||||
// Without an extra config option, Gitea is impossible to distinguish between case 2 and case 3,
|
// Without more information, Gitea is impossible to distinguish between case 2 and case 3, then case 2 would result in
|
||||||
// then case 2 would result in wrong guess like guessed AppURL becomes "http://gitea:3000/", which is not accessible by end users.
|
// wrong guess like guessed AppURL becomes "http://gitea:3000/" behind a "https" reverse proxy, which is not accessible by end users.
|
||||||
// So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL.
|
// So we introduced "UseHostHeader" option, it could be enabled by setting "ROOT_URL" to empty
|
||||||
reqScheme := getRequestScheme(req)
|
reqScheme := getRequestScheme(req)
|
||||||
if reqScheme == "" {
|
if reqScheme == "" {
|
||||||
|
// if no reverse proxy header, try to use "Host" header for absolute URL
|
||||||
|
if setting.UseHostHeader && req.Host != "" {
|
||||||
|
return util.Iif(req.TLS == nil, "http://", "https://") + req.Host
|
||||||
|
}
|
||||||
|
// fall back to default AppURL
|
||||||
return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
|
return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
|
||||||
}
|
}
|
||||||
// X-Forwarded-Host has many problems: non-standard, not well-defined (X-Forwarded-Port or not), conflicts with Host header.
|
// X-Forwarded-Host has many problems: non-standard, not well-defined (X-Forwarded-Port or not), conflicts with Host header.
|
||||||
|
@ -5,6 +5,7 @@ package httplib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -39,6 +40,25 @@ func TestIsRelativeURL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGuessCurrentHostURL(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
|
||||||
|
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||||
|
defer test.MockVariableValue(&setting.UseHostHeader, false)()
|
||||||
|
|
||||||
|
ctx := t.Context()
|
||||||
|
assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{Host: "localhost:3000"})
|
||||||
|
assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
|
||||||
|
|
||||||
|
defer test.MockVariableValue(&setting.UseHostHeader, true)()
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{Host: "http-host:3000"})
|
||||||
|
assert.Equal(t, "http://http-host:3000", GuessCurrentHostURL(ctx))
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{Host: "http-host", TLS: &tls.ConnectionState{}})
|
||||||
|
assert.Equal(t, "https://http-host", GuessCurrentHostURL(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
func TestMakeAbsoluteURL(t *testing.T) {
|
func TestMakeAbsoluteURL(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Protocol, "http")()
|
defer test.MockVariableValue(&setting.Protocol, "http")()
|
||||||
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
|
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
|
||||||
|
@ -71,7 +71,8 @@ var globalVars = sync.OnceValue(func() *globalVarsType {
|
|||||||
// it is still accepted by the CommonMark specification, as well as the HTML5 spec:
|
// it is still accepted by the CommonMark specification, as well as the HTML5 spec:
|
||||||
// http://spec.commonmark.org/0.28/#email-address
|
// http://spec.commonmark.org/0.28/#email-address
|
||||||
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
|
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
|
||||||
v.emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|;|,|\\?|!|\\.(\\s|$))")
|
// At the moment, we use stricter rule for rendering purpose: only allow the "name" part starting after the word boundary
|
||||||
|
v.emailRegex = regexp.MustCompile(`\b([-\w.!#$%&'*+/=?^{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)\b`)
|
||||||
|
|
||||||
// emojiShortCodeRegex find emoji by alias like :smile:
|
// emojiShortCodeRegex find emoji by alias like :smile:
|
||||||
v.emojiShortCodeRegex = regexp.MustCompile(`:[-+\w]+:`)
|
v.emojiShortCodeRegex = regexp.MustCompile(`:[-+\w]+:`)
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
|
|
||||||
package markup
|
package markup
|
||||||
|
|
||||||
import "golang.org/x/net/html"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
// emailAddressProcessor replaces raw email addresses with a mailto: link.
|
// emailAddressProcessor replaces raw email addresses with a mailto: link.
|
||||||
func emailAddressProcessor(ctx *RenderContext, node *html.Node) {
|
func emailAddressProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
@ -14,6 +18,14 @@ func emailAddressProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nextByte byte
|
||||||
|
if len(node.Data) > m[3] {
|
||||||
|
nextByte = node.Data[m[3]]
|
||||||
|
}
|
||||||
|
if strings.IndexByte(":/", nextByte) != -1 {
|
||||||
|
// for cases: "git@gitea.com:owner/repo.git", "https://git@gitea.com/owner/repo.git"
|
||||||
|
return
|
||||||
|
}
|
||||||
mail := node.Data[m[2]:m[3]]
|
mail := node.Data[m[2]:m[3]]
|
||||||
replaceContent(node, m[2], m[3], createLink(ctx, "mailto:"+mail, mail, "" /*mailto*/))
|
replaceContent(node, m[2], m[3], createLink(ctx, "mailto:"+mail, mail, "" /*mailto*/))
|
||||||
node = node.NextSibling.NextSibling
|
node = node.NextSibling.NextSibling
|
||||||
|
@ -225,10 +225,10 @@ func TestRender_email(t *testing.T) {
|
|||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
res, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
res, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res))
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res), "input: %s", input)
|
||||||
}
|
}
|
||||||
// Text that should be turned into email link
|
|
||||||
|
|
||||||
|
// Text that should be turned into email link
|
||||||
test(
|
test(
|
||||||
"info@gitea.com",
|
"info@gitea.com",
|
||||||
`<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`)
|
`<p><a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a></p>`)
|
||||||
@ -260,28 +260,48 @@ func TestRender_email(t *testing.T) {
|
|||||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>?
|
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>?
|
||||||
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`)
|
<a href="mailto:j.doe@example.com" rel="nofollow">j.doe@example.com</a>!</p>`)
|
||||||
|
|
||||||
|
// match GitHub behavior
|
||||||
|
test("email@domain@domain.com", `<p>email@<a href="mailto:domain@domain.com" rel="nofollow">domain@domain.com</a></p>`)
|
||||||
|
|
||||||
|
// match GitHub behavior
|
||||||
|
test(`"info@gitea.com"`, `<p>"<a href="mailto:info@gitea.com" rel="nofollow">info@gitea.com</a>"</p>`)
|
||||||
|
|
||||||
// Test that should *not* be turned into email links
|
// Test that should *not* be turned into email links
|
||||||
test(
|
|
||||||
"\"info@gitea.com\"",
|
|
||||||
`<p>"info@gitea.com"</p>`)
|
|
||||||
test(
|
test(
|
||||||
"/home/gitea/mailstore/info@gitea/com",
|
"/home/gitea/mailstore/info@gitea/com",
|
||||||
`<p>/home/gitea/mailstore/info@gitea/com</p>`)
|
`<p>/home/gitea/mailstore/info@gitea/com</p>`)
|
||||||
test(
|
test(
|
||||||
"git@try.gitea.io:go-gitea/gitea.git",
|
"git@try.gitea.io:go-gitea/gitea.git",
|
||||||
`<p>git@try.gitea.io:go-gitea/gitea.git</p>`)
|
`<p>git@try.gitea.io:go-gitea/gitea.git</p>`)
|
||||||
|
test(
|
||||||
|
"https://foo:bar@gitea.io",
|
||||||
|
`<p><a href="https://foo:bar@gitea.io" rel="nofollow">https://foo:bar@gitea.io</a></p>`)
|
||||||
test(
|
test(
|
||||||
"gitea@3",
|
"gitea@3",
|
||||||
`<p>gitea@3</p>`)
|
`<p>gitea@3</p>`)
|
||||||
test(
|
test(
|
||||||
"gitea@gmail.c",
|
"gitea@gmail.c",
|
||||||
`<p>gitea@gmail.c</p>`)
|
`<p>gitea@gmail.c</p>`)
|
||||||
test(
|
|
||||||
"email@domain@domain.com",
|
|
||||||
`<p>email@domain@domain.com</p>`)
|
|
||||||
test(
|
test(
|
||||||
"email@domain..com",
|
"email@domain..com",
|
||||||
`<p>email@domain..com</p>`)
|
`<p>email@domain..com</p>`)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
input, expected string
|
||||||
|
}{
|
||||||
|
// match GitHub behavior
|
||||||
|
{"?a@d.zz", `<p>?<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
|
||||||
|
{"*a@d.zz", `<p>*<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
|
||||||
|
{"~a@d.zz", `<p>~<a href="mailto:a@d.zz" rel="nofollow">a@d.zz</a></p>`},
|
||||||
|
|
||||||
|
// the following cases don't match GitHub behavior, but they are valid email addresses ...
|
||||||
|
// maybe we should reduce the candidate characters for the "name" part in the future
|
||||||
|
{"a*a@d.zz", `<p><a href="mailto:a*a@d.zz" rel="nofollow">a*a@d.zz</a></p>`},
|
||||||
|
{"a~a@d.zz", `<p><a href="mailto:a~a@d.zz" rel="nofollow">a~a@d.zz</a></p>`},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
test(c.input, c.expected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRender_emoji(t *testing.T) {
|
func TestRender_emoji(t *testing.T) {
|
||||||
|
@ -46,25 +46,37 @@ var (
|
|||||||
// AppURL is the Application ROOT_URL. It always has a '/' suffix
|
// AppURL is the Application ROOT_URL. It always has a '/' suffix
|
||||||
// It maps to ini:"ROOT_URL"
|
// It maps to ini:"ROOT_URL"
|
||||||
AppURL string
|
AppURL string
|
||||||
// AppSubURL represents the sub-url mounting point for gitea. It is either "" or starts with '/' and ends without '/', such as '/{subpath}'.
|
|
||||||
|
// AppSubURL represents the sub-url mounting point for gitea, parsed from "ROOT_URL"
|
||||||
|
// It is either "" or starts with '/' and ends without '/', such as '/{sub-path}'.
|
||||||
// This value is empty if site does not have sub-url.
|
// This value is empty if site does not have sub-url.
|
||||||
AppSubURL string
|
AppSubURL string
|
||||||
// UseSubURLPath makes Gitea handle requests with sub-path like "/sub-path/owner/repo/...", to make it easier to debug sub-path related problems without a reverse proxy.
|
|
||||||
|
// UseSubURLPath makes Gitea handle requests with sub-path like "/sub-path/owner/repo/...",
|
||||||
|
// to make it easier to debug sub-path related problems without a reverse proxy.
|
||||||
UseSubURLPath bool
|
UseSubURLPath bool
|
||||||
|
|
||||||
|
// UseHostHeader makes Gitea prefer to use the "Host" request header for construction of absolute URLs.
|
||||||
|
UseHostHeader bool
|
||||||
|
|
||||||
// AppDataPath is the default path for storing data.
|
// AppDataPath is the default path for storing data.
|
||||||
// It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data"
|
// It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data"
|
||||||
AppDataPath string
|
AppDataPath string
|
||||||
|
|
||||||
// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
|
// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
|
||||||
// It maps to ini:"LOCAL_ROOT_URL" in [server]
|
// It maps to ini:"LOCAL_ROOT_URL" in [server]
|
||||||
LocalURL string
|
LocalURL string
|
||||||
// AssetVersion holds a opaque value that is used for cache-busting assets
|
|
||||||
|
// AssetVersion holds an opaque value that is used for cache-busting assets
|
||||||
AssetVersion string
|
AssetVersion string
|
||||||
|
|
||||||
appTempPathInternal string // the temporary path for the app, it is only an internal variable, do not use it, always use AppDataTempDir
|
// appTempPathInternal is the temporary path for the app, it is only an internal variable
|
||||||
|
// DO NOT use it directly, always use AppDataTempDir
|
||||||
|
appTempPathInternal string
|
||||||
|
|
||||||
Protocol Scheme
|
Protocol Scheme
|
||||||
UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"`
|
UseProxyProtocol bool
|
||||||
ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"`
|
ProxyProtocolTLSBridging bool
|
||||||
ProxyProtocolHeaderTimeout time.Duration
|
ProxyProtocolHeaderTimeout time.Duration
|
||||||
ProxyProtocolAcceptUnknown bool
|
ProxyProtocolAcceptUnknown bool
|
||||||
Domain string
|
Domain string
|
||||||
@ -181,13 +193,14 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
|
EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
Protocol = HTTP
|
|
||||||
protocolCfg := sec.Key("PROTOCOL").String()
|
protocolCfg := sec.Key("PROTOCOL").String()
|
||||||
if protocolCfg != "https" && EnableAcme {
|
if protocolCfg != "https" && EnableAcme {
|
||||||
log.Fatal("ACME could only be used with HTTPS protocol")
|
log.Fatal("ACME could only be used with HTTPS protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch protocolCfg {
|
switch protocolCfg {
|
||||||
|
case "", "http":
|
||||||
|
Protocol = HTTP
|
||||||
case "https":
|
case "https":
|
||||||
Protocol = HTTPS
|
Protocol = HTTPS
|
||||||
if EnableAcme {
|
if EnableAcme {
|
||||||
@ -243,7 +256,7 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
case "unix":
|
case "unix":
|
||||||
log.Warn("unix PROTOCOL value is deprecated, please use http+unix")
|
log.Warn("unix PROTOCOL value is deprecated, please use http+unix")
|
||||||
fallthrough
|
fallthrough
|
||||||
case "http+unix":
|
default: // "http+unix"
|
||||||
Protocol = HTTPUnix
|
Protocol = HTTPUnix
|
||||||
}
|
}
|
||||||
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
|
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
|
||||||
@ -256,6 +269,8 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
if !filepath.IsAbs(HTTPAddr) {
|
if !filepath.IsAbs(HTTPAddr) {
|
||||||
HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr)
|
HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
log.Fatal("Invalid PROTOCOL %q", Protocol)
|
||||||
}
|
}
|
||||||
UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false)
|
UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false)
|
||||||
ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false)
|
ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false)
|
||||||
@ -268,12 +283,16 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout)
|
PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout)
|
||||||
|
|
||||||
defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort
|
defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort
|
||||||
AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL)
|
AppURL = sec.Key("ROOT_URL").String()
|
||||||
|
if AppURL == "" {
|
||||||
|
UseHostHeader = true
|
||||||
|
AppURL = defaultAppURL
|
||||||
|
}
|
||||||
|
|
||||||
// Check validity of AppURL
|
// Check validity of AppURL
|
||||||
appURL, err := url.Parse(AppURL)
|
appURL, err := url.Parse(AppURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err)
|
log.Fatal("Invalid ROOT_URL %q: %s", AppURL, err)
|
||||||
}
|
}
|
||||||
// Remove default ports from AppURL.
|
// Remove default ports from AppURL.
|
||||||
// (scheme-based URL normalization, RFC 3986 section 6.2.3)
|
// (scheme-based URL normalization, RFC 3986 section 6.2.3)
|
||||||
@ -309,13 +328,15 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
defaultLocalURL = AppURL
|
defaultLocalURL = AppURL
|
||||||
case FCGIUnix:
|
case FCGIUnix:
|
||||||
defaultLocalURL = AppURL
|
defaultLocalURL = AppURL
|
||||||
default:
|
case HTTP, HTTPS:
|
||||||
defaultLocalURL = string(Protocol) + "://"
|
defaultLocalURL = string(Protocol) + "://"
|
||||||
if HTTPAddr == "0.0.0.0" {
|
if HTTPAddr == "0.0.0.0" {
|
||||||
defaultLocalURL += net.JoinHostPort("localhost", HTTPPort) + "/"
|
defaultLocalURL += net.JoinHostPort("localhost", HTTPPort) + "/"
|
||||||
} else {
|
} else {
|
||||||
defaultLocalURL += net.JoinHostPort(HTTPAddr, HTTPPort) + "/"
|
defaultLocalURL += net.JoinHostPort(HTTPAddr, HTTPPort) + "/"
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
log.Fatal("Invalid PROTOCOL %q", Protocol)
|
||||||
}
|
}
|
||||||
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
|
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
|
||||||
LocalURL = strings.TrimRight(LocalURL, "/") + "/"
|
LocalURL = strings.TrimRight(LocalURL, "/") + "/"
|
||||||
|
@ -76,6 +76,7 @@ func TestShadowPassword(t *testing.T) {
|
|||||||
func TestSelfCheckPost(t *testing.T) {
|
func TestSelfCheckPost(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")()
|
defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")()
|
||||||
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||||
|
defer test.MockVariableValue(&setting.UseHostHeader, false)()
|
||||||
|
|
||||||
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
|
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
|
||||||
SelfCheckPost(ctx)
|
SelfCheckPost(ctx)
|
||||||
|
@ -6,7 +6,7 @@ package feed
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strings"
|
||||||
|
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -14,15 +14,10 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func userFeedCacheKey(userID int64) string {
|
|
||||||
return fmt.Sprintf("user_feed_%d", userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFeedsForDashboard(ctx context.Context, opts activities_model.GetFeedsOptions) (activities_model.ActionList, int, error) {
|
func GetFeedsForDashboard(ctx context.Context, opts activities_model.GetFeedsOptions) (activities_model.ActionList, int, error) {
|
||||||
opts.DontCount = opts.RequestedTeam == nil && opts.Date == ""
|
opts.DontCount = opts.RequestedTeam == nil && opts.Date == ""
|
||||||
results, cnt, err := activities_model.GetFeeds(ctx, opts)
|
results, cnt, err := activities_model.GetFeeds(ctx, opts)
|
||||||
@ -40,7 +35,18 @@ func GetFeeds(ctx context.Context, opts activities_model.GetFeedsOptions) (activ
|
|||||||
// * Organization action: UserID=100 (the repo's org), ActUserID=1
|
// * Organization action: UserID=100 (the repo's org), ActUserID=1
|
||||||
// * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1
|
// * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1
|
||||||
func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers []*repo_model.Watch, permCode, permIssue, permPR []bool) error {
|
func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers []*repo_model.Watch, permCode, permIssue, permPR []bool) error {
|
||||||
// Add feed for actioner.
|
// MySQL has TEXT length limit 65535.
|
||||||
|
// Sometimes the content is "field1|field2|field3", sometimes the content is JSON (ActionMirrorSyncPush, ActionCommitRepo, ActionPushTag, etc...)
|
||||||
|
if left, right := util.EllipsisDisplayStringX(act.Content, 65535); right != "" {
|
||||||
|
if strings.HasPrefix(act.Content, `{"`) && strings.HasSuffix(act.Content, `}`) {
|
||||||
|
// FIXME: at the moment we can do nothing if the content is JSON and it is too long
|
||||||
|
act.Content = "{}"
|
||||||
|
} else {
|
||||||
|
act.Content = left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add feed for actor.
|
||||||
act.UserID = act.ActUserID
|
act.UserID = act.ActUserID
|
||||||
if err := db.Insert(ctx, act); err != nil {
|
if err := db.Insert(ctx, act); err != nil {
|
||||||
return fmt.Errorf("insert new actioner: %w", err)
|
return fmt.Errorf("insert new actioner: %w", err)
|
||||||
@ -76,24 +82,18 @@ func notifyWatchers(ctx context.Context, act *activities_model.Action, watchers
|
|||||||
if !permPR[i] {
|
if !permPR[i] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Insert(ctx, act); err != nil {
|
if err := db.Insert(ctx, act); err != nil {
|
||||||
return fmt.Errorf("insert new action: %w", err)
|
return fmt.Errorf("insert new action: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
total, err := activities_model.CountUserFeeds(ctx, act.UserID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("count user feeds: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = cache.GetCache().Put(userFeedCacheKey(act.UserID), strconv.FormatInt(total, 10), setting.CacheService.TTLSeconds())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
// NotifyWatchers creates batch of actions for every watcher.
|
||||||
func NotifyWatchers(ctx context.Context, acts ...*activities_model.Action) error {
|
func NotifyWatchers(ctx context.Context, acts ...*activities_model.Action) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||||
if len(acts) == 0 {
|
if len(acts) == 0 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user