Goit

Simple and lightweight Git web server
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

Goit/src/repo/download.go (150 lines, 3.6 KiB) -rw-r--r-- file download

c2c5250 Jakob Wakeling 2023-12-12 09:13:37
0
// Copyright (C) 2023, Jakob Wakeling
c2c5250 Jakob Wakeling 2023-12-12 09:13:37
1
// All rights reserved.
c2c5250 Jakob Wakeling 2023-12-12 09:13:37
2
b4de626 Jakob Wakeling 2023-11-16 23:06:56
3
package repo
b4de626 Jakob Wakeling 2023-11-16 23:06:56
4
b4de626 Jakob Wakeling 2023-11-16 23:06:56
5
import (
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
6
	"archive/zip"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
7
	"errors"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
8
	"fmt"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
9
	"io"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
10
	"log"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
11
	"net/http"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
12
	"path/filepath"
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
13
	"strings"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
14
b4de626 Jakob Wakeling 2023-11-16 23:06:56
15
	"github.com/Jamozed/Goit/src/goit"
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
16
	"github.com/Jamozed/Goit/src/util"
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
17
	"github.com/go-chi/chi/v5"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
18
	"github.com/go-git/go-git/v5"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
19
	"github.com/go-git/go-git/v5/plumbing"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
20
	"github.com/go-git/go-git/v5/plumbing/object"
b4de626 Jakob Wakeling 2023-11-16 23:06:56
21
)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
22
b4de626 Jakob Wakeling 2023-11-16 23:06:56
23
func HandleDownload(w http.ResponseWriter, r *http.Request) {
b4de626 Jakob Wakeling 2023-11-16 23:06:56
24
	auth, user, err := goit.Auth(w, r, true)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
25
	if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
26
		log.Println("[repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
27
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
28
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
29
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
30
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
31
	tpath := chi.URLParam(r, "*")
b4de626 Jakob Wakeling 2023-11-16 23:06:56
32
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
33
	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
b4de626 Jakob Wakeling 2023-11-16 23:06:56
34
	if err != nil {
b4de626 Jakob Wakeling 2023-11-16 23:06:56
35
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
36
		return
778d467 Jakob Wakeling 2024-01-17 18:29:55
37
	} else if repo == nil || !goit.IsVisible(repo, auth, user) {
b4de626 Jakob Wakeling 2023-11-16 23:06:56
38
		goit.HttpError(w, http.StatusNotFound)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
39
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
40
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
41
b4de626 Jakob Wakeling 2023-11-16 23:06:56
42
	gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true))
b4de626 Jakob Wakeling 2023-11-16 23:06:56
43
	if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
44
		log.Println("[/repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
45
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
46
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
47
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
48
b4de626 Jakob Wakeling 2023-11-16 23:06:56
49
	ref, err := gr.Head()
b4de626 Jakob Wakeling 2023-11-16 23:06:56
50
	if errors.Is(err, plumbing.ErrReferenceNotFound) {
b4de626 Jakob Wakeling 2023-11-16 23:06:56
51
		goit.HttpError(w, http.StatusNotFound)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
52
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
53
	} else if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
54
		log.Println("[/repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
55
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
56
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
57
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
58
b4de626 Jakob Wakeling 2023-11-16 23:06:56
59
	commit, err := gr.CommitObject(ref.Hash())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
60
	if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
61
		log.Println("[/repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
62
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
63
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
64
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
65
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
66
	file, err := commit.File(tpath)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
67
	if errors.Is(err, object.ErrFileNotFound) {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
68
		/* Possibly a directory, search file tree for prefix */
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
69
		var files []string
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
70
		var zSize uint64
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
71
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
72
		iter, err := commit.Files()
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
73
		if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
74
			log.Println("[/repo/download]", err.Error())
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
75
			goit.HttpError(w, http.StatusInternalServerError)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
76
			return
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
77
		}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
78
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
79
		iter.ForEach(func(f *object.File) error {
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
80
			if tpath == "" || strings.HasPrefix(f.Name, tpath+"/") {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
81
				files = append(files, f.Name)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
82
				zSize += uint64(f.Size)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
83
			}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
84
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
85
			return nil
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
86
		})
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
87
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
88
		if len(files) == 0 {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
89
			goit.HttpError(w, http.StatusNotFound)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
90
			return
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
91
		}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
92
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
93
		/* Build and write ZIP of directory */
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
94
		w.Header().Set(
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
95
			"Content-Disposition", "attachment; filename="+util.If(tpath == "", repo.Name, filepath.Base(tpath))+".zip",
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
96
		)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
97
		// w.Header().Set("Content-Length", fmt.Sprint(zSize))
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
98
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
99
		z := zip.NewWriter(w)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
100
		for _, f := range files {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
101
			zh := zip.FileHeader{Name: f, Method: zip.Store}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
102
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
103
			zf, err := z.CreateHeader(&zh)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
104
			if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
105
				log.Println("[/repo/download]", err.Error())
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
106
				goit.HttpError(w, http.StatusInternalServerError)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
107
			}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
108
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
109
			if file, err := commit.File(f); err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
110
				log.Println("[/repo/download]", err.Error())
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
111
				goit.HttpError(w, http.StatusInternalServerError)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
112
				return
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
113
			} else if rc, err := file.Blob.Reader(); err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
114
				log.Println("[/repo/download]", err.Error())
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
115
				goit.HttpError(w, http.StatusInternalServerError)
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
116
				return
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
117
			} else {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
118
				if _, err := io.Copy(zf, rc); err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
119
					log.Println("[/repo/download]", err.Error())
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
120
				}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
121
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
122
				rc.Close()
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
123
			}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
124
		}
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
125
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
126
		z.Close()
b4de626 Jakob Wakeling 2023-11-16 23:06:56
127
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
128
	} else if err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
129
		log.Println("[/repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
130
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
131
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
132
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
133
b4de626 Jakob Wakeling 2023-11-16 23:06:56
134
	if rc, err := file.Blob.Reader(); err != nil {
7dd4459 Jakob Wakeling 2023-11-20 23:18:08
135
		log.Println("[/repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
136
		goit.HttpError(w, http.StatusInternalServerError)
b4de626 Jakob Wakeling 2023-11-16 23:06:56
137
		return
b4de626 Jakob Wakeling 2023-11-16 23:06:56
138
	} else {
3f4c3f4 Jakob Wakeling 2023-12-01 23:26:03
139
		w.Header().Set("Content-Disposition", "attachement; filename="+filepath.Base(tpath))
b4de626 Jakob Wakeling 2023-11-16 23:06:56
140
		w.Header().Set("Content-Length", fmt.Sprint(file.Size))
b4de626 Jakob Wakeling 2023-11-16 23:06:56
141
b4de626 Jakob Wakeling 2023-11-16 23:06:56
142
		if _, err := io.Copy(w, rc); err != nil {
b4de626 Jakob Wakeling 2023-11-16 23:06:56
143
			log.Println("[/repo/download]", err.Error())
b4de626 Jakob Wakeling 2023-11-16 23:06:56
144
		}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
145
b4de626 Jakob Wakeling 2023-11-16 23:06:56
146
		rc.Close()
b4de626 Jakob Wakeling 2023-11-16 23:06:56
147
	}
b4de626 Jakob Wakeling 2023-11-16 23:06:56
148
}
149