新增:路由定义

This commit is contained in:
yystopf 2022-10-20 18:33:02 +08:00
parent 3e5b2a738c
commit da9cd18f74
8 changed files with 807 additions and 1 deletions

273
cmd/web.go Normal file
View File

@ -0,0 +1,273 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"context"
"fmt"
"net"
"net/http"
"os"
"strings"
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/install"
hat_routers "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers"
"github.com/felixge/fgprof"
"github.com/urfave/cli"
ini "gopkg.in/ini.v1"
)
// CmdWeb represents the available web sub-command.
var CmdWeb = cli.Command{
Name: "web",
Usage: "Start Gitea web server",
Description: `Gitea web server is the only thing you need to run,
and it takes care of all the other things for you`,
Action: runWeb,
Flags: []cli.Flag{
cli.StringFlag{
Name: "port, p",
Value: "3000",
Usage: "Temporary port number to prevent conflict",
},
cli.StringFlag{
Name: "install-port",
Value: "3000",
Usage: "Temporary port number to run the install page on to prevent conflict",
},
cli.StringFlag{
Name: "pid, P",
Value: setting.PIDFile,
Usage: "Custom pid file path",
},
cli.BoolFlag{
Name: "quiet, q",
Usage: "Only display Fatal logging errors until logging is set-up",
},
cli.BoolFlag{
Name: "verbose",
Usage: "Set initial logging to TRACE level until logging is properly set-up",
},
},
}
func runHTTPRedirector() {
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: HTTP Redirector", process.SystemProcessType, true)
defer finished()
source := fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.PortToRedirect)
dest := strings.TrimSuffix(setting.AppURL, "/")
log.Info("Redirecting: %s to %s", source, dest)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
target := dest + r.URL.Path
if len(r.URL.RawQuery) > 0 {
target += "?" + r.URL.RawQuery
}
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
})
err := runHTTP("tcp", source, "HTTP Redirector", handler)
if err != nil {
log.Fatal("Failed to start port redirection: %v", err)
}
}
func runWeb(ctx *cli.Context) error {
if ctx.Bool("verbose") {
_ = log.DelLogger("console")
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "trace", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
} else if ctx.Bool("quiet") {
_ = log.DelLogger("console")
log.NewLogger(0, "console", "console", fmt.Sprintf(`{"level": "fatal", "colorize": %t, "stacktraceLevel": "none"}`, log.CanColorStdout))
}
defer func() {
if panicked := recover(); panicked != nil {
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
}
}()
managerCtx, cancel := context.WithCancel(context.Background())
graceful.InitManager(managerCtx)
defer cancel()
if os.Getppid() > 1 && len(os.Getenv("LISTEN_FDS")) > 0 {
log.Info("Restarting Gitea on PID: %d from parent PID: %d", os.Getpid(), os.Getppid())
} else {
log.Info("Starting Gitea on PID: %d", os.Getpid())
}
// Set pid file setting
if ctx.IsSet("pid") {
setting.PIDFile = ctx.String("pid")
setting.WritePIDFile = true
}
// Perform pre-initialization
needsInstall := install.PreloadSettings(graceful.GetManager().HammerContext())
if needsInstall {
// Flag for port number in case first time run conflict
if ctx.IsSet("port") {
if err := setPort(ctx.String("port")); err != nil {
return err
}
}
if ctx.IsSet("install-port") {
if err := setPort(ctx.String("install-port")); err != nil {
return err
}
}
c := install.Routes()
err := listen(c, false)
if err != nil {
log.Critical("Unable to open listener for installer. Is Gitea already running?")
graceful.GetManager().DoGracefulShutdown()
}
select {
case <-graceful.GetManager().IsShutdown():
<-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid())
log.Close()
return err
default:
}
} else {
NoInstallListener()
}
if setting.EnablePprof {
go func() {
http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
_, _, finished := process.GetManager().AddTypedContext(context.Background(), "Web: PProf Server", process.SystemProcessType, true)
log.Info("Starting pprof server on localhost:6060")
log.Info("%v", http.ListenAndServe("localhost:6060", nil))
finished()
}()
}
log.Info("Global init")
// Perform global initialization
setting.LoadFromExisting()
routers.GlobalInitInstalled(graceful.GetManager().HammerContext())
// We check that AppDataPath exists here (it should have been created during installation)
// We can't check it in `GlobalInitInstalled`, because some integration tests
// use cmd -> GlobalInitInstalled, but the AppDataPath doesn't exist during those tests.
if _, err := os.Stat(setting.AppDataPath); err != nil {
log.Fatal("Can not find APP_DATA_PATH '%s'", setting.AppDataPath)
}
// Override the provided port number within the configuration
if ctx.IsSet("port") {
if err := setPort(ctx.String("port")); err != nil {
return err
}
}
// Set up Chi routes
c := routers.NormalRoutes()
hat_routers.InitHatRouters(c)
err := listen(c, true)
<-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid())
log.Close()
return err
}
func setPort(port string) error {
setting.AppURL = strings.Replace(setting.AppURL, setting.HTTPPort, port, 1)
setting.HTTPPort = port
switch setting.Protocol {
case setting.HTTPUnix:
case setting.FCGI:
case setting.FCGIUnix:
default:
defaultLocalURL := string(setting.Protocol) + "://"
if setting.HTTPAddr == "0.0.0.0" {
defaultLocalURL += "localhost"
} else {
defaultLocalURL += setting.HTTPAddr
}
defaultLocalURL += ":" + setting.HTTPPort + "/"
// Save LOCAL_ROOT_URL if port changed
setting.CreateOrAppendToCustomConf(func(cfg *ini.File) {
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
})
}
return nil
}
func listen(m http.Handler, handleRedirector bool) error {
listenAddr := setting.HTTPAddr
if setting.Protocol != setting.HTTPUnix && setting.Protocol != setting.FCGIUnix {
listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort)
}
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: Gitea Server", process.SystemProcessType, true)
defer finished()
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
// This can be useful for users, many users do wrong to their config and get strange behaviors behind a reverse-proxy.
// A user may fix the configuration mistake when he sees this log.
// And this is also very helpful to maintainers to provide help to users to resolve their configuration problems.
log.Info("AppURL(ROOT_URL): %s", setting.AppURL)
if setting.LFS.StartServer {
log.Info("LFS server enabled")
}
var err error
switch setting.Protocol {
case setting.HTTP:
if handleRedirector {
NoHTTPRedirector()
}
err = runHTTP("tcp", listenAddr, "Web", m)
case setting.HTTPS:
if setting.EnableAcme {
err = runACME(listenAddr, m)
break
} else {
if handleRedirector {
if setting.RedirectOtherPort {
go runHTTPRedirector()
} else {
NoHTTPRedirector()
}
}
err = runHTTPS("tcp", listenAddr, "Web", setting.CertFile, setting.KeyFile, m)
}
case setting.FCGI:
if handleRedirector {
NoHTTPRedirector()
}
err = runFCGI("tcp", listenAddr, "FCGI Web", m)
case setting.HTTPUnix:
if handleRedirector {
NoHTTPRedirector()
}
err = runHTTP("unix", listenAddr, "Web", m)
case setting.FCGIUnix:
if handleRedirector {
NoHTTPRedirector()
}
err = runFCGI("unix", listenAddr, "Web", m)
default:
log.Fatal("Invalid protocol: %s", setting.Protocol)
}
if err != nil {
log.Critical("Failed to start server: %v", err)
}
log.Info("HTTP Listener: %s Closed", listenAddr)
return err
}

