106 lines
2.3 KiB
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()
|
|
}
|
|
}
|