diff options
-rw-r--r-- | pkg/ext/auth.go | 22 | ||||
-rw-r--r-- | pkg/ext/compression.go | 31 | ||||
-rw-r--r-- | pkg/ext/log.go | 4 | ||||
-rw-r--r-- | pkg/ext/request.go | 14 | ||||
-rw-r--r-- | pkg/ext/router.go | 19 | ||||
-rw-r--r-- | pkg/git/git.go | 48 | ||||
-rw-r--r-- | pkg/handler/about/handler.go | 3 | ||||
-rw-r--r-- | pkg/handler/auth/login.go | 4 | ||||
-rw-r--r-- | pkg/handler/git/handler.go | 25 | ||||
-rw-r--r-- | pkg/handler/static/handler.go | 4 |
10 files changed, 110 insertions, 64 deletions
diff --git a/pkg/ext/auth.go b/pkg/ext/auth.go index 5c3070e..ef126ec 100644 --- a/pkg/ext/auth.go +++ b/pkg/ext/auth.go @@ -14,19 +14,20 @@ type authService interface { ValidateToken(token []byte) (bool, error) } -func DisableAuthentication(next http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func DisableAuthentication(next HandlerFunc) HandlerFunc { + return func(w http.ResponseWriter, r *Request) { ctx := r.Context() ctx = context.WithValue(ctx, "disableAuthentication", true) - next(w, r.WithContext(ctx)) + r.Request = r.WithContext(ctx) + next(w, r) } } func VerifyRespository( config *serverconfig.ConfigurationRepository, -) func(next http.HandlerFunc) http.HandlerFunc { - return func(next http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +) func(next HandlerFunc) HandlerFunc { + return func(next HandlerFunc) HandlerFunc { + return func(w http.ResponseWriter, r *Request) { name := r.PathValue("name") if name != "" { repo := config.GetByName(name) @@ -41,9 +42,9 @@ func VerifyRespository( } } -func Authenticate(auth authService) func(next http.HandlerFunc) http.HandlerFunc { - return func(next http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func Authenticate(auth authService) func(next HandlerFunc) HandlerFunc { + return func(next HandlerFunc) HandlerFunc { + return func(w http.ResponseWriter, r *Request) { cookie, err := r.Cookie("auth") if err != nil { if !errors.Is(err, http.ErrNoCookie) { @@ -70,9 +71,10 @@ func Authenticate(auth authService) func(next http.HandlerFunc) http.HandlerFunc ctx := r.Context() ctx = context.WithValue(ctx, "logged", valid) + r.Request = r.WithContext(ctx) slog.Info("Validated token", "valid?", valid) - next(w, r.WithContext(ctx)) + next(w, r) } } } diff --git a/pkg/ext/compression.go b/pkg/ext/compression.go index 6c7a219..d3a3df1 100644 --- a/pkg/ext/compression.go +++ b/pkg/ext/compression.go @@ -15,18 +15,37 @@ import ( "github.com/klauspost/compress/zstd" ) -var ( - errInvalidParam = errors.New("Invalid weighted param") -) +var errInvalidParam = errors.New("Invalid weighted param") type CompressionResponseWriter struct { innerWriter http.ResponseWriter compressWriter io.Writer } -func Compress(next http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func Compress(next HandlerFunc) HandlerFunc { + return func(w http.ResponseWriter, r *Request) { + // TODO: hand this better + if strings.HasSuffix(r.URL.Path, ".tar.gz") { + next(w, r) + return + } + + if accept, ok := r.Header["Accept-Encoding"]; ok { + if compress, algo := GetCompressionWriter(u.FirstOrZero(accept), w); algo != "" { + defer compress.Close() + w.Header().Add("Content-Encoding", algo) + w = &CompressionResponseWriter{ + innerWriter: w, + compressWriter: compress, + } + } + } + next(w, r) + } +} +func Decompress(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { // TODO: hand this better if strings.HasSuffix(r.URL.Path, ".tar.gz") { next(w, r) @@ -61,12 +80,12 @@ func GetCompressionWriter(header string, inner io.Writer) (io.WriteCloser, strin default: return nil, "" } - } func (c *CompressionResponseWriter) Header() http.Header { return c.innerWriter.Header() } + func (c *CompressionResponseWriter) Write(b []byte) (int, error) { return c.compressWriter.Write(b) } diff --git a/pkg/ext/log.go b/pkg/ext/log.go index 8e68134..e0ad89f 100644 --- a/pkg/ext/log.go +++ b/pkg/ext/log.go @@ -39,8 +39,8 @@ func wrap(w http.ResponseWriter) *statusWraper { } } -func Log(next http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func Log(next HandlerFunc) HandlerFunc { + return func(w http.ResponseWriter, r *Request) { t := time.Now() s := wrap(w) next(s, r) diff --git a/pkg/ext/request.go b/pkg/ext/request.go new file mode 100644 index 0000000..d1593b2 --- /dev/null +++ b/pkg/ext/request.go @@ -0,0 +1,14 @@ +package ext + +import ( + "io" + "net/http" +) + +type Request struct { + *http.Request +} + +func (r *Request) ReadBody() io.ReadCloser { + return r.Body +} diff --git a/pkg/ext/router.go b/pkg/ext/router.go index 434972b..bbbffa1 100644 --- a/pkg/ext/router.go +++ b/pkg/ext/router.go @@ -16,8 +16,9 @@ type ( middlewares []Middleware router *http.ServeMux } - Middleware func(next http.HandlerFunc) http.HandlerFunc - ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error + HandlerFunc func(http.ResponseWriter, *Request) + Middleware func(next HandlerFunc) HandlerFunc + ErrorRequestHandler func(w http.ResponseWriter, r *Request) error ) func NewRouter() *Router { @@ -34,15 +35,15 @@ func (r *Router) AddMiddleware(middleware Middleware) { r.middlewares = append(r.middlewares, middleware) } -func wrapError(next ErrorRequestHandler) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func wrapError(next ErrorRequestHandler) HandlerFunc { + return func(w http.ResponseWriter, r *Request) { if err := next(w, r); err != nil { if errors.Is(err, service.ErrRepositoryNotFound) || errors.Is(err, plumbing.ErrReferenceNotFound) { NotFound(w, r) } else { slog.Error("Internal Server Error", "error", err) - InternalServerError(r, w, err) + InternalServerError(w, r, err) } } } @@ -54,7 +55,7 @@ func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc { for _, r := range r.middlewares { req = r(req) } - req(w, re) + req(w, &Request{Request: re}) } } @@ -62,14 +63,14 @@ func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) { r.router.HandleFunc(path, r.run(handler)) } -func NotFound(w http.ResponseWriter, r *http.Request) { +func NotFound(w http.ResponseWriter, r *Request) { w.WriteHeader(http.StatusNotFound) templates.WritePageTemplate(w, &templates.ErrorPage{ Message: "Not Found", }, r.Context()) } -func BadRequest(w http.ResponseWriter, r *http.Request, msg string) { +func BadRequest(w http.ResponseWriter, r *Request, msg string) { w.WriteHeader(http.StatusBadRequest) templates.WritePageTemplate(w, &templates.ErrorPage{ Message: msg, @@ -81,7 +82,7 @@ func Redirect(w http.ResponseWriter, location string) { w.WriteHeader(http.StatusTemporaryRedirect) } -func InternalServerError(r *http.Request, w http.ResponseWriter, err error) { +func InternalServerError(w http.ResponseWriter, r *Request, err error) { w.WriteHeader(http.StatusInternalServerError) templates.WritePageTemplate(w, &templates.ErrorPage{ Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()), diff --git a/pkg/git/git.go b/pkg/git/git.go index 95355f3..83f3f93 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -8,12 +8,10 @@ import ( "fmt" "io" "io/fs" - "log" "log/slog" "os/exec" "path" "sort" - "syscall" "time" "github.com/go-git/go-git/v5" @@ -447,10 +445,14 @@ func (g *GitRepository) WriteInfoRefs(ctx context.Context, w io.Writer) error { ) cmd.Dir = g.path - cmd.Stdout = w + cmd.Env = []string{ + // TODO: get this from header. + "GIT_PROTOCOL=version=2", + } - var buff bytes.Buffer - cmd.Stderr = &buff + var errBuff bytes.Buffer + cmd.Stderr = &errBuff + cmd.Stdout = w err := packLine(w, "# service=git-upload-pack\n") if err != nil { @@ -464,7 +466,7 @@ func (g *GitRepository) WriteInfoRefs(ctx context.Context, w io.Writer) error { err = cmd.Run() if err != nil { - slog.Error("Error upload pack refs", "message", buff.String()) + slog.Error("Error upload pack refs", "message", errBuff.String()) return err } return nil @@ -478,19 +480,17 @@ func (g *GitRepository) WriteUploadPack(ctx context.Context, r io.Reader, w io.W ".", ) cmd.Dir = g.Path() - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - var buff bytes.Buffer - cmd.Stderr = &buff - cmd.Stdin = r - cmd.Stdout = w - - if err := cmd.Start(); err != nil { - log.Printf("git: failed to start git-upload-pack: %s", err) - return err + cmd.Env = []string{ + // TODO: get this from header. + "GIT_PROTOCOL=version=2", } + var errBuff bytes.Buffer + cmd.Stderr = &errBuff + cmd.Stdout = w + cmd.Stdin = r - if err := cmd.Wait(); err != nil { - log.Printf("git: failed to wait for git-upload-pack: %s", buff.String()) + if err := cmd.Run(); err != nil { + slog.ErrorContext(ctx, "Git upload pack failed", "error", err, "message", errBuff.String()) return err } @@ -694,8 +694,16 @@ type debugReader struct { } func (d *debugReader) Read(p []byte) (n int, err error) { - fmt.Printf("READ: %x\n", p) - return d.r.Read(p) + r, err := d.r.Read(p) + if err != nil { + if errors.Is(io.EOF, err) { + fmt.Printf("READ: EOF\n") + } + return r, err + } + + fmt.Printf("READ: %s\n", p[:r]) + return r, nil } type debugWriter struct { @@ -703,6 +711,6 @@ type debugWriter struct { } func (d *debugWriter) Write(p []byte) (n int, err error) { - fmt.Printf("WRITE: %x\n", p) + fmt.Printf("WRITE: %s\n", p) return d.w.Write(p) } diff --git a/pkg/handler/about/handler.go b/pkg/handler/about/handler.go index ee084cd..b3a1593 100644 --- a/pkg/handler/about/handler.go +++ b/pkg/handler/about/handler.go @@ -9,6 +9,7 @@ import ( "github.com/gomarkdown/markdown/html" "github.com/gomarkdown/markdown/parser" + "git.gabrielgio.me/cerrado/pkg/ext" "git.gabrielgio.me/cerrado/templates" ) @@ -26,7 +27,7 @@ func NewAboutHandler(configRepo configurationRepository) *AboutHandler { return &AboutHandler{configRepo.GetRootReadme()} } -func (g *AboutHandler) About(w http.ResponseWriter, r *http.Request) error { +func (g *AboutHandler) About(w http.ResponseWriter, r *ext.Request) error { f, err := os.Open(g.readmePath) if err != nil { return err diff --git a/pkg/handler/auth/login.go b/pkg/handler/auth/login.go index 89fd87b..9cc13cc 100644 --- a/pkg/handler/auth/login.go +++ b/pkg/handler/auth/login.go @@ -26,7 +26,7 @@ func NewLoginHandler(auth authService) *LoginHandler { } } -func (g *LoginHandler) Logout(w http.ResponseWriter, r *http.Request) error { +func (g *LoginHandler) Logout(w http.ResponseWriter, r *ext.Request) error { cookie := &http.Cookie{ Name: "auth", Value: "", @@ -44,7 +44,7 @@ func (g *LoginHandler) Logout(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *LoginHandler) Login(w http.ResponseWriter, r *http.Request) error { +func (g *LoginHandler) Login(w http.ResponseWriter, r *ext.Request) error { referer := r.URL.Query().Get("referer") // if query value is empty tries to get from header diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go index 61765bb..cb202a2 100644 --- a/pkg/handler/git/handler.go +++ b/pkg/handler/git/handler.go @@ -48,7 +48,7 @@ func NewGitHandler(gitService *service.GitService, confRepo configurationReposit } } -func (g *GitHandler) List(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) List(w http.ResponseWriter, r *ext.Request) error { // this is the only handler that needs to handle authentication itself. // everything else relay on name path parameter logged := ext.IsLoggedIn(r.Context()) @@ -90,7 +90,7 @@ func (g *GitHandler) List(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Archive(w http.ResponseWriter, r *ext.Request) error { ext.SetGZip(w) name := r.PathValue("name") file := r.PathValue("file") @@ -116,7 +116,7 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Multiplex(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Multiplex(w http.ResponseWriter, r *ext.Request) error { path := r.PathValue("rest") name := r.PathValue("name") @@ -141,7 +141,8 @@ func (g *GitHandler) Multiplex(w http.ResponseWriter, r *http.Request) error { reader := r.Body if r.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(r.Body) + var err error + reader, err = gzip.NewReader(r.Body) if err != nil { return err } @@ -159,7 +160,7 @@ func (g *GitHandler) Multiplex(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Summary(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref, err := g.gitService.GetHead(name) @@ -199,7 +200,7 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) About(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref, err := g.gitService.GetHead(name) @@ -243,7 +244,7 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Refs(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") @@ -274,7 +275,7 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Tree(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -303,7 +304,7 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Blob(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -371,7 +372,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Log(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -394,7 +395,7 @@ func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Ref(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Ref(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") @@ -416,7 +417,7 @@ func (g *GitHandler) Ref(w http.ResponseWriter, r *http.Request) error { return nil } -func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error { +func (g *GitHandler) Commit(w http.ResponseWriter, r *ext.Request) error { ext.SetHTML(w) name := r.PathValue("name") ref := r.PathValue("ref") diff --git a/pkg/handler/static/handler.go b/pkg/handler/static/handler.go index 361f690..cdb2ae6 100644 --- a/pkg/handler/static/handler.go +++ b/pkg/handler/static/handler.go @@ -16,7 +16,7 @@ func ServeStaticHandler() (ext.ErrorRequestHandler, error) { return nil, err } - return func(w http.ResponseWriter, r *http.Request) error { + return func(w http.ResponseWriter, r *ext.Request) error { var ( f = r.PathValue("file") e = filepath.Ext(f) @@ -24,7 +24,7 @@ func ServeStaticHandler() (ext.ErrorRequestHandler, error) { ) ext.SetMIME(w, m) w.Header().Add("Cache-Control", "max-age=31536000") - http.ServeFileFS(w, r, staticFs, f) + http.ServeFileFS(w, r.Request, staticFs, f) return nil }, nil } |