136
cmd/web_acme.go Normal file
View File

@ -0,0 +1,136 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"crypto/x509"
"encoding/pem"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"github.com/caddyserver/certmagic"
)
func getCARoot(path string) (*x509.CertPool, error) {
r, err := os.ReadFile(path)
if err != nil {
return nil, err
}
block, _ := pem.Decode(r)
if block == nil {
return nil, fmt.Errorf("no PEM found in the file %s", path)
}
caRoot, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
certPool := x509.NewCertPool()
certPool.AddCert(caRoot)
return certPool, nil
}
func runACME(listenAddr string, m http.Handler) error {
// If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443.
// Due to docker port mapping this can't be checked programmatically
// TODO: these are placeholders until we add options for each in settings with appropriate warning
enableHTTPChallenge := true
enableTLSALPNChallenge := true
altHTTPPort := 0
altTLSALPNPort := 0
if p, err := strconv.Atoi(setting.PortToRedirect); err == nil {
altHTTPPort = p
}
if p, err := strconv.Atoi(setting.HTTPPort); err == nil {
altTLSALPNPort = p
}
magic := certmagic.NewDefault()
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
// Try to use private CA root if provided, otherwise defaults to system's trust
var certPool *x509.CertPool
if setting.AcmeCARoot != "" {
var err error
certPool, err = getCARoot(setting.AcmeCARoot)
if err != nil {
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
}
}
myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{
CA: setting.AcmeURL,
TrustedRoots: certPool,
Email: setting.AcmeEmail,
Agreed: setting.AcmeTOS,
DisableHTTPChallenge: !enableHTTPChallenge,
DisableTLSALPNChallenge: !enableTLSALPNChallenge,
ListenHost: setting.HTTPAddr,
AltTLSALPNPort: altTLSALPNPort,
AltHTTPPort: altHTTPPort,
})
magic.Issuers = []certmagic.Issuer{myACME}
// this obtains certificates or renews them if necessary
err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{setting.Domain})
if err != nil {
return err
}
tlsConfig := magic.TLSConfig()
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
tlsConfig.MinVersion = version
}
if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
tlsConfig.MaxVersion = version
}
// Set curve preferences
if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
tlsConfig.CurvePreferences = curves
}
// Set cipher suites
if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
tlsConfig.CipherSuites = ciphers
}
if enableHTTPChallenge {
go func() {
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: ACME HTTP challenge server", process.SystemProcessType, true)
defer finished()
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
err := runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
if err != nil {
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
}
}()
}
return runHTTPSWithTLSConfig("tcp", listenAddr, "Web", tlsConfig, m)
}
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "HEAD" {
http.Error(w, "Use HTTPS", http.StatusBadRequest)
return
}
// Remove the trailing slash at the end of setting.AppURL, the request
// URI always contains a leading slash, which would result in a double
// slash
target := strings.TrimSuffix(setting.AppURL, "/") + r.URL.RequestURI()
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
}

