git_file_handler.go

 1package http
 2
 3import (
 4	"bytes"
 5	"net/http"
 6	"time"
 7
 8	"github.com/gorilla/mux"
 9
10	"github.com/git-bug/git-bug/cache"
11	"github.com/git-bug/git-bug/repository"
12)
13
14// implement a http.Handler that will read and server git blob.
15//
16// Expected gorilla/mux parameters:
17//   - "owner" : ignored (reserved for future multi-owner support); "_" for local
18//   - "repo"  : the name of the repo, or "_" for the default one
19//   - "hash"  : the git hash of the file to retrieve
20type gitFileHandler struct {
21	mrc *cache.MultiRepoCache
22}
23
24func NewGitFileHandler(mrc *cache.MultiRepoCache) http.Handler {
25	return &gitFileHandler{mrc: mrc}
26}
27
28func (gfh *gitFileHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
29	var repo *cache.RepoCache
30	var err error
31
32	repoVar := mux.Vars(r)["repo"]
33	if repoVar == "_" {
34		repo, err = gfh.mrc.DefaultRepo()
35	} else {
36		repo, err = gfh.mrc.ResolveRepo(repoVar)
37	}
38
39	if err != nil {
40		http.Error(rw, "invalid repo reference", http.StatusBadRequest)
41		return
42	}
43
44	hash := repository.Hash(mux.Vars(r)["hash"])
45	if !hash.IsValid() {
46		http.Error(rw, "invalid git hash", http.StatusBadRequest)
47		return
48	}
49
50	// TODO: this mean that the whole file will be buffered in memory
51	// This can be a problem for big files. There might be a way around
52	// that by implementing a io.ReadSeeker that would read and discard
53	// data when a seek is called.
54	data, err := repo.ReadData(hash)
55	if err != nil {
56		http.Error(rw, err.Error(), http.StatusInternalServerError)
57		return
58	}
59
60	http.ServeContent(rw, r, "", time.Now(), bytes.NewReader(data))
61}