Files
codit/backend/internal/git/http.go

106 lines
2.3 KiB
Go

package git
import "codit/internal/util"
import "net/http"
import "os"
import "path/filepath"
import "strings"
import "github.com/sosedoff/gitkit"
type HTTPServer struct {
handler http.Handler
baseDir string
logger *util.Logger
}
type AuthFunc func(username, password string) (bool, error)
func NewHTTPServer(baseDir string, auth AuthFunc, logger *util.Logger) (*HTTPServer, error) {
var cfg gitkit.Config
var srv *gitkit.Server
cfg = gitkit.Config{
Dir: baseDir,
AutoCreate: false,
Auth: auth != nil,
}
srv = gitkit.New(cfg)
srv.AuthFunc = func(cred gitkit.Credential, _ *gitkit.Request) (bool, error) {
if auth == nil {
return true, nil
}
return auth(cred.Username, cred.Password)
}
return &HTTPServer{handler: srv, baseDir: baseDir, logger: logger}, nil
}
func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var repoPath string
var err error
var recorder *statusRecorder
var userLabel string
var username string
var ok bool
userLabel = "-"
recorder = &statusRecorder{ResponseWriter: w, status: http.StatusOK}
repoPath = s.repoPathFromRequest(r)
if repoPath != "" {
_, err = os.Stat(repoPath)
if err == nil {
_ = EnsureHead(repoPath)
}
}
if r != nil {
username, _, ok = r.BasicAuth()
if ok && username != "" {
userLabel = username
}
}
s.handler.ServeHTTP(recorder, r)
if s.logger != nil {
s.logger.Write(
"git", util.LOG_INFO, "method=%s path=%s remote=%s user=%s status=%d\n",
r.Method, r.URL.Path, r.RemoteAddr, userLabel, recorder.status)
}
}
func (s *HTTPServer) repoPathFromRequest(r *http.Request) string {
var path string
var suffixes []string
var i int
var suffix string
path = r.URL.Path
suffixes = []string{"/info/refs", "/git-upload-pack", "/git-receive-pack"}
for i = 0; i < len(suffixes); i++ {
suffix = suffixes[i]
if strings.HasSuffix(path, suffix) {
path = strings.TrimSuffix(path, suffix)
break
}
}
path = strings.Trim(path, "/")
if path == "" {
return ""
}
return filepath.Join(s.baseDir, filepath.FromSlash(path))
}
type statusRecorder struct {
http.ResponseWriter
status int
}
func (r *statusRecorder) WriteHeader(code int) {
r.status = code
r.ResponseWriter.WriteHeader(code)
}
func (r *statusRecorder) Flush() {
var flusher http.Flusher
var ok bool
flusher, ok = r.ResponseWriter.(http.Flusher)
if ok {
flusher.Flush()
}
}