tangled
alpha
login
or
join now
zan.dev
/
core
forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
0
fork
atom
overview
issues
pulls
pipelines
knotserver: git: serve raw binary blobs
anirudh.fi
9 months ago
5e7fddf7
9fbb3c31
verified
This commit was signed with the committer's
known signature
.
anirudh.fi
SSH Key Fingerprint:
SHA256:cz35vdbiWEzCNEfuL9fMC2JVIhtXavXBHrRjv8gxpAk=
+68
-2
3 changed files
expand all
collapse all
unified
split
knotserver
git
git.go
handler.go
routes.go
+31
-1
knotserver/git/git.go
···
37
37
}
38
38
39
39
var (
40
40
-
ErrBinaryFile = fmt.Errorf("binary file")
40
40
+
ErrBinaryFile = fmt.Errorf("binary file")
41
41
+
ErrNotBinaryFile = fmt.Errorf("not binary file")
41
42
)
42
43
43
44
type GitRepo struct {
···
191
192
} else {
192
193
return "", ErrBinaryFile
193
194
}
195
195
+
}
196
196
+
197
197
+
func (g *GitRepo) BinContent(path string) ([]byte, error) {
198
198
+
c, err := g.r.CommitObject(g.h)
199
199
+
if err != nil {
200
200
+
return nil, fmt.Errorf("commit object: %w", err)
201
201
+
}
202
202
+
203
203
+
tree, err := c.Tree()
204
204
+
if err != nil {
205
205
+
return nil, fmt.Errorf("file tree: %w", err)
206
206
+
}
207
207
+
208
208
+
file, err := tree.File(path)
209
209
+
if err != nil {
210
210
+
return nil, err
211
211
+
}
212
212
+
213
213
+
isbin, _ := file.IsBinary()
214
214
+
if isbin {
215
215
+
reader, err := file.Reader()
216
216
+
if err != nil {
217
217
+
return nil, fmt.Errorf("opening file reader: %w", err)
218
218
+
}
219
219
+
defer reader.Close()
220
220
+
221
221
+
return io.ReadAll(reader)
222
222
+
}
223
223
+
return nil, ErrNotBinaryFile
194
224
}
195
225
196
226
func (g *GitRepo) Tags() ([]*TagReference, error) {
+1
knotserver/handler.go
···
100
100
101
101
r.Route("/blob/{ref}", func(r chi.Router) {
102
102
r.Get("/*", h.Blob)
103
103
+
r.Get("/raw/*", h.BlobRaw)
103
104
})
104
105
105
106
r.Get("/log/{ref}", h.Log)
+36
-1
knotserver/routes.go
···
194
194
return
195
195
}
196
196
197
197
+
func (h *Handle) BlobRaw(w http.ResponseWriter, r *http.Request) {
198
198
+
treePath := chi.URLParam(r, "*")
199
199
+
ref := chi.URLParam(r, "ref")
200
200
+
ref, _ = url.PathUnescape(ref)
201
201
+
202
202
+
l := h.l.With("handler", "BlobRaw", "ref", ref, "treePath", treePath)
203
203
+
204
204
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
205
205
+
gr, err := git.Open(path, ref)
206
206
+
if err != nil {
207
207
+
notFound(w)
208
208
+
return
209
209
+
}
210
210
+
211
211
+
contents, err := gr.BinContent(treePath)
212
212
+
if err != nil {
213
213
+
writeError(w, err.Error(), http.StatusBadRequest)
214
214
+
l.Error("file content", "error", err.Error())
215
215
+
return
216
216
+
}
217
217
+
218
218
+
mimeType := http.DetectContentType(contents)
219
219
+
220
220
+
if !strings.HasPrefix(mimeType, "image/") && !strings.HasPrefix(mimeType, "video/") {
221
221
+
l.Error("attempted to serve non-image/video file", "mimetype", mimeType)
222
222
+
writeError(w, "only image and video files can be accessed directly", http.StatusForbidden)
223
223
+
return
224
224
+
}
225
225
+
226
226
+
w.Header().Set("Cache-Control", "public, max-age=86400") // cache for 24 hours
227
227
+
w.Header().Set("ETag", fmt.Sprintf("%x", sha256.Sum256(contents)))
228
228
+
w.Header().Set("Content-Type", mimeType)
229
229
+
w.Write(contents)
230
230
+
}
231
231
+
197
232
func (h *Handle) Blob(w http.ResponseWriter, r *http.Request) {
198
233
treePath := chi.URLParam(r, "*")
199
234
ref := chi.URLParam(r, "ref")
200
235
ref, _ = url.PathUnescape(ref)
201
236
202
202
-
l := h.l.With("handler", "FileContent", "ref", ref, "treePath", treePath)
237
237
+
l := h.l.With("handler", "Blob", "ref", ref, "treePath", treePath)
203
238
204
239
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
205
240
gr, err := git.Open(path, ref)