1package http
2
3import (
4 "encoding/json"
5 "io"
6 "net/http"
7
8 "github.com/gorilla/mux"
9
10 "github.com/git-bug/git-bug/cache"
11)
12
13// implement a http.Handler that will accept and store content into git blob.
14//
15// Expected gorilla/mux parameters:
16// - "owner" : ignored (reserved for future multi-owner support); "_" for local
17// - "repo" : the name of the repo, or "_" for the default one
18type gitUploadFileHandler struct {
19 mrc *cache.MultiRepoCache
20}
21
22func NewGitUploadFileHandler(mrc *cache.MultiRepoCache) http.Handler {
23 return &gitUploadFileHandler{mrc: mrc}
24}
25
26func (gufh *gitUploadFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
27 var repo *cache.RepoCache
28 var err error
29
30 repoVar := mux.Vars(r)["repo"]
31 if repoVar == "_" {
32 repo, err = gufh.mrc.DefaultRepo()
33 } else {
34 repo, err = gufh.mrc.ResolveRepo(repoVar)
35 }
36
37 if err != nil {
38 http.Error(rw, "invalid repo reference", http.StatusBadRequest)
39 return
40 }
41
42 // 100MB (github limit)
43 var maxUploadSize int64 = 100 * 1000 * 1000
44 r.Body = http.MaxBytesReader(rw, r.Body, maxUploadSize)
45 if err := r.ParseMultipartForm(maxUploadSize); err != nil {
46 http.Error(rw, "file too big (100MB max)", http.StatusBadRequest)
47 return
48 }
49
50 file, _, err := r.FormFile("uploadfile")
51 if err != nil {
52 http.Error(rw, "invalid file", http.StatusBadRequest)
53 return
54 }
55 defer file.Close()
56 fileBytes, err := io.ReadAll(file)
57 if err != nil {
58 http.Error(rw, "invalid file", http.StatusBadRequest)
59 return
60 }
61
62 filetype := http.DetectContentType(fileBytes)
63 if filetype != "image/jpeg" && filetype != "image/jpg" &&
64 filetype != "image/gif" && filetype != "image/png" {
65 http.Error(rw, "invalid file type", http.StatusBadRequest)
66 return
67 }
68
69 hash, err := repo.StoreData(fileBytes)
70 if err != nil {
71 http.Error(rw, err.Error(), http.StatusInternalServerError)
72 return
73 }
74
75 type response struct {
76 Hash string `json:"hash"`
77 }
78
79 resp := response{Hash: string(hash)}
80
81 js, err := json.Marshal(resp)
82 if err != nil {
83 http.Error(rw, err.Error(), http.StatusInternalServerError)
84 return
85 }
86
87 rw.Header().Set("Content-Type", "application/json")
88 _, err = rw.Write(js)
89 if err != nil {
90 http.Error(rw, err.Error(), http.StatusInternalServerError)
91 return
92 }
93}