Files
simplegit/gitrpc/binary.go
T
2026-07-29 06:51:43 -04:00

114 lines
2.5 KiB
Go

package gitrpc
import (
"errors"
"io"
"net/http"
)
func (s *Server) authorizeRead(w http.ResponseWriter, r *http.Request, repo string) bool {
if repo == "" {
http.Error(w, "missing repo", http.StatusBadRequest)
return false
}
// No local JWT/JWKS check: /raw, /archive, /patch are reached only via the
// console gateway (which authenticates the user) or internally. smart-HTTP
// clone/push auth lives in the daemon App (PAT-based), not here.
return true
}
func (s *Server) serveRaw(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
repoName := q.Get("repo")
if !s.authorizeRead(w, r, repoName) {
return
}
ref := q.Get("ref")
filePath := q.Get("file")
repo, err := s.open(r.Context(), repoName)
if err != nil {
writeHTTPError(w, err)
return
}
content, err := repo.GetRawContent(ref, filePath)
if err != nil {
http.Error(w, "read file: "+err.Error(), http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/octet-stream")
_, _ = io.WriteString(w, content)
}
func (s *Server) servePatch(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
repoName := q.Get("repo")
if !s.authorizeRead(w, r, repoName) {
return
}
sha := q.Get("sha")
repo, err := s.open(r.Context(), repoName)
if err != nil {
writeHTTPError(w, err)
return
}
patch, err := repo.Patch(sha)
if err != nil {
http.Error(w, "format-patch: "+err.Error(), http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
_, _ = io.WriteString(w, patch)
}
func (s *Server) serveArchive(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
repoName := q.Get("repo")
if !s.authorizeRead(w, r, repoName) {
return
}
ref := q.Get("ref")
format := q.Get("format")
repo, err := s.open(r.Context(), repoName)
if err != nil {
writeHTTPError(w, err)
return
}
if format == "" {
format = "zip"
}
switch format {
case "zip":
w.Header().Set("Content-Type", "application/zip")
case "tar":
w.Header().Set("Content-Type", "application/x-tar")
default:
http.Error(w, "format must be zip or tar", http.StatusBadRequest)
return
}
if err := repo.Archive(ref, format, w); err != nil {
http.Error(w, "archive: "+err.Error(), http.StatusInternalServerError)
return
}
}
func writeHTTPError(w http.ResponseWriter, err error) {
var re *rpcError
if errors.As(err, &re) {
switch re.Code {
case codeRepoNotFound:
http.Error(w, re.Message, http.StatusNotFound)
default:
http.Error(w, re.Message, http.StatusBadRequest)
}
return
}
http.Error(w, err.Error(), http.StatusBadRequest)
}