56
cmd/web_graceful.go Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"net"
"net/http"
"net/http/fcgi"
"strings"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
func runHTTP(network, listenAddr, name string, m http.Handler) error {
return graceful.HTTPListenAndServe(network, listenAddr, name, m)
}
// NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
func NoHTTPRedirector() {
graceful.GetManager().InformCleanup()
}
// NoMainListener tells our cleanup routine that we will not be using a possibly provided listener
// for our main HTTP/HTTPS service
func NoMainListener() {
graceful.GetManager().InformCleanup()
}
// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener
// for our install HTTP/HTTPS service
func NoInstallListener() {
graceful.GetManager().InformCleanup()
}
func runFCGI(network, listenAddr, name string, m http.Handler) error {
// This needs to handle stdin as fcgi point
fcgiServer := graceful.NewServer(network, listenAddr, name)
err := fcgiServer.ListenAndServe(func(listener net.Listener) error {
return fcgi.Serve(listener, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
if setting.AppSubURL != "" {
req.URL.Path = strings.TrimPrefix(req.URL.Path, setting.AppSubURL)
}
m.ServeHTTP(resp, req)
}))
})
if err != nil {
log.Fatal("Failed to start FCGI main server: %v", err)
}
log.Info("FCGI Listener: %s Closed", listenAddr)
return err
}

192
cmd/web_https.go Normal file
View File

