0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-01-19 03:22:44 +01:00

fix git service handling

This commit is contained in:
wxiaoguang 2026-01-17 19:40:57 +08:00
parent be3f7790d1
commit f8b418d07d
2 changed files with 37 additions and 42 deletions

View File

@ -10,10 +10,13 @@ import (
)
func addOwnerRepoGitHTTPRouters(m *web.Router) {
presetGitService := func(service string) func(ctx *context.Context) {
return func(ctx *context.Context) { ctx.SetPathParam("preset-git-service", service) }
}
m.Group("/{username}/{reponame}", func() {
m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
m.Methods("POST,OPTIONS", "/git-upload-archive", repo.ServiceUploadArchive)
m.Methods("POST,OPTIONS", "/git-upload-pack", presetGitService("git-upload-pack"), repo.ServiceUploadPack)
m.Methods("POST,OPTIONS", "/git-receive-pack", presetGitService("git-receive-pack"), repo.ServiceReceivePack)
m.Methods("POST,OPTIONS", "/git-upload-archive", presetGitService("git-upload-archive"), repo.ServiceUploadArchive)
m.Methods("GET,OPTIONS", "/info/refs", repo.GetInfoRefs)
m.Methods("GET,OPTIONS", "/HEAD", repo.GetTextFile("HEAD"))
m.Methods("GET,OPTIONS", "/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))

View File

@ -66,16 +66,13 @@ func httpBase(ctx *context.Context) *serviceHandler {
}
var isPull, receivePack bool
service := ctx.FormString("service")
if service == "git-receive-pack" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
gitService := ctx.FormString("service", ctx.PathParam("preset-git-service"))
if gitService == "git-receive-pack" {
isPull = false
receivePack = true
} else if service == "git-upload-pack" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
} else if gitService == "git-upload-pack" {
isPull = true
} else if service == "git-upload-archive" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
} else if gitService == "git-upload-archive" {
isPull = true
} else {
isPull = ctx.Req.Method == http.MethodHead || ctx.Req.Method == http.MethodGet
@ -380,39 +377,35 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
// one or more key=value pairs separated by colons
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
func prepareGitCmdWithAllowedService(service string) (*gitcmd.Command, error) {
if service == ServiceTypeReceivePack {
return gitcmd.NewCommand(ServiceTypeReceivePack), nil
func prepareGitCmdWithAllowedService(service string, allowedServices []string) *gitcmd.Command {
if !slices.Contains(allowedServices, service) {
return nil
}
if service == ServiceTypeUploadPack {
return gitcmd.NewCommand(ServiceTypeUploadPack), nil
switch service {
case ServiceTypeReceivePack:
return gitcmd.NewCommand(ServiceTypeReceivePack)
case ServiceTypeUploadPack:
return gitcmd.NewCommand(ServiceTypeUploadPack)
case ServiceTypeUploadArchive:
return gitcmd.NewCommand(ServiceTypeUploadArchive)
default:
return nil
}
if service == ServiceTypeUploadArchive {
return gitcmd.NewCommand(ServiceTypeUploadArchive), nil
}
return nil, fmt.Errorf("service %q is not allowed", service)
}
func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
defer func() {
if err := ctx.Req.Body.Close(); err != nil {
log.Error("serviceRPC: Close: %v", err)
}
}()
defer ctx.Req.Body.Close()
expectedContentType := fmt.Sprintf("application/x-git-%s-request", service)
if ctx.Req.Header.Get("Content-Type") != expectedContentType {
log.Error("Content-Type (%q) doesn't match expected: %q", ctx.Req.Header.Get("Content-Type"), expectedContentType)
// FIXME: why it's 401 if the content type is unexpected?
ctx.Resp.WriteHeader(http.StatusUnauthorized)
ctx.Resp.WriteHeader(http.StatusBadRequest)
return
}
cmd, err := prepareGitCmdWithAllowedService(service)
if err != nil {
log.Error("Failed to prepareGitCmdWithService: %v", err)
// FIXME: why it's 401 if the service type doesn't supported?
ctx.Resp.WriteHeader(http.StatusUnauthorized)
cmd := prepareGitCmdWithAllowedService(service, []string{ServiceTypeUploadPack, ServiceTypeReceivePack, ServiceTypeUploadArchive})
if cmd == nil {
ctx.Resp.WriteHeader(http.StatusBadRequest)
return
}
@ -422,10 +415,10 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
// Handle GZIP.
if ctx.Req.Header.Get("Content-Encoding") == "gzip" {
var err error
reqBody, err = gzip.NewReader(reqBody)
if err != nil {
log.Error("Fail to create gzip reader: %v", err)
ctx.Resp.WriteHeader(http.StatusInternalServerError)
ctx.Resp.WriteHeader(http.StatusBadRequest)
return
}
}
@ -438,7 +431,7 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
}
var stderr bytes.Buffer
// git upload-archive does not have a -- stateless-rpc option
// git upload-archive does not have a "--stateless-rpc" option
if service == ServiceTypeUploadArchive || service == ServiceTypeReceivePack {
cmd.AddArguments("--stateless-rpc")
}
@ -484,7 +477,8 @@ func ServiceReceivePack(ctx *context.Context) {
}
func getServiceType(ctx *context.Context) string {
switch ctx.Req.FormValue("service") {
gitService := ctx.Req.FormValue("service")
switch gitService {
case "git-" + ServiceTypeUploadPack:
return ServiceTypeUploadPack
case "git-" + ServiceTypeReceivePack:
@ -511,12 +505,8 @@ func GetInfoRefs(ctx *context.Context) {
}
setHeaderNoCache(ctx)
service := getServiceType(ctx)
if !(service == ServiceTypeUploadPack || service == ServiceTypeReceivePack) {
ctx.Resp.WriteHeader(http.StatusBadRequest)
return
}
cmd, err := prepareGitCmdWithAllowedService(service)
if err == nil {
cmd := prepareGitCmdWithAllowedService(service, []string{ServiceTypeUploadPack, ServiceTypeReceivePack})
if cmd != nil {
if protocol := ctx.Req.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) {
h.environ = append(h.environ, "GIT_PROTOCOL="+protocol)
}
@ -533,11 +523,13 @@ func GetInfoRefs(ctx *context.Context) {
_, _ = ctx.Resp.Write(packetWrite("# service=git-" + service + "\n"))
_, _ = ctx.Resp.Write([]byte("0000"))
_, _ = ctx.Resp.Write(refs)
} else {
} else if service == "" {
if err := gitrepo.UpdateServerInfo(ctx, h.getStorageRepo()); err != nil {
log.Error("Failed to update server info: %v", err)
}
h.sendFile(ctx, "text/plain; charset=utf-8", "info/refs")
} else {
ctx.Resp.WriteHeader(http.StatusBadRequest)
}
}