Skip to content

Commit 3521177

Browse files
jolheiserzeripath
authored andcommitted
Fix push-to-create (#9772) (#9797)
* Fix push-to-create Signed-off-by: jolheiser <[email protected]> * Check URL path and service Signed-off-by: jolheiser <[email protected]> * Send dummy payload on receive-pack GET Signed-off-by: jolheiser <[email protected]> * The space was actually a NUL byte Signed-off-by: jolheiser <[email protected]> * Use real bare repo instead of manufactured payload Signed-off-by: jolheiser <[email protected]> Co-authored-by: zeripath <[email protected]>
1 parent c8bb0ec commit 3521177

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

routers/repo/http.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010
"compress/gzip"
1111
gocontext "context"
1212
"fmt"
13+
"io/ioutil"
1314
"net/http"
1415
"os"
1516
"os/exec"
1617
"path"
1718
"regexp"
1819
"strconv"
1920
"strings"
21+
"sync"
2022
"time"
2123

2224
"code.gitea.io/gitea/models"
@@ -65,11 +67,12 @@ func HTTP(ctx *context.Context) {
6567
return
6668
}
6769

68-
var isPull bool
70+
var isPull, receivePack bool
6971
service := ctx.Query("service")
7072
if service == "git-receive-pack" ||
7173
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
7274
isPull = false
75+
receivePack = true
7376
} else if service == "git-upload-pack" ||
7477
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
7578
isPull = true
@@ -282,6 +285,11 @@ func HTTP(ctx *context.Context) {
282285
}
283286

284287
if !repoExist {
288+
if !receivePack {
289+
ctx.HandleText(http.StatusNotFound, "Repository not found")
290+
return
291+
}
292+
285293
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
286294
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
287295
return
@@ -290,6 +298,13 @@ func HTTP(ctx *context.Context) {
290298
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for users.")
291299
return
292300
}
301+
302+
// Return dummy payload if GET receive-pack
303+
if ctx.Req.Method == http.MethodGet {
304+
dummyInfoRefs(ctx)
305+
return
306+
}
307+
293308
repo, err = repo_service.PushCreateRepo(authUser, owner, reponame)
294309
if err != nil {
295310
log.Error("pushCreateRepo: %v", err)
@@ -352,6 +367,48 @@ func HTTP(ctx *context.Context) {
352367
ctx.NotFound("Smart Git HTTP", nil)
353368
}
354369

370+
var (
371+
infoRefsCache []byte
372+
infoRefsOnce sync.Once
373+
)
374+
375+
func dummyInfoRefs(ctx *context.Context) {
376+
infoRefsOnce.Do(func() {
377+
tmpDir, err := ioutil.TempDir(os.TempDir(), "gitea-info-refs-cache")
378+
if err != nil {
379+
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
380+
return
381+
}
382+
383+
defer func() {
384+
if err := os.RemoveAll(tmpDir); err != nil {
385+
log.Error("RemoveAll: %v", err)
386+
}
387+
}()
388+
389+
if err := git.InitRepository(tmpDir, true); err != nil {
390+
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
391+
return
392+
}
393+
394+
refs, err := git.NewCommand("receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(tmpDir)
395+
if err != nil {
396+
log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
397+
}
398+
399+
log.Debug("populating infoRefsCache: \n%s", string(refs))
400+
infoRefsCache = refs
401+
})
402+
403+
ctx.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
404+
ctx.Header().Set("Pragma", "no-cache")
405+
ctx.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
406+
ctx.Header().Set("Content-Type", "application/x-git-receive-pack-advertisement")
407+
_, _ = ctx.Write(packetWrite("# service=git-receive-pack\n"))
408+
_, _ = ctx.Write([]byte("0000"))
409+
_, _ = ctx.Write(infoRefsCache)
410+
}
411+
355412
type serviceConfig struct {
356413
UploadPack bool
357414
ReceivePack bool

0 commit comments

Comments
 (0)