@ -0,0 +1,192 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"crypto/tls"
"net/http"
"os"
"strings"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/klauspost/cpuid/v2"
)
var tlsVersionStringMap = map[string]uint16{
"": tls.VersionTLS12, // Default to tls.VersionTLS12
"tlsv1.0": tls.VersionTLS10,
"tlsv1.1": tls.VersionTLS11,
"tlsv1.2": tls.VersionTLS12,
"tlsv1.3": tls.VersionTLS13,
}
func toTLSVersion(version string) uint16 {
tlsVersion, ok := tlsVersionStringMap[strings.TrimSpace(strings.ToLower(version))]
if !ok {
log.Warn("Unknown tls version: %s", version)
return 0
}
return tlsVersion
}
var curveStringMap = map[string]tls.CurveID{
"x25519": tls.X25519,
"p256": tls.CurveP256,
"p384": tls.CurveP384,
"p521": tls.CurveP521,
}
func toCurvePreferences(preferences []string) []tls.CurveID {
ids := make([]tls.CurveID, 0, len(preferences))
for _, pref := range preferences {
id, ok := curveStringMap[strings.TrimSpace(strings.ToLower(pref))]
if !ok {
log.Warn("Unknown curve: %s", pref)
}
if id != 0 {
ids = append(ids, id)
}
}
return ids
}
var cipherStringMap = map[string]uint16{
"rsa_with_rc4_128_sha": tls.TLS_RSA_WITH_RC4_128_SHA,
"rsa_with_3des_ede_cbc_sha": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
"rsa_with_aes_128_cbc_sha": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
"rsa_with_aes_256_cbc_sha": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
"rsa_with_aes_128_cbc_sha256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
"rsa_with_aes_128_gcm_sha256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
"rsa_with_aes_256_gcm_sha384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
"ecdhe_ecdsa_with_rc4_128_sha": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
"ecdhe_ecdsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
"ecdhe_ecdsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
"ecdhe_rsa_with_rc4_128_sha": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
"ecdhe_rsa_with_3des_ede_cbc_sha": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
"ecdhe_rsa_with_aes_128_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
"ecdhe_rsa_with_aes_256_cbc_sha": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
"ecdhe_ecdsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
"ecdhe_rsa_with_aes_128_cbc_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
"ecdhe_rsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
"ecdhe_ecdsa_with_aes_128_gcm_sha256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
"ecdhe_rsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
"ecdhe_ecdsa_with_aes_256_gcm_sha384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
"ecdhe_rsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
"ecdhe_ecdsa_with_chacha20_poly1305_sha256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
"ecdhe_rsa_with_chacha20_poly1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
"ecdhe_ecdsa_with_chacha20_poly1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
"aes_128_gcm_sha256": tls.TLS_AES_128_GCM_SHA256,
"aes_256_gcm_sha384": tls.TLS_AES_256_GCM_SHA384,
"chacha20_poly1305_sha256": tls.TLS_CHACHA20_POLY1305_SHA256,
}
func toTLSCiphers(cipherStrings []string) []uint16 {
ciphers := make([]uint16, 0, len(cipherStrings))
for _, cipherString := range cipherStrings {
cipher, ok := cipherStringMap[strings.TrimSpace(strings.ToLower(cipherString))]
if !ok {
log.Warn("Unknown cipher: %s", cipherString)
}
if cipher != 0 {
ciphers = append(ciphers, cipher)
}
}
return ciphers
}
// defaultCiphers uses hardware support to check if AES is specifically
// supported by the CPU.
//
// If AES is supported AES ciphers will be preferred over ChaCha based ciphers
// (This code is directly inspired by the certmagic code.)
func defaultCiphers() []uint16 {
if cpuid.CPU.Supports(cpuid.AESNI) {
return defaultCiphersAESfirst
}
return defaultCiphersChaChaFirst
}
var (
defaultCiphersAES = []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
}
defaultCiphersChaCha = []uint16{
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
}
defaultCiphersAESfirst = append(defaultCiphersAES, defaultCiphersChaCha...)
defaultCiphersChaChaFirst = append(defaultCiphersChaCha, defaultCiphersAES...)
)
// runHTTPs listens on the provided network address and then calls
// Serve to handle requests on incoming TLS connections.
//
// Filenames containing a certificate and matching private key for the server must
// be provided. If the certificate is signed by a certificate authority, the
// certFile should be the concatenation of the server's certificate followed by the
// CA's certificate.
func runHTTPS(network, listenAddr, name, certFile, keyFile string, m http.Handler) error {
tlsConfig := &tls.Config{}
if tlsConfig.NextProtos == nil {
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
}
if version := toTLSVersion(setting.SSLMinimumVersion); version != 0 {
tlsConfig.MinVersion = version
}
if version := toTLSVersion(setting.SSLMaximumVersion); version != 0 {
tlsConfig.MaxVersion = version
}
// Set curve preferences
tlsConfig.CurvePreferences = []tls.CurveID{
tls.X25519,
tls.CurveP256,
}
if curves := toCurvePreferences(setting.SSLCurvePreferences); len(curves) > 0 {
tlsConfig.CurvePreferences = curves
}
// Set cipher suites
tlsConfig.CipherSuites = defaultCiphers()
if ciphers := toTLSCiphers(setting.SSLCipherSuites); len(ciphers) > 0 {
tlsConfig.CipherSuites = ciphers
}
tlsConfig.Certificates = make([]tls.Certificate, 1)
certPEMBlock, err := os.ReadFile(certFile)
if err != nil {
log.Error("Failed to load https cert file %s for %s:%s: %v", certFile, network, listenAddr, err)
return err
}
keyPEMBlock, err := os.ReadFile(keyFile)
if err != nil {
log.Error("Failed to load https key file %s for %s:%s: %v", keyFile, network, listenAddr, err)
return err
}
tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
log.Error("Failed to create certificate from cert file %s and key file %s for %s:%s: %v", certFile, keyFile, network, listenAddr, err)
return err
}
return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m)
}
func runHTTPSWithTLSConfig(network, listenAddr, name string, tlsConfig *tls.Config, m http.Handler) error {
return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, name, tlsConfig, m)
}

