mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-24 19:06:22 +02:00
fix git service handling
This commit is contained in:
parent
be3f7790d1
commit
f8b418d07d
@ -10,10 +10,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func addOwnerRepoGitHTTPRouters(m *web.Router) {
|
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.Group("/{username}/{reponame}", func() {
|
||||||
m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
|
m.Methods("POST,OPTIONS", "/git-upload-pack", presetGitService("git-upload-pack"), repo.ServiceUploadPack)
|
||||||
m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
|
m.Methods("POST,OPTIONS", "/git-receive-pack", presetGitService("git-receive-pack"), repo.ServiceReceivePack)
|
||||||
m.Methods("POST,OPTIONS", "/git-upload-archive", repo.ServiceUploadArchive)
|
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", "/info/refs", repo.GetInfoRefs)
|
||||||
m.Methods("GET,OPTIONS", "/HEAD", repo.GetTextFile("HEAD"))
|
m.Methods("GET,OPTIONS", "/HEAD", repo.GetTextFile("HEAD"))
|
||||||
m.Methods("GET,OPTIONS", "/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
|
m.Methods("GET,OPTIONS", "/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
|
||||||
|
|||||||
@ -66,16 +66,13 @@ func httpBase(ctx *context.Context) *serviceHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isPull, receivePack bool
|
var isPull, receivePack bool
|
||||||
service := ctx.FormString("service")
|
gitService := ctx.FormString("service", ctx.PathParam("preset-git-service"))
|
||||||
if service == "git-receive-pack" ||
|
if gitService == "git-receive-pack" {
|
||||||
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
|
|
||||||
isPull = false
|
isPull = false
|
||||||
receivePack = true
|
receivePack = true
|
||||||
} else if service == "git-upload-pack" ||
|
} else if gitService == "git-upload-pack" {
|
||||||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
|
|
||||||
isPull = true
|
isPull = true
|
||||||
} else if service == "git-upload-archive" ||
|
} else if gitService == "git-upload-archive" {
|
||||||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
|
|
||||||
isPull = true
|
isPull = true
|
||||||
} else {
|
} else {
|
||||||
isPull = ctx.Req.Method == http.MethodHead || ctx.Req.Method == http.MethodGet
|
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
|
// 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]+)*$`)
|
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) {
|
func prepareGitCmdWithAllowedService(service string, allowedServices []string) *gitcmd.Command {
|
||||||
if service == ServiceTypeReceivePack {
|
if !slices.Contains(allowedServices, service) {
|
||||||
return gitcmd.NewCommand(ServiceTypeReceivePack), nil
|
return nil
|
||||||
}
|
}
|
||||||
if service == ServiceTypeUploadPack {
|
switch service {
|
||||||
return gitcmd.NewCommand(ServiceTypeUploadPack), nil
|
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) {
|
func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
|
||||||
defer func() {
|
defer ctx.Req.Body.Close()
|
||||||
if err := ctx.Req.Body.Close(); err != nil {
|
|
||||||
log.Error("serviceRPC: Close: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
expectedContentType := fmt.Sprintf("application/x-git-%s-request", service)
|
expectedContentType := fmt.Sprintf("application/x-git-%s-request", service)
|
||||||
if ctx.Req.Header.Get("Content-Type") != expectedContentType {
|
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)
|
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.StatusBadRequest)
|
||||||
ctx.Resp.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd, err := prepareGitCmdWithAllowedService(service)
|
cmd := prepareGitCmdWithAllowedService(service, []string{ServiceTypeUploadPack, ServiceTypeReceivePack, ServiceTypeUploadArchive})
|
||||||
if err != nil {
|
if cmd == nil {
|
||||||
log.Error("Failed to prepareGitCmdWithService: %v", err)
|
ctx.Resp.WriteHeader(http.StatusBadRequest)
|
||||||
// FIXME: why it's 401 if the service type doesn't supported?
|
|
||||||
ctx.Resp.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,10 +415,10 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
|
|||||||
|
|
||||||
// Handle GZIP.
|
// Handle GZIP.
|
||||||
if ctx.Req.Header.Get("Content-Encoding") == "gzip" {
|
if ctx.Req.Header.Get("Content-Encoding") == "gzip" {
|
||||||
|
var err error
|
||||||
reqBody, err = gzip.NewReader(reqBody)
|
reqBody, err = gzip.NewReader(reqBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Fail to create gzip reader: %v", err)
|
ctx.Resp.WriteHeader(http.StatusBadRequest)
|
||||||
ctx.Resp.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,7 +431,7 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
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 {
|
if service == ServiceTypeUploadArchive || service == ServiceTypeReceivePack {
|
||||||
cmd.AddArguments("--stateless-rpc")
|
cmd.AddArguments("--stateless-rpc")
|
||||||
}
|
}
|
||||||
@ -484,7 +477,8 @@ func ServiceReceivePack(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getServiceType(ctx *context.Context) string {
|
func getServiceType(ctx *context.Context) string {
|
||||||
switch ctx.Req.FormValue("service") {
|
gitService := ctx.Req.FormValue("service")
|
||||||
|
switch gitService {
|
||||||
case "git-" + ServiceTypeUploadPack:
|
case "git-" + ServiceTypeUploadPack:
|
||||||
return ServiceTypeUploadPack
|
return ServiceTypeUploadPack
|
||||||
case "git-" + ServiceTypeReceivePack:
|
case "git-" + ServiceTypeReceivePack:
|
||||||
@ -511,12 +505,8 @@ func GetInfoRefs(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
setHeaderNoCache(ctx)
|
setHeaderNoCache(ctx)
|
||||||
service := getServiceType(ctx)
|
service := getServiceType(ctx)
|
||||||
if !(service == ServiceTypeUploadPack || service == ServiceTypeReceivePack) {
|
cmd := prepareGitCmdWithAllowedService(service, []string{ServiceTypeUploadPack, ServiceTypeReceivePack})
|
||||||
ctx.Resp.WriteHeader(http.StatusBadRequest)
|
if cmd != nil {
|
||||||
return
|
|
||||||
}
|
|
||||||
cmd, err := prepareGitCmdWithAllowedService(service)
|
|
||||||
if err == nil {
|
|
||||||
if protocol := ctx.Req.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) {
|
if protocol := ctx.Req.Header.Get("Git-Protocol"); protocol != "" && safeGitProtocolHeader.MatchString(protocol) {
|
||||||
h.environ = append(h.environ, "GIT_PROTOCOL="+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(packetWrite("# service=git-" + service + "\n"))
|
||||||
_, _ = ctx.Resp.Write([]byte("0000"))
|
_, _ = ctx.Resp.Write([]byte("0000"))
|
||||||
_, _ = ctx.Resp.Write(refs)
|
_, _ = ctx.Resp.Write(refs)
|
||||||
} else {
|
} else if service == "" {
|
||||||
if err := gitrepo.UpdateServerInfo(ctx, h.getStorageRepo()); err != nil {
|
if err := gitrepo.UpdateServerInfo(ctx, h.getStorageRepo()); err != nil {
|
||||||
log.Error("Failed to update server info: %v", err)
|
log.Error("Failed to update server info: %v", err)
|
||||||
}
|
}
|
||||||
h.sendFile(ctx, "text/plain; charset=utf-8", "info/refs")
|
h.sendFile(ctx, "text/plain; charset=utf-8", "info/refs")
|
||||||
|
} else {
|
||||||
|
ctx.Resp.WriteHeader(http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user