55package repo
66
77import (
8- "bytes"
98 "compress/gzip"
10- gocontext "context"
119 "fmt"
1210 "net/http"
1311 "os"
14- "path/filepath"
1512 "regexp"
1613 "slices"
1714 "strconv"
@@ -26,6 +23,7 @@ import (
2623 repo_model "code.gitea.io/gitea/models/repo"
2724 "code.gitea.io/gitea/models/unit"
2825 "code.gitea.io/gitea/modules/git"
26+ "code.gitea.io/gitea/modules/gitrepo"
2927 "code.gitea.io/gitea/modules/log"
3028 repo_module "code.gitea.io/gitea/modules/repository"
3129 "code.gitea.io/gitea/modules/setting"
@@ -339,11 +337,11 @@ type serviceHandler struct {
339337 environ []string
340338}
341339
342- func (h * serviceHandler ) getRepoDir () string {
340+ func (h * serviceHandler ) getStorageRepo () gitrepo. Repository {
343341 if h .isWiki {
344- return h .repo .WikiPath ()
342+ return h .repo .WikiStorageRepo ()
345343 }
346- return h .repo . RepoPath ()
344+ return h .repo
347345}
348346
349347func setHeaderNoCache (ctx * context.Context ) {
@@ -375,9 +373,16 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
375373 ctx .Resp .WriteHeader (http .StatusBadRequest )
376374 return
377375 }
378- reqFile := filepath .Join (h .getRepoDir (), file )
379376
380- fi , err := os .Stat (reqFile )
377+ fs := gitrepo .GetRepoFS (h .getStorageRepo ())
378+ f , err := fs .Open (file )
379+ if err != nil {
380+ log .Error ("Failed to open file: %v" , err )
381+ return
382+ }
383+ defer f .Close ()
384+
385+ fi , err := f .Stat ()
381386 if os .IsNotExist (err ) {
382387 ctx .Resp .WriteHeader (http .StatusNotFound )
383388 return
@@ -387,23 +392,12 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
387392 ctx .Resp .Header ().Set ("Content-Length" , strconv .FormatInt (fi .Size (), 10 ))
388393 // http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
389394 ctx .Resp .Header ().Set ("Last-Modified" , fi .ModTime ().UTC ().Format (http .TimeFormat ))
390- http .ServeFile (ctx .Resp , ctx .Req , reqFile )
395+ http .ServeFileFS (ctx .Resp , ctx .Req , fs , file )
391396}
392397
393398// one or more key=value pairs separated by colons
394399var safeGitProtocolHeader = regexp .MustCompile (`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$` )
395400
396- func prepareGitCmdWithAllowedService (service string ) (* git.Command , error ) {
397- if service == "receive-pack" {
398- return git .NewCommand ("receive-pack" ), nil
399- }
400- if service == "upload-pack" {
401- return git .NewCommand ("upload-pack" ), nil
402- }
403-
404- return nil , fmt .Errorf ("service %q is not allowed" , service )
405- }
406-
407401func serviceRPC (ctx * context.Context , h * serviceHandler , service string ) {
408402 defer func () {
409403 if err := ctx .Req .Body .Close (); err != nil {
@@ -418,17 +412,16 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
418412 return
419413 }
420414
421- cmd , err := prepareGitCmdWithAllowedService (service )
422- if err != nil {
423- log .Error ("Failed to prepareGitCmdWithService: %v" , err )
415+ if service != "upload-pack" && service != "receive-pack" {
416+ log .Error ("Invalid service: %q" , service )
424417 ctx .Resp .WriteHeader (http .StatusUnauthorized )
425418 return
426419 }
427420
428421 ctx .Resp .Header ().Set ("Content-Type" , fmt .Sprintf ("application/x-git-%s-result" , service ))
429422
430423 reqBody := ctx .Req .Body
431-
424+ var err error
432425 // Handle GZIP.
433426 if ctx .Req .Header .Get ("Content-Encoding" ) == "gzip" {
434427 reqBody , err = gzip .NewReader (reqBody )
@@ -446,18 +439,9 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
446439 h .environ = append (h .environ , "GIT_PROTOCOL=" + protocol )
447440 }
448441
449- var stderr bytes.Buffer
450- cmd .AddArguments ("--stateless-rpc" ).AddDynamicArguments (h .getRepoDir ())
451- if err := cmd .Run (ctx , & git.RunOpts {
452- Dir : h .getRepoDir (),
453- Env : append (os .Environ (), h .environ ... ),
454- Stdout : ctx .Resp ,
455- Stdin : reqBody ,
456- Stderr : & stderr ,
457- UseContextTimeout : true ,
458- }); err != nil {
442+ if stderr , err := gitrepo .StatelessRPC (ctx , h .getStorageRepo (), service , h .environ , reqBody , ctx .Resp ); err != nil {
459443 if ! git .IsErrCanceledOrKilled (err ) {
460- log .Error ("Fail to serve RPC(%s) in %s: %v - %s" , service , h .getRepoDir () , err , stderr . String () )
444+ log .Error ("Fail to serve RPC(%s) in %s: %v - %s" , service , h .getStorageRepo (). RelativePath () , err , stderr )
461445 }
462446 return
463447 }
@@ -487,14 +471,6 @@ func getServiceType(ctx *context.Context) string {
487471 return strings .TrimPrefix (serviceType , "git-" )
488472}
489473
490- func updateServerInfo (ctx gocontext.Context , dir string ) []byte {
491- out , _ , err := git .NewCommand ("update-server-info" ).RunStdBytes (ctx , & git.RunOpts {Dir : dir })
492- if err != nil {
493- log .Error (fmt .Sprintf ("%v - %s" , err , string (out )))
494- }
495- return out
496- }
497-
498474func packetWrite (str string ) []byte {
499475 s := strconv .FormatInt (int64 (len (str )+ 4 ), 16 )
500476 if len (s )% 4 != 0 {
@@ -511,14 +487,12 @@ func GetInfoRefs(ctx *context.Context) {
511487 }
512488 setHeaderNoCache (ctx )
513489 service := getServiceType (ctx )
514- cmd , err := prepareGitCmdWithAllowedService (service )
515- if err == nil {
490+ if service == "upload-pack" || service == "receive-pack" {
516491 if protocol := ctx .Req .Header .Get ("Git-Protocol" ); protocol != "" && safeGitProtocolHeader .MatchString (protocol ) {
517492 h .environ = append (h .environ , "GIT_PROTOCOL=" + protocol )
518493 }
519- h .environ = append (os .Environ (), h .environ ... )
520494
521- refs , _ , err := cmd . AddArguments ( "--stateless-rpc" , "--advertise-refs" , "." ). RunStdBytes ( ctx , & git. RunOpts { Env : h . environ , Dir : h . getRepoDir ()} )
495+ refs , err := gitrepo . StatelessRPCAdvertiseRefs ( ctx , h . getStorageRepo (), service , h . environ )
522496 if err != nil {
523497 log .Error (fmt .Sprintf ("%v - %s" , err , string (refs )))
524498 }
@@ -529,7 +503,9 @@ func GetInfoRefs(ctx *context.Context) {
529503 _ , _ = ctx .Resp .Write ([]byte ("0000" ))
530504 _ , _ = ctx .Resp .Write (refs )
531505 } else {
532- updateServerInfo (ctx , h .getRepoDir ())
506+ if err := gitrepo .UpdateServerInfo (ctx , h .getStorageRepo ()); err != nil {
507+ log .Error ("Failed to update server info: %v" , err )
508+ }
533509 h .sendFile (ctx , "text/plain; charset=utf-8" , "info/refs" )
534510 }
535511}
0 commit comments