View File

@ -10,6 +10,8 @@ import (
"code.gitea.io/gitea/cmd"
"code.gitea.io/gitea/modules/setting"
hat_cmd "code.gitlink.org.cn/Gitlink/gitea_hat.git/cmd"
"github.com/urfave/cli"
)
@ -40,7 +42,7 @@ func main() {
arguments - which can alternatively be run by running the subcommand web.`
app.Version = Version + formatBuiltWith()
app.Commands = []cli.Command{
cmd.CmdWeb,
hat_cmd.CmdWeb,
cmd.CmdServ,
cmd.CmdHook,
cmd.CmdDump,

77
routers/hat/hat.go Normal file
View File

@ -0,0 +1,77 @@
package hat
import (
"net/http"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/misc"
"code.gitea.io/gitea/services/auth"
"github.com/go-chi/cors"
)
func Routers() *web.Route {
m := web.NewRoute()
m.Use(securityHeaders())
if setting.CORSConfig.Enabled {
m.Use(cors.Handler(cors.Options{
// Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option
AllowedOrigins: setting.CORSConfig.AllowDomain,
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
AllowedMethods: setting.CORSConfig.Methods,
AllowCredentials: setting.CORSConfig.AllowCredentials,
AllowedHeaders: []string{"Authorization", "X-Gitea-OTP"},
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
}))
}
m.Use(context.APIContexter())
group := buildAuthGroup()
if err := group.Init(); err != nil {
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err)
}
// Get user from session if logged in.
m.Use(context.APIAuth(group))
m.Use(context.ToggleAPI(&context.ToggleOptions{
SignInRequired: setting.Service.RequireSignInView,
}))
m.Use(context.ToggleAPI(&context.ToggleOptions{
SignInRequired: setting.Service.RequireSignInView,
}))
m.Group("", func() {
m.Get("/version", misc.Version)
})
return m
}
func securityHeaders() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
// CORB: https://www.chromium.org/Home/chromium-security/corb-for-developers
// http://stackoverflow.com/a/3146618/244009
resp.Header().Set("x-content-type-options", "nosniff")
next.ServeHTTP(resp, req)
})
}
}
func buildAuthGroup() *auth.Group {
group := auth.NewGroup(
&auth.OAuth2{},
&auth.HTTPSign{},
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
)
if setting.Service.EnableReverseProxyAuth {
group.Add(&auth.ReverseProxy{})
}
return group
}

58
routers/hat/repo/tag.go Normal file
View File

@ -0,0 +1,58 @@
package repo
import (
"net/http"
"strings"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
)
func TagNameSet(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/tag_name_set repository repoTagNameSet
// ---
// summary: List a repository's tag name***
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: name
// in: query
// description: name of the tag
// type: string
// responses:
// "200":
// "$ref": "#/responses/BranchNameSet"
searchName := ctx.Params("name")
tags, err := ctx.Repo.GitRepo.GetTags(0, 0)
if err != nil {
ctx.ServerError("GetTags", err)
return
}
if searchName == "" {
ctx.JSON(http.StatusOK, tags)
} else {
var tagNameSet []string
for _, tag := range tags {
log.Info("tag is \n", tag)
if strings.Contains(tag, searchName) {
tagNameSet = append(tagNameSet, tag)
}
}
ctx.JSON(http.StatusOK, tagNameSet)
}
}

12
routers/init.go Normal file
View File

@ -0,0 +1,12 @@
package routers
import (
"code.gitea.io/gitea/modules/web"
api_hat "code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat"
)
func InitHatRouters(e *web.Route) *web.Route {
e.Mount("/api/hat", api_hat.Routers())
return e
}