Skip to content
1 change: 1 addition & 0 deletions routers/web/githttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func addOwnerRepoGitHTTPRouters(m *web.Router) {
m.Group("/{username}/{reponame}", func() {
m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
m.Post("/git-upload-archive", repo.ServiceUploadArchive)
Comment thread
TheFox0x7 marked this conversation as resolved.
Outdated
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"))
Expand Down
23 changes: 19 additions & 4 deletions routers/web/repo/githttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@ func prepareGitCmdWithAllowedService(service string) (*gitcmd.Command, error) {
if service == ServiceTypeUploadPack {
return gitcmd.NewCommand(ServiceTypeUploadPack), nil
}
if service == ServiceTypeUploadArchive {
return gitcmd.NewCommand(ServiceTypeUploadArchive), nil
}
Comment thread
wxiaoguang marked this conversation as resolved.
return nil, fmt.Errorf("service %q is not allowed", service)
}

Expand Down Expand Up @@ -435,7 +438,10 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
}

var stderr bytes.Buffer
if err := gitrepo.RunCmd(ctx, h.getStorageRepo(), cmd.AddArguments("--stateless-rpc", ".").
if service != ServiceTypeUploadArchive {
Comment thread
TheFox0x7 marked this conversation as resolved.
Outdated
cmd.AddArguments("--stateless-rpc")
}
if err := gitrepo.RunCmd(ctx, h.getStorageRepo(), cmd.AddArguments(".").
WithEnv(append(os.Environ(), h.environ...)).
WithStderr(&stderr).
WithStdin(reqBody).
Expand All @@ -444,13 +450,13 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
if !git.IsErrCanceledOrKilled(err) {
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.getStorageRepo().RelativePath(), err, stderr.String())
}
return
}
}

const (
ServiceTypeUploadPack = "upload-pack"
ServiceTypeReceivePack = "receive-pack"
ServiceTypeUploadPack = "upload-pack"
ServiceTypeReceivePack = "receive-pack"
ServiceTypeUploadArchive = "upload-archive"
)

// ServiceUploadPack implements Git Smart HTTP protocol
Expand All @@ -461,6 +467,13 @@ func ServiceUploadPack(ctx *context.Context) {
}
}

func ServiceUploadArchive(ctx *context.Context) {
h := httpBase(ctx)
if h != nil {
serviceRPC(ctx, h, ServiceTypeUploadArchive)
}
}

// ServiceReceivePack implements Git Smart HTTP protocol
func ServiceReceivePack(ctx *context.Context) {
h := httpBase(ctx)
Expand All @@ -475,6 +488,8 @@ func getServiceType(ctx *context.Context) string {
return ServiceTypeUploadPack
case "git-" + ServiceTypeReceivePack:
return ServiceTypeReceivePack
case "git-" + ServiceTypeUploadArchive:
return ServiceTypeUploadArchive
}
return ""
}
Expand Down
12 changes: 12 additions & 0 deletions tests/integration/git_helper_for_declarative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,15 @@ func doGitPull(dstPath string, args ...string) func(*testing.T) {
assert.NoError(t, err)
}
}

// doGitRemoteArchive runs a git archive command requesting an archive from remote
// and verifies that the command did not error out and returned only normal output
func doGitRemoteArchive(remote string, args ...string) func(*testing.T) {
return func(t *testing.T) {
stdout, stderr, err := gitcmd.NewCommand("archive").AddOptionValues("--remote", remote).AddArguments(gitcmd.ToTrustedCmdArgs(args)...).
RunStdString(t.Context())
require.NoError(t, err)
assert.Empty(t, stderr)
assert.NotEmpty(t, stdout)
}
}
8 changes: 8 additions & 0 deletions tests/integration/git_smart_http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func TestGitSmartHTTP(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
testGitSmartHTTP(t, u)
testRenamedRepoRedirect(t)
testGitArchiveRemote(t, u)
})
}

Expand Down Expand Up @@ -96,3 +97,10 @@ func testRenamedRepoRedirect(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), "65f1bf27bc3bf70f64657658635e66094edbcb4d\trefs/tags/v1.1")
}

func testGitArchiveRemote(t *testing.T, u *url.URL) {
u = u.JoinPath("user27/repo49.git")
t.Run("Fetch HEAD archive", doGitRemoteArchive(u.String(), "HEAD"))
t.Run("Fetch HEAD archive subpath", doGitRemoteArchive(u.String(), "HEAD", "test"))
t.Run("list compression options", doGitRemoteArchive(u.String(), "--list